Георги обнови решението на 06.11.2011 20:43 (преди около 13 години)
+require 'bigdecimal'
+require 'bigdecimal/util'
+
+class Product
+ attr_accessor :name, :price, :promo
+
+ def initialize(name, price, *promo)
+ @name = name
+ @price = price.to_d
+ @promo = (promo == [] ? nil : promo[0])
+ end
+
+end
+
+class Coupon
+ attr_accessor :name, :type
+
+ def initialize(name, type)
+ @name = name
+ @type = type
+ end
+
+end
+
+class Promo_compute
+
+ def self.ending(num)
+ case num
+ when 1 then "1st"
+ when 2 then "2nd"
+ when 3 then "3rd"
+ else num.to_s + "th"
+ end
+ end
+
+ def self.kv(k, v)
+ start = "| " + k
+ start + " " * ((v > 9 ? 46 : 47) - start.length) + v.to_s + " |"
+ end
+
+ def self.invoice_string(promo, save)
+ if promo == []
+ return ""
+ end
+ k = promo.keys[0]
+ v = promo[k]
+ if v.kind_of? Hash
+ v1 = v.keys[0]
+ v2 = v[v1]
+ end
+ u = "% off of every after the "
+ case k
+ when :get_one_free then e = "| (buy " + (v - 1).to_s + ", get 1 free)"
+ when :package then e = "| (get " + v2.to_s + "% off for every " + v1.to_s + ")"
+ when :threshold then e = "| (" + v2.to_s + u + self.ending(v1) + ")"
+ end
+ e + " " * (49 - e.length) + "|" + sprintf("%9.2f", -save) + " |\n"
+ end
+
+ def self.invoice_sc(name, coupon, save)
+ k = coupon.keys[0]
+ v = coupon[k]
+ start = "| Coupon " + name + " - " + v.to_s
+ if k == :percent
+ start << "%"
+ end
+ start << " off"
+ start + " " * (49 - start.length) + "|" + sprintf("%9.2f", -save) + " |\n"
+ end
+
+ def self.calc_promo(k, v, count, perc, v1, v2, price)
+ case k
+ when :get_one_free then price * (count - count / v)
+ when :package then price * ((count - count % v1) * perc + (count % v1))
+ when :threshold then price * ([v1, count].min + perc * [(count - v1), 0].max)
+ end
+ end
+
+ def self.invoice_end(q, total)
+ ret = q + "| " + sprintf("%s %41s", "TOTAL", "") + "|"
+ ret << sprintf("%9.2f", total) + " |"+ "\n" + q
+ end
+end
+
+class Cart
+ attr_accessor :contents, :products, :using, :coupons
+
+ def initialize(products, coupons)
+ @contents = {}
+ @products = products
+ @coupons = coupons
+ end
+
+ def add(name, *count_opt)
+ count = (count_opt == [] ? 1 : count_opt[0])
+ if @products.collect {|p| p.name == name}.count(true) == 0 || count < 1
+ raise "Invalid parameters passed."
+ end
+ if !contents.has_key?(name)
+ contents[name] = 0
+ end
+ contents[name] += count
+ if contents[name] > 99
+ raise "Invalid parameters passed."
+ end
+ end
+
+ def use(coupon)
+ @using = coupon
+ end
+
+ def get_ptc(item, count)
+ product = @products.select {|p| p.name == item} [0]
+ if product.promo == []
+ return product.price * count
+ end
+ k, v = product.promo.keys[0], product.promo.values[0]
+ if v.kind_of? Hash
+ v1, v2 = v.keys[0], v.values[0]
+ perc = BigDecimal(((100.0 - v2) / 100.0).to_s)
+ end
+ Promo_compute.calc_promo(k, v, count, perc, v1, v2, product.price)
+ end
+
+ def get_cd(sum)
+ if @using != nil
+ k = @coupons[@using].keys[0]
+ v = BigDecimal(@coupons[@using][k].to_s)
+ case k
+ when :percent then sum - (sum * (100 - v) / 100)
+ when :amount then [v, sum].min
+ end
+ else
+ 0
+ end
+ end
+
+ def tot_wc
+ sum = BigDecimal('0')
+ @contents.each do |k, v|
+ sum += get_ptc(k, v)
+ end
+ sum
+ end
+
+ def total
+ tot_wc - get_cd(tot_wc)
+ end
+
+ def get_p(item)
+ @products.select {|p| p.name == item} [0].price
+ end
+
+ def get_promo(item)
+ @products.select {|p| p.name == item} [0].promo
+ end
+
+ def invoice
+ q = "+------------------------------------------------+----------+\n"
+ result = q + "| Name qty | price |\n" + q
+ @contents.each do |k, v|
+ result << Promo_compute.kv(k, v) + sprintf("%9.2f", get_p(k) * v) + " |\n"
+ result << Promo_compute.invoice_string(get_promo(k), get_p(k) * v - get_ptc(k, v))
+ end
+ if @using != nil
+ result << Promo_compute.invoice_sc(@using, @coupons[@using], get_cd(tot_wc))
+ end
+ result << Promo_compute.invoice_end(q, total)
+ end
+
+end
+
+class Inventory
+ attr_accessor :products, :coupons
+
+ def initialize
+ @products = []
+ @coupons = {}
+ end
+
+ def check_register_data(name, price)
+ if (!name.kind_of? String) or (!price.kind_of? String)
+ raise "Invalid parameters passed."
+ end
+ if name.length > 40 or price.to_d < 0.01 or price.to_d > 999.99
+ raise "Invalid parameters passed."
+ end
+ if @products.collect {|p| p.name == name}.count(true) > 0
+ raise "Invalid parameters passed."
+ end
+ end
+
+ def register(name, price, *promo)
+ check_register_data(name, price)
+ @products << Product.new(name, price, (promo == [] ? [] : promo[0]))
+ end
+
+ def register_coupon(name, type)
+ @coupons[name] = type
+ end
+
+ def new_cart
+ Cart.new(@products, @coupons)
+ end
+
+ end