Георги обнови решението на 07.11.2011 11:50 (преди около 13 години)
+require 'bigdecimal'
+require 'bigdecimal/util'
+
+class Inventory
+ MinPrice = BigDecimal('0.01')
+ MaxPrice = BigDecimal('999.99')
+
+ attr_reader :goods_in_stock, :coupons, :goods_in_promotion
+
+ def initialize
+ @goods_in_stock = {}
+ @goods_in_promotion = {}
+ @coupons = {}
+ end
+
+ def register(goods_name, price, promotion=nil)
+ decimal_price = BigDecimal(price)
+ if goods_name.length > 40 || !decimal_price.between?(MinPrice, MaxPrice)
+ raise 'Invalid parameters passed.'
+ elsif @goods_in_stock.has_key?(goods_name)
+ raise 'Already exist in the inventory.'
+ end
+ @goods_in_stock[goods_name] = decimal_price
+ if promotion != nil
+ @goods_in_promotion[goods_name] = Promotions.create_promotion(promotion)
+ end
+ end
+
+ def register_coupon(name, type)
+ @coupons[name] = type
+ end
+
+ def new_cart
+ Cart.new(@goods_in_stock, @goods_in_promotion, @coupons)
+ end
+end
+
+class Cart
+ def initialize(goods_in_stock, goods_in_promotion, coupons)
+ @items = Hash.new(0)
+ @goods_in_stock = goods_in_stock
+ @goods_in_promotion = goods_in_promotion
+ @coupons = coupons
+ @total = BigDecimal('0')
+ @used_coupon = nil
+ end
+
+ def total
+ calculate_total_without_coupons()
+ calculate_total_with_coupons() if @used_coupon != nil
+ @total
+ end
+
+ def add(goods_name, quantity=1)
+ raise 'Not in the inventory.' if !@goods_in_stock.has_key?(goods_name)
+ raise 'Invalid quantity. ' if !quantity.between?(1, 99)
+ @items[goods_name] += quantity
+ end
+
+ def invoice
+ Receipt.new(self).print()
+ end
+
+ def use(name)
+ @used_coupon = name if @used_coupon == nil
+ end
+
+ private
+ def calculate_total_without_coupons
+ @total, item_tot = BigDecimal('0'), BigDecimal('0')
+ @items.each do |name, qty|
+ if @goods_in_promotion.include?(name)
+ item_tot= @goods_in_promotion[name].calculate_subtotal(qty, @goods_in_stock[name])
+ else
+ item_tot = (qty * @goods_in_stock[name])
+ end
+ @total += item_tot
+ end
+ end
+
+ def calculate_total_with_coupons
+ case @coupons[@used_coupon].keys.first
+ when :amount then
+ discount = @coupons[@used_coupon][:amount].to_d
+ @total = (discount <= @total)? (@total - discount): '0.00'.to_d
+ when :percent then
+ @total -= (@coupons[@used_coupon][:percent] / '100.00'.to_d) * @total
+ end
+ end
+end
+
+class Receipt
+ def initialize(cart)
+
+ end
+
+ def print
+
+ end
+end
+
+class Promotions
+ def Promotions.create_promotion(promo)
+ promotion = case promo.keys.first
+ when :get_one_free then GetOneFreePromo.new(promo[:get_one_free])
+ when :package then PackagePromo.new(promo[:package])
+ when :threshold then ThresholdPromo.new(promo[:threshold])
+ end
+ promotion
+ end
+end
+
+class GetOneFreePromo
+ def initialize(condition)
+ @condition = condition
+ end
+
+ def calculate_subtotal(qty, item_price)
+ subtotal = BigDecimal('0')
+ subtotal = qty * item_price
+ if qty >= @condition
+ subtotal -= ((qty / @condition) * item_price)
+ end
+ subtotal
+ end
+end
+
+class PackagePromo
+ def initialize(condition)
+ @number_of_items = condition.keys.first
+ @percent_discount = condition.values.first
+ end
+
+ def calculate_subtotal(qty, item_price)
+ subtotal = BigDecimal('0')
+ subtotal = qty * item_price
+ if qty >= @number_of_items
+ items_in_promo, coeff = qty / @number_of_items, (@percent_discount / '100.00'.to_d)
+ subtotal -= (items_in_promo * (coeff * (@number_of_items * item_price)))
+ end
+ subtotal
+ end
+end
+
+class ThresholdPromo
+ def initialize(condition)
+ @number_of_items = condition.keys.first
+ @percent_discount = condition.values.first
+ end
+
+ def calculate_subtotal(qty, item_price)
+ subtotal = BigDecimal('0')
+ subtotal = qty * item_price
+ if qty >= @number_of_items
+ items_in_prom, coeff = (qty - @number_of_items), (@percent_discount / '100.00'.to_d)
+ subtotal -= (items_in_prom * coeff * (item_price))
+ end
+ subtotal
+ end
+end