Мая обнови решението на 07.11.2011 09:14 (преди около 13 години)
+require 'bigdecimal'
+require 'bigdecimal/util' # добавя String#to_d
+
+class Product
+ attr_accessor :name, :price, :promotion_type, :details
+
+ def get_one_free(amount)
+ (amount/@details)*@price
+ end
+
+ def package(amount)
+ t = (amount/@details.keys[0])*@details.keys[0]
+ t*BigDecimal(@details.values[0].to_s)*BigDecimal("0.01")*price
+ end
+
+ def threshold(amount)
+ if amount <= @details.keys.first
+ 0
+ else
+ t = (amount-@details.keys.first)*price
+ t*(BigDecimal(@details.values.first.to_s)*BigDecimal("0.01"))
+ end
+ end
+
+ def initialize(name, price, promotion = nil)
+ @name, @price = name, price.to_d
+ if promotion != nil
+ @promotion_type, @details = promotion.keys.first, promotion.values.first
+ else
+ @promotion_type, @details = nil, nil
+ end
+ end
+
+ def discount(amount)
+ (@promotion_type.nil?) ? 0 : send(@promotion_type, amount)
+ end
+end
+
+class Coupon
+ attr_accessor :name, :type, :value
+
+ def initialize(name, type, value)
+ @name, @type, @value = name, type, value.to_s.to_d
+ end
+
+ def discount(price)
+ if @type == :percent
+ BigDecimal(@value.to_s)*BigDecimal("0.01")*BigDecimal(price.to_s)
+ else
+ (price > @value) ? @value : price
+ end
+ end
+
+ def price_off(price)
+ if @type == :percent
+ 10*BigDecimal(price.to_s)/(100-BigDecimal(value.to_s))
+ else
+ (price > @value) ? @value : price
+ end
+ end
+end
+
+class Cart
+ attr_accessor :using_coupon
+
+ def initialize(inventory, coupons)
+ @cart = Hash.new(0)
+ @inventory, @coupons, @using_coupon = inventory, coupons, nil
+ end
+
+ def add(product_name, number = 1)
+ if @inventory.select {|x| x.name == product_name} == [] or number <= 0 or number > 99
+ raise "Invalid parameters passed."
+ else
+ @cart[@inventory.select {|x| x.name == product_name}.first] += number
+ end
+ end
+
+ def use(coupon_name)
+ @using_coupon = @coupons.select {|x| x.name == coupon_name}.first
+ end
+
+ def total()
+ total = total1 - ((@using_coupon.nil?) ? 0 : @using_coupon.discount(total1))
+ end
+
+ def total1()
+ prices = @cart.map {|product, amount| product.price*amount-product.discount(amount)}
+ t = prices.inject(:+)
+ t = 0 unless t
+ t
+ end
+
+ def invoice()
+ cart = @cart.to_a
+ line = '+' + '-'*48 + '+' + '-'*10 + '+' + "\n"
+ t = line + '| Name' + ' '*39 + 'qty |' + ' '*4 + "price |\n" + line
+ @cart.each do |key, value|
+ t += sprintf("| %- 38s", key.name)
+ t += sprintf("%8d |", value) + sprintf("%9.2f |\n", value*key.price)
+ t += send(key.promotion_type, key, value) if key.promotion_type != nil
+ end
+ t += reduction + line + '| TOTAL' + ' '*42 + '|' + sprintf("%9.2f |\n", total) + line
+ end
+
+ private
+
+ def reduction()
+ t = ""
+ if u = @using_coupon
+ if u.type == :percent
+ t = sprintf("| Coupon %-40s", u.name.to_s+" - "+sprintf("%d", u.value)+"% off")
+ t += sprintf("|%9.2f |\n", -total1+total)
+ else
+ t = sprintf("%-49s",sprintf("| Coupon "+u.name.to_s+" - %.2f off", u.value.to_s))
+ t += sprintf("|%9.2f |\n", -total1+total)
+ end
+ end
+ t
+ end
+
+ def get_one_free(key, value)
+ l1 = sprintf("| %-45s", "(buy " + (key.details-1).to_s + ", get 1 free)")
+ l1 += sprintf("|%9.2f |\n", -key.get_one_free(value))
+ end
+
+ def package(key, value)
+ percent = sprintf("%d", key.details.values[0])
+ amount = (key.details.keys[0]).to_s
+ l1 = sprintf("| %-45s", "(get " + percent + "% off for every " + amount + ")")
+ l1 += sprintf("|%9.2f |\n", -key.package(value))
+ end
+
+ def threshold(key, value)
+ ending = case key.details.keys[0]
+ when 1 then "st)"
+ when 2 then "nd)"
+ when 3 then "rd)"
+ else "th)"
+ end
+ percent = "(" + (key.details.values[0]).to_s + "% off of every after the "
+ l1 = sprintf("| %-45s", percent + (key.details.keys[0]).to_s + ending)
+ l1 += sprintf("|%9.2f |\n", -key.threshold(value))
+ end
+end
+
+class Inventory
+ def initialize
+ @inventory, @coupons = [], []
+ end
+
+ def register(product_name, price, promotion = nil)
+ if product_name.length > 40 or
+ price.to_d < 0.01 or
+ price.to_d > 999.99 or
+ @inventory.include? product_name
+ raise "Invalid parameters passed."
+ else
+ @inventory << Product.new(product_name, price, promotion)
+ end
+ end
+
+ def register_coupon(name, k)
+ @coupons << Coupon.new(name, k.keys.first, k.values.first)
+ end
+
+ def new_cart
+ Cart.new(@inventory, @coupons)
+ end
+end