Александър обнови решението на 07.11.2011 03:17 (преди около 13 години)
+class Invoice
+ def initialize(cart)
+ @cart_instance = cart
+ @cart = cart.cart
+ @promos = cart.promos
+ @coupons = cart.coupons
+ @used_coupon = cart.used_coupon
+ end
+
+ def suffix(number)
+ number = number.to_s
+ case number
+ when '1' then number + 'st)'
+ when '2' then number + 'nd)'
+ when '3' then number + 'rd)'
+ else number + 'th)'
+ end
+ end
+
+ def print_product_mixed(name, count, discount=nil)
+ if discount
+ price = sprintf "-%.2f", @cart_instance.determine_product_discount(name)
+ name = discount
+ else
+ price = sprintf "%.2f", @cart_instance.determine_product_price(name)
+ end
+ ('| ' + name).ljust(48 - count.length) + count + ' |' + price.rjust(9) + " |\n"
+ end
+
+ def print_product_promo(name)
+ promo = @promos[name].values[0]
+ case @promos[name].keys[0]
+ when :get_one_free then opt_str = " (buy #{promo - 1}, get 1 free)"
+ when :package
+ opt_str = " (get #{promo.values[0]}% off for every #{promo.keys[0]})"
+ when :threshold
+ opt_str = " (#{promo.values[0]}% off of every after the #{suffix(promo.keys[0])}"
+ end
+ print_product_mixed(name, '', opt_str)
+ end
+
+ def print_product_invoice
+ product_invoice = ''
+ @cart.keys.each do |name|
+ product_invoice += print_product_mixed(name, @cart[name].to_s)
+ product_invoice += print_product_promo(name) if @promos[name]
+ end
+ product_invoice
+ end
+
+ def print_coupon_invoice
+ hash = @coupons[@used_coupon]
+ coupon_discount =
+ sprintf "%.2f", @cart_instance.determine_coupon_discount(@cart_instance.total false)
+ str = "| Coupon #{@used_coupon} - #{hash.values[0]} off".ljust(49)
+ if hash.keys[0] == :percent
+ str = str.sub(" off ", "% off")
+ end
+ str + '|' + "-#{coupon_discount}".rjust(9) + " |\n"
+ end
+
+ def print_footer_invoice
+ "+------------------------------------------------+----------+\n" +
+ "| Name qty | price |\n" +
+ "+------------------------------------------------+----------+\n"
+ end
+
+ def invoice
+ invoice = print_footer_invoice
+ invoice += print_product_invoice
+ invoice += print_coupon_invoice if @used_coupon
+ invoice += "+------------------------------------------------+----------+\n" +
+ "| TOTAL |" +
+ sprintf("%.2f", @cart_instance.total).rjust(9) + " |\n" +
+ "+------------------------------------------------+----------+\n"
+ invoice
+ end
+end
+
+class Cart
+ require 'bigdecimal'
+ require 'bigdecimal/util'
+
+ attr_reader :cart, :promos, :coupons, :used_coupon
+ def initialize(inventory)
+ @inventory = inventory.inventory
+ @cart = {}
+ @promos = inventory.promos
+ @coupons = inventory.coupons
+ @used_coupon = nil
+ end
+
+ def add(name, count = 1)
+ if not @inventory[name] or not (1..99).include? count
+ raise "Invalid parameters passed."
+ end
+ @cart[name] = (@cart[name] or 0) + count
+ end
+
+ def use(coupon_name)
+ @used_coupon = coupon_name
+ end
+
+ def determine_product_price(name)
+ @inventory[name].to_d*@cart[name]
+ end
+
+ def determine_product_discount(name)
+ promo = @promos[name].values[0]
+ price = @inventory[name].to_d
+ count = @cart[name]
+ case @promos[name].keys[0]
+ when :get_one_free then price*(count/promo)
+ when :package then (count/promo.keys[0])*promo.keys[0]*(price*promo.values[0]/100)
+ when :threshold
+ (promo.keys[0] < count)?(count-promo.keys[0])*price*promo.values[0]/100:'0'.to_d
+ end
+ end
+
+ def determine_coupon_discount(total_price)
+ return BigDecimal('0') if not @used_coupon
+ case @coupons[@used_coupon].keys[0]
+ when :percent
+ total_price*@coupons[@used_coupon].values[0]/100
+ when :amount
+ discount = (@coupons[@used_coupon].values[0]).to_d
+ (discount > total_price)?total_price:discount
+ end
+ end
+
+ def total(calc_discount = true)
+ total_price = BigDecimal.new('0')
+ @cart.keys.each do |name|
+ total_price += determine_product_price(name)
+ total_price -= determine_product_discount(name) if @promos[name]
+ end
+ coupon_discount = BigDecimal('0') if not calc_discount
+ coupon_discount = determine_coupon_discount(total_price) if calc_discount
+ (total_price < coupon_discount)?BigDecimal('0'):total_price - coupon_discount
+ end
+
+ def invoice
+ Invoice.new(self).invoice
+ end
+end
+
+class Inventory
+ attr_reader :inventory, :promos, :coupons
+
+ def initialize
+ @inventory = {}
+ @promos = {}
+ @coupons = {}
+ end
+
+ def register(name, price, promo = {})
+ if not (0..40).include? name.length or
+ not ('0.01'..'999.99').include? price or @inventory[name]
+ raise "Invalid parameters passed."
+ end
+ @inventory[name] = price
+ @promos[name] = (promo.keys.size == 0)?nil:promo
+ end
+
+ def register_coupon(coupon_name, coupon_discount)
+ @coupons[coupon_name] = coupon_discount
+ end
+
+ def new_cart
+ Cart.new self
+ end
+end