Решение на Трета задача от Николай Константинов

Обратно към всички решения

Към профила на Николай Константинов

Резултати

  • 4 точки от тестове
  • 0 бонус точки
  • 4 точки общо
  • 12 успешни тест(а)
  • 7 неуспешни тест(а)

Код

require 'bigdecimal'
require 'bigdecimal/util'
module Constants
LOWER_PRICE_BOUND = BigDecimal('0.01')
HIGHER_PRICE_BOUND = BigDecimal('999.99')
SEPARATOR = '+'+('-' * 48) + '+' + ('-'*10) + '+' + "\n"
VERTICAL_LINE = '|'
PRODUCT_MAX_LENGHT = 40
end
module CartHelper
def format_price(digit)
sprintf("%0.2f", digit)
end
def is_quant_invalid?(quantity)
quantity <= 0 or quantity > 99
end
def threshold_ending(bound_elem)
if bound_elem.to_s.end_with?('1')
'st)'
elsif bound_elem.to_s.end_with?('2')
'nd)'
elsif bound_elem.to_s.end_with?('3')
'rd)'
else bound_elem > 3
'th)'
end
end
def summed_price(product_name, product_quantity)
format_price((products_in_inv.find{|y|y.name == product_name}.price)*product_quantity)
end
def calc_money(product, quantity, type)
if type == :get_one_free
product.price*(quantity / product.promotions[:get_one_free])
elsif type == :package
perc = (product.promotions[:package].values.first().to_f / 100)
format_price((product.price * perc) * product.promotions[:package].keys.first() *
(quantity / product.promotions[:package].keys.first())).to_d
elsif type == :threshold
threshold_price(product, quantity)
end
end
def check_promo?(product, quantity, type)
if type == :get_one_free
product.promotions.key?(:get_one_free)&&quantity>=product.promotions[:get_one_free]
elsif type == :package
product.promotions.key?(:package)&&quantity>=product.promotions[:package].keys.first()
elsif type == :threshold
product.promotions.key?(:threshold)&&
quantity >= product.promotions[:threshold].keys.first()
end
end
def package_msg(product)
"(get " + first_prod_to_s(product)+\
"% off for every " + product.promotions[:package].keys.first().to_s + ")"
end
def threshold_msg(product)
elem = product.promotions[:threshold].keys.first()
"("+first_prod_to_s(product)+"% off of every after the "+elem.to_s+threshold_ending(elem)
end
def get_one_free_msg(product)
"(buy " + (product.promotions.values.first() - 1).to_s + ", get 1 free)"
end
def threshold_price(product, quantity)
diff = format_price(quantity-product.promotions[:threshold].keys.first())
perc = (product.promotions[:threshold].values.first().to_f / 100)
format_price(BigDecimal(diff) * ((product.price * perc))).to_d
end
end
class Inventory
include Constants, CartHelper
attr_accessor :products, :coupons
def register_coupon(coupon_name, discount)
coupons << Coupon.new(coupon_name, discount)
end
def initialize()
@products = []
@coupons = []
end
def new_cart()
Cart.new(products, coupons)
end
def validate_registration(product_name, product_price)
if is_product_name_correct?(product_name) or not is_price_in_range?(product_price)
raise RuntimeError.new("Invalid parameters passed.")
end
end
def is_product_name_correct?(product_name)
products.one?{ |x| x.name == product_name} or product_name.length>PRODUCT_MAX_LENGHT
end
def is_price_in_range?(price)
BigDecimal(price) >= LOWER_PRICE_BOUND and BigDecimal(price) <= HIGHER_PRICE_BOUND
end
def register(product_name, product_price, promo = {})
validate_registration(product_name, format_price(product_price))
products << Product.new(product_name, BigDecimal(format_price(product_price)), promo)
end
end
class Cart
include Constants, CartHelper
attr_accessor :products_in_inv, :products_in_cart, :coupons, :coupon_sum,
:cart_sum, :promo_sum, :promo_products
def initialize(products, coupons)
@products_in_inv = products
@products_in_cart = {}
@promo_products = {}
@coupons = coupons
@coupon_sum = BigDecimal('0.00')
@cart_sum = BigDecimal('0.00')
@promo_sum = BigDecimal('0.00')
end
def add(product_name, quantity = 1)
if is_quant_invalid?(quantity) or not products_in_inv.one?{|x| x.name == product_name}
raise "invalid arguments (cart)"
end
if products_in_cart[product_name] == nil
products_in_cart[product_name] = quantity
else
if products_in_cart[product_name] + quantity > 99
raise "invalid argmunts (cart)"
end
products_in_cart[product_name] += quantity
end
cache_saved_prices
end
def total
bill_after_promotions = cart_sum - (promo_sum)
bill_after_coupons = bill_after_promotions > coupon_sum ?
bill_after_promotions - coupon_sum : BigDecimal('0.00')
@promo_sum = BigDecimal('0.00')
bill_after_coupons
end
def cache_saved_prices
cart_sum = BigDecimal('0.00')
saved_sum = BigDecimal('0.00')
products_in_cart.keys.each do |x|
cart_sum += products_in_inv.find {|y| y.name == x}.price * products_in_cart[x]
saved_sum = apply_promo(products_in_inv.find {|y| y.name == x}, products_in_cart[x])
promo_products[x] = saved_sum
end
@cart_sum = cart_sum
@promo_sum += saved_sum
end
def apply_promo(product, quant_in_cart)
saved_money = BigDecimal('0.00')
if(check_promo?(product, quant_in_cart, :get_one_free))
saved_money = calc_money(product, quant_in_cart, :get_one_free)
elsif(check_promo?(product, quant_in_cart, :package))
saved_money = calc_money(product, quant_in_cart, :package)
elsif(check_promo?(product, quant_in_cart, :threshold))
saved_money = calc_money(product, quant_in_cart, :threshold)
end
saved_money
end
def use(coupon_name)
rest_sum = cart_sum - promo_sum
if(coupons[0].discount.keys.first() == :percent)
@coupon_sum = format_price(rest_sum *
BigDecimal((coupons[0].discount.values.first().to_f / 100).to_s)).to_d
else
@coupon_sum = BigDecimal(format_price(coupons[0].discount.values.first()))-rest_sum
end
promo_products[coupons[0].name] = @coupon_sum
@coupon_sum
end
def invoice
receipt_msg = SEPARATOR + "| Name qty | price |\n"+ SEPARATOR
products_in_cart.each do |key, value|
receipt_msg += "| " + key.to_s + (" ") + value.to_s + " |"+\
(" ") + summed_price(key, value) + " |\n"
receipt_msg += construct_promotion_msg(key)
end
receipt_msg += construct_coupon_msg if(coupons != [])
footer = SEPARATOR + "| TOTAL | " + format_price(total) + " |\n" + SEPARATOR
receipt_msg += footer
end
def first_prod_to_s(product)
product.promotions.values.first().values.first().to_s
end
def construct_promotion_msg(key)
msg, product = "|" + " ", products_in_inv.find{ |x| x.name == key}
if(product.promotions.key?(:get_one_free)) then ms = get_one_free_msg(product)
elsif(product.promotions.key?(:package)) then ms = package_msg(product)
elsif(product.promotions.key?(:threshold))
ms = threshold_msg(product)
else return ""
end
msg += ms + " | -" + format_price(promo_products[product.name]) + " |\n"
end
def construct_coupon_msg
msg = "|" + " Coupon " + coupons[0].name
if(coupons[0].discount.keys.first() == :percent)
ms = " - " + coupons[0].discount[:percent].to_s + "% off"
elsif(coupons[0].discount.keys.first() == :amount)
ms = " - " + format_price(coupons[0].discount[:amount]) + " off"
else
return ""
end
msg += ms + " | -" + format_price(promo_products[coupons[0].name]) + " |\n"
end
end
class Product
attr_accessor :name, :price, :promotions
def initialize(name, price, promotions)
@name, @price, @promotions = name, price, promotions
end
end
class Coupon
attr_accessor :name, :discount
def initialize(name, discount)
@name, @discount = name, discount
end
end

Лог от изпълнението

..F..F..F..F..F..FF

Failures:

  1) Inventory with no discounts can print an invoice
     Failure/Error: cart.invoice.should eq <<INVOICE
       
       expected: "+------------------------------------------------+----------+\n| Name                                       qty |    price |\n+------------------------------------------------+----------+\n| Green Tea                                    1 |     0.79 |\n| Earl Grey                                    3 |     2.97 |\n| Black Coffee                                 2 |     3.98 |\n+------------------------------------------------+----------+\n| TOTAL                                          |     7.74 |\n+------------------------------------------------+----------+\n"
            got: "+------------------------------------------------+----------+\n| Name qty | price |\n+------------------------------------------------+----------+\n| Green Tea 1 | 0.79 |\n| Earl Grey 3 | 2.97 |\n| Black Coffee 2 | 3.98 |\n+------------------------------------------------+----------+\n| TOTAL | 7.74 |\n+------------------------------------------------+----------+\n"
       
       (compared using ==)
       
       Diff:
       
       
       @@ -1,10 +1,10 @@
        +------------------------------------------------+----------+
       -| Name                                       qty |    price |
       +| Name qty | price |
        +------------------------------------------------+----------+
       -| Green Tea                                    1 |     0.79 |
       -| Earl Grey                                    3 |     2.97 |
       -| Black Coffee                                 2 |     3.98 |
       +| Green Tea 1 | 0.79 |
       +| Earl Grey 3 | 2.97 |
       +| Black Coffee 2 | 3.98 |
        +------------------------------------------------+----------+
       -| TOTAL                                          |     7.74 |
       +| TOTAL | 7.74 |
        +------------------------------------------------+----------+
     # /tmp/d20111115-5847-1cg7ggx/spec.rb:73:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  2) Inventory with a 'buy X, get one free' promotion shows the discount in the invoice
     Failure/Error: cart.invoice.should eq <<INVOICE
       
       expected: "+------------------------------------------------+----------+\n| Name                                       qty |    price |\n+------------------------------------------------+----------+\n| Green Tea                                    3 |     3.00 |\n|   (buy 2, get 1 free)                          |    -1.00 |\n| Red Tea                                      8 |    16.00 |\n|   (buy 4, get 1 free)                          |    -2.00 |\n+------------------------------------------------+----------+\n| TOTAL                                          |    16.00 |\n+------------------------------------------------+----------+\n"
            got: "+------------------------------------------------+----------+\n| Name qty | price |\n+------------------------------------------------+----------+\n| Green Tea 3 | 3.00 |\n| (buy 2, get 1 free) | -1.00 |\n| Red Tea 8 | 16.00 |\n| (buy 4, get 1 free) | -2.00 |\n+------------------------------------------------+----------+\n| TOTAL | 16.00 |\n+------------------------------------------------+----------+\n"
       
       (compared using ==)
       
       Diff:
       
       
       @@ -1,11 +1,11 @@
        +------------------------------------------------+----------+
       -| Name                                       qty |    price |
       +| Name qty | price |
        +------------------------------------------------+----------+
       -| Green Tea                                    3 |     3.00 |
       -|   (buy 2, get 1 free)                          |    -1.00 |
       -| Red Tea                                      8 |    16.00 |
       -|   (buy 4, get 1 free)                          |    -2.00 |
       +| Green Tea 3 | 3.00 |
       +| (buy 2, get 1 free) | -1.00 |
       +| Red Tea 8 | 16.00 |
       +| (buy 4, get 1 free) | -2.00 |
        +------------------------------------------------+----------+
       -| TOTAL                                          |    16.00 |
       +| TOTAL | 16.00 |
        +------------------------------------------------+----------+
     # /tmp/d20111115-5847-1cg7ggx/spec.rb:111:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  3) Inventory with a '% off for every n' promotion shows the discount in the invoice
     Failure/Error: cart.invoice.should eq <<INVOICE
       
       expected: "+------------------------------------------------+----------+\n| Name                                       qty |    price |\n+------------------------------------------------+----------+\n| Green Tea                                    4 |     4.00 |\n|   (get 10% off for every 4)                    |    -0.40 |\n| Red Tea                                      8 |    16.00 |\n|   (get 20% off for every 5)                    |    -2.00 |\n+------------------------------------------------+----------+\n| TOTAL                                          |    17.60 |\n+------------------------------------------------+----------+\n"
            got: "+------------------------------------------------+----------+\n| Name qty | price |\n+------------------------------------------------+----------+\n| Green Tea 4 | 4.00 |\n| (get 10% off for every 4) | -0.40 |\n| Red Tea 8 | 16.00 |\n| (get 20% off for every 5) | -2.00 |\n+------------------------------------------------+----------+\n| TOTAL | 17.60 |\n+------------------------------------------------+----------+\n"
       
       (compared using ==)
       
       Diff:
       
       
       @@ -1,11 +1,11 @@
        +------------------------------------------------+----------+
       -| Name                                       qty |    price |
       +| Name qty | price |
        +------------------------------------------------+----------+
       -| Green Tea                                    4 |     4.00 |
       -|   (get 10% off for every 4)                    |    -0.40 |
       -| Red Tea                                      8 |    16.00 |
       -|   (get 20% off for every 5)                    |    -2.00 |
       +| Green Tea 4 | 4.00 |
       +| (get 10% off for every 4) | -0.40 |
       +| Red Tea 8 | 16.00 |
       +| (get 20% off for every 5) | -2.00 |
        +------------------------------------------------+----------+
       -| TOTAL                                          |    17.60 |
       +| TOTAL | 17.60 |
        +------------------------------------------------+----------+
     # /tmp/d20111115-5847-1cg7ggx/spec.rb:154:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  4) Inventory with a '% off of every item after the nth' promotion shows the discount in the ivnoice
     Failure/Error: cart.invoice.should eq <<INVOICE
       
       expected: "+------------------------------------------------+----------+\n| Name                                       qty |    price |\n+------------------------------------------------+----------+\n| Green Tea                                   12 |    12.00 |\n|   (10% off of every after the 10th)            |    -0.20 |\n| Red Tea                                     20 |    40.00 |\n|   (20% off of every after the 15th)            |    -2.00 |\n+------------------------------------------------+----------+\n| TOTAL                                          |    49.80 |\n+------------------------------------------------+----------+\n"
            got: "+------------------------------------------------+----------+\n| Name qty | price |\n+------------------------------------------------+----------+\n| Green Tea 12 | 12.00 |\n| (10% off of every after the 10th) | -0.20 |\n| Red Tea 20 | 40.00 |\n| (20% off of every after the 15th) | -2.00 |\n+------------------------------------------------+----------+\n| TOTAL | 49.80 |\n+------------------------------------------------+----------+\n"
       
       (compared using ==)
       
       Diff:
       
       
       @@ -1,11 +1,11 @@
        +------------------------------------------------+----------+
       -| Name                                       qty |    price |
       +| Name qty | price |
        +------------------------------------------------+----------+
       -| Green Tea                                   12 |    12.00 |
       -|   (10% off of every after the 10th)            |    -0.20 |
       -| Red Tea                                     20 |    40.00 |
       -|   (20% off of every after the 15th)            |    -2.00 |
       +| Green Tea 12 | 12.00 |
       +| (10% off of every after the 10th) | -0.20 |
       +| Red Tea 20 | 40.00 |
       +| (20% off of every after the 15th) | -2.00 |
        +------------------------------------------------+----------+
       -| TOTAL                                          |    49.80 |
       +| TOTAL | 49.80 |
        +------------------------------------------------+----------+
     # /tmp/d20111115-5847-1cg7ggx/spec.rb:197:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  5) Inventory with a '% off' coupon shows the discount in the invoice
     Failure/Error: cart.invoice.should eq <<INVOICE
       
       expected: "+------------------------------------------------+----------+\n| Name                                       qty |    price |\n+------------------------------------------------+----------+\n| Green Tea                                   10 |    10.00 |\n| Coupon TEA-TIME - 20% off                      |    -2.00 |\n+------------------------------------------------+----------+\n| TOTAL                                          |     8.00 |\n+------------------------------------------------+----------+\n"
            got: "+------------------------------------------------+----------+\n| Name qty | price |\n+------------------------------------------------+----------+\n| Green Tea 10 | 10.00 |\n| Coupon TEA-TIME - 20% off | -2.00 |\n+------------------------------------------------+----------+\n| TOTAL | 8.00 |\n+------------------------------------------------+----------+\n"
       
       (compared using ==)
       
       Diff:
       
       
       @@ -1,9 +1,9 @@
        +------------------------------------------------+----------+
       -| Name                                       qty |    price |
       +| Name qty | price |
        +------------------------------------------------+----------+
       -| Green Tea                                   10 |    10.00 |
       -| Coupon TEA-TIME - 20% off                      |    -2.00 |
       +| Green Tea 10 | 10.00 |
       +| Coupon TEA-TIME - 20% off | -2.00 |
        +------------------------------------------------+----------+
       -| TOTAL                                          |     8.00 |
       +| TOTAL | 8.00 |
        +------------------------------------------------+----------+
     # /tmp/d20111115-5847-1cg7ggx/spec.rb:240:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  6) Inventory with an 'amount off' coupon shows the discount in the invoice
     Failure/Error: cart.invoice.should eq <<INVOICE
       
       expected: "+------------------------------------------------+----------+\n| Name                                       qty |    price |\n+------------------------------------------------+----------+\n| Green Tea                                    5 |     5.00 |\n| Coupon TEA-TIME - 10.00 off                    |    -5.00 |\n+------------------------------------------------+----------+\n| TOTAL                                          |     0.00 |\n+------------------------------------------------+----------+\n"
            got: "+------------------------------------------------+----------+\n| Name qty | price |\n+------------------------------------------------+----------+\n| Green Tea 5 | 5.00 |\n| Coupon TEA-TIME - 10.00 off | -5.00 |\n+------------------------------------------------+----------+\n| TOTAL | 0.00 |\n+------------------------------------------------+----------+\n"
       
       (compared using ==)
       
       Diff:
       
       
       @@ -1,9 +1,9 @@
        +------------------------------------------------+----------+
       -| Name                                       qty |    price |
       +| Name qty | price |
        +------------------------------------------------+----------+
       -| Green Tea                                    5 |     5.00 |
       -| Coupon TEA-TIME - 10.00 off                    |    -5.00 |
       +| Green Tea 5 | 5.00 |
       +| Coupon TEA-TIME - 10.00 off | -5.00 |
        +------------------------------------------------+----------+
       -| TOTAL                                          |     0.00 |
       +| TOTAL | 0.00 |
        +------------------------------------------------+----------+
     # /tmp/d20111115-5847-1cg7ggx/spec.rb:281:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  7) Inventory with multiple discounts can print an invoice
     Failure/Error: cart.invoice.should eq <<INVOICE
       
       expected: "+------------------------------------------------+----------+\n| Name                                       qty |    price |\n+------------------------------------------------+----------+\n| Green Tea                                    8 |    22.32 |\n|   (buy 1, get 1 free)                          |   -11.16 |\n| Black Coffee                                 5 |    14.95 |\n|   (get 20% off for every 2)                    |    -2.39 |\n| Milk                                         5 |     8.95 |\n|   (30% off of every after the 3rd)             |    -1.07 |\n| Cereal                                       3 |     7.47 |\n| Coupon BREAKFAST - 10% off                     |    -3.91 |\n+------------------------------------------------+----------+\n| TOTAL                                          |    35.16 |\n+------------------------------------------------+----------+\n"
            got: "+------------------------------------------------+----------+\n| Name qty | price |\n+------------------------------------------------+----------+\n| Green Tea 8 | 22.32 |\n| (buy 1, get 1 free) | -11.16 |\n| Black Coffee 5 | 14.95 |\n| (get 20% off for every 2) | -2.39 |\n| Milk 5 | 8.95 |\n| (30% off of every after the 3rd) | -1.07 |\n| Cereal 3 | 7.47 |\n| Coupon BREAKFAST - 10% off | -3.91 |\n+------------------------------------------------+----------+\n| TOTAL | 35.16 |\n+------------------------------------------------+----------+\n"
       
       (compared using ==)
       
       Diff:
       
       
       @@ -1,15 +1,15 @@
        +------------------------------------------------+----------+
       -| Name                                       qty |    price |
       +| Name qty | price |
        +------------------------------------------------+----------+
       -| Green Tea                                    8 |    22.32 |
       -|   (buy 1, get 1 free)                          |   -11.16 |
       -| Black Coffee                                 5 |    14.95 |
       -|   (get 20% off for every 2)                    |    -2.39 |
       -| Milk                                         5 |     8.95 |
       -|   (30% off of every after the 3rd)             |    -1.07 |
       -| Cereal                                       3 |     7.47 |
       -| Coupon BREAKFAST - 10% off                     |    -3.91 |
       +| Green Tea 8 | 22.32 |
       +| (buy 1, get 1 free) | -11.16 |
       +| Black Coffee 5 | 14.95 |
       +| (get 20% off for every 2) | -2.39 |
       +| Milk 5 | 8.95 |
       +| (30% off of every after the 3rd) | -1.07 |
       +| Cereal 3 | 7.47 |
       +| Coupon BREAKFAST - 10% off | -3.91 |
        +------------------------------------------------+----------+
       -| TOTAL                                          |    35.16 |
       +| TOTAL | 35.16 |
        +------------------------------------------------+----------+
     # /tmp/d20111115-5847-1cg7ggx/spec.rb:309:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

Finished in 0.57712 seconds
19 examples, 7 failures

Failed examples:

rspec /tmp/d20111115-5847-1cg7ggx/spec.rb:64 # Inventory with no discounts can print an invoice
rspec /tmp/d20111115-5847-1cg7ggx/spec.rb:104 # Inventory with a 'buy X, get one free' promotion shows the discount in the invoice
rspec /tmp/d20111115-5847-1cg7ggx/spec.rb:147 # Inventory with a '% off for every n' promotion shows the discount in the invoice
rspec /tmp/d20111115-5847-1cg7ggx/spec.rb:190 # Inventory with a '% off of every item after the nth' promotion shows the discount in the ivnoice
rspec /tmp/d20111115-5847-1cg7ggx/spec.rb:233 # Inventory with a '% off' coupon shows the discount in the invoice
rspec /tmp/d20111115-5847-1cg7ggx/spec.rb:274 # Inventory with an 'amount off' coupon shows the discount in the invoice
rspec /tmp/d20111115-5847-1cg7ggx/spec.rb:295 # Inventory with multiple discounts can print an invoice

История (1 версия и 0 коментара)

Николай обнови решението на 07.11.2011 14:06 (преди около 13 години)

+require 'bigdecimal'
+require 'bigdecimal/util'
+module Constants
+ LOWER_PRICE_BOUND = BigDecimal('0.01')
+ HIGHER_PRICE_BOUND = BigDecimal('999.99')
+ SEPARATOR = '+'+('-' * 48) + '+' + ('-'*10) + '+' + "\n"
+ VERTICAL_LINE = '|'
+ PRODUCT_MAX_LENGHT = 40
+end
+
+module CartHelper
+
+ def format_price(digit)
+ sprintf("%0.2f", digit)
+ end
+
+ def is_quant_invalid?(quantity)
+ quantity <= 0 or quantity > 99
+ end
+
+ def threshold_ending(bound_elem)
+ if bound_elem.to_s.end_with?('1')
+ 'st)'
+ elsif bound_elem.to_s.end_with?('2')
+ 'nd)'
+ elsif bound_elem.to_s.end_with?('3')
+ 'rd)'
+ else bound_elem > 3
+ 'th)'
+ end
+ end
+
+ def summed_price(product_name, product_quantity)
+ format_price((products_in_inv.find{|y|y.name == product_name}.price)*product_quantity)
+ end
+
+ def calc_money(product, quantity, type)
+ if type == :get_one_free
+ product.price*(quantity / product.promotions[:get_one_free])
+ elsif type == :package
+ perc = (product.promotions[:package].values.first().to_f / 100)
+ format_price((product.price * perc) * product.promotions[:package].keys.first() *
+ (quantity / product.promotions[:package].keys.first())).to_d
+ elsif type == :threshold
+ threshold_price(product, quantity)
+ end
+ end
+
+ def check_promo?(product, quantity, type)
+ if type == :get_one_free
+ product.promotions.key?(:get_one_free)&&quantity>=product.promotions[:get_one_free]
+ elsif type == :package
+ product.promotions.key?(:package)&&quantity>=product.promotions[:package].keys.first()
+ elsif type == :threshold
+ product.promotions.key?(:threshold)&&
+ quantity >= product.promotions[:threshold].keys.first()
+ end
+ end
+
+ def package_msg(product)
+ "(get " + first_prod_to_s(product)+\
+ "% off for every " + product.promotions[:package].keys.first().to_s + ")"
+ end
+
+ def threshold_msg(product)
+ elem = product.promotions[:threshold].keys.first()
+ "("+first_prod_to_s(product)+"% off of every after the "+elem.to_s+threshold_ending(elem)
+ end
+
+ def get_one_free_msg(product)
+ "(buy " + (product.promotions.values.first() - 1).to_s + ", get 1 free)"
+ end
+
+ def threshold_price(product, quantity)
+ diff = format_price(quantity-product.promotions[:threshold].keys.first())
+ perc = (product.promotions[:threshold].values.first().to_f / 100)
+ format_price(BigDecimal(diff) * ((product.price * perc))).to_d
+ end
+end
+
+class Inventory
+ include Constants, CartHelper
+ attr_accessor :products, :coupons
+
+ def register_coupon(coupon_name, discount)
+ coupons << Coupon.new(coupon_name, discount)
+ end
+
+ def initialize()
+ @products = []
+ @coupons = []
+ end
+
+ def new_cart()
+ Cart.new(products, coupons)
+ end
+
+ def validate_registration(product_name, product_price)
+ if is_product_name_correct?(product_name) or not is_price_in_range?(product_price)
+ raise RuntimeError.new("Invalid parameters passed.")
+ end
+ end
+
+ def is_product_name_correct?(product_name)
+ products.one?{ |x| x.name == product_name} or product_name.length>PRODUCT_MAX_LENGHT
+ end
+
+ def is_price_in_range?(price)
+ BigDecimal(price) >= LOWER_PRICE_BOUND and BigDecimal(price) <= HIGHER_PRICE_BOUND
+ end
+
+ def register(product_name, product_price, promo = {})
+ validate_registration(product_name, format_price(product_price))
+ products << Product.new(product_name, BigDecimal(format_price(product_price)), promo)
+ end
+end
+
+
+class Cart
+ include Constants, CartHelper
+ attr_accessor :products_in_inv, :products_in_cart, :coupons, :coupon_sum,
+ :cart_sum, :promo_sum, :promo_products
+
+ def initialize(products, coupons)
+ @products_in_inv = products
+ @products_in_cart = {}
+ @promo_products = {}
+ @coupons = coupons
+ @coupon_sum = BigDecimal('0.00')
+ @cart_sum = BigDecimal('0.00')
+ @promo_sum = BigDecimal('0.00')
+ end
+
+ def add(product_name, quantity = 1)
+ if is_quant_invalid?(quantity) or not products_in_inv.one?{|x| x.name == product_name}
+ raise "invalid arguments (cart)"
+ end
+ if products_in_cart[product_name] == nil
+ products_in_cart[product_name] = quantity
+ else
+ if products_in_cart[product_name] + quantity > 99
+ raise "invalid argmunts (cart)"
+ end
+ products_in_cart[product_name] += quantity
+ end
+ cache_saved_prices
+ end
+
+ def total
+ bill_after_promotions = cart_sum - (promo_sum)
+ bill_after_coupons = bill_after_promotions > coupon_sum ?
+ bill_after_promotions - coupon_sum : BigDecimal('0.00')
+ @promo_sum = BigDecimal('0.00')
+ bill_after_coupons
+ end
+
+ def cache_saved_prices
+ cart_sum = BigDecimal('0.00')
+ saved_sum = BigDecimal('0.00')
+ products_in_cart.keys.each do |x|
+ cart_sum += products_in_inv.find {|y| y.name == x}.price * products_in_cart[x]
+ saved_sum = apply_promo(products_in_inv.find {|y| y.name == x}, products_in_cart[x])
+ promo_products[x] = saved_sum
+ end
+ @cart_sum = cart_sum
+ @promo_sum += saved_sum
+ end
+
+ def apply_promo(product, quant_in_cart)
+ saved_money = BigDecimal('0.00')
+ if(check_promo?(product, quant_in_cart, :get_one_free))
+ saved_money = calc_money(product, quant_in_cart, :get_one_free)
+ elsif(check_promo?(product, quant_in_cart, :package))
+ saved_money = calc_money(product, quant_in_cart, :package)
+ elsif(check_promo?(product, quant_in_cart, :threshold))
+ saved_money = calc_money(product, quant_in_cart, :threshold)
+ end
+ saved_money
+ end
+
+
+ def use(coupon_name)
+ rest_sum = cart_sum - promo_sum
+ if(coupons[0].discount.keys.first() == :percent)
+ @coupon_sum = format_price(rest_sum *
+ BigDecimal((coupons[0].discount.values.first().to_f / 100).to_s)).to_d
+ else
+ @coupon_sum = BigDecimal(format_price(coupons[0].discount.values.first()))-rest_sum
+ end
+ promo_products[coupons[0].name] = @coupon_sum
+ @coupon_sum
+ end
+
+ def invoice
+ receipt_msg = SEPARATOR + "| Name qty | price |\n"+ SEPARATOR
+ products_in_cart.each do |key, value|
+ receipt_msg += "| " + key.to_s + (" ") + value.to_s + " |"+\
+ (" ") + summed_price(key, value) + " |\n"
+ receipt_msg += construct_promotion_msg(key)
+ end
+ receipt_msg += construct_coupon_msg if(coupons != [])
+ footer = SEPARATOR + "| TOTAL | " + format_price(total) + " |\n" + SEPARATOR
+ receipt_msg += footer
+ end
+
+ def first_prod_to_s(product)
+ product.promotions.values.first().values.first().to_s
+ end
+
+ def construct_promotion_msg(key)
+ msg, product = "|" + " ", products_in_inv.find{ |x| x.name == key}
+ if(product.promotions.key?(:get_one_free)) then ms = get_one_free_msg(product)
+ elsif(product.promotions.key?(:package)) then ms = package_msg(product)
+ elsif(product.promotions.key?(:threshold))
+ ms = threshold_msg(product)
+ else return ""
+ end
+ msg += ms + " | -" + format_price(promo_products[product.name]) + " |\n"
+ end
+
+ def construct_coupon_msg
+ msg = "|" + " Coupon " + coupons[0].name
+ if(coupons[0].discount.keys.first() == :percent)
+ ms = " - " + coupons[0].discount[:percent].to_s + "% off"
+ elsif(coupons[0].discount.keys.first() == :amount)
+ ms = " - " + format_price(coupons[0].discount[:amount]) + " off"
+ else
+ return ""
+ end
+ msg += ms + " | -" + format_price(promo_products[coupons[0].name]) + " |\n"
+ end
+end
+
+class Product
+ attr_accessor :name, :price, :promotions
+
+ def initialize(name, price, promotions)
+ @name, @price, @promotions = name, price, promotions
+ end
+end
+
+class Coupon
+ attr_accessor :name, :discount
+
+ def initialize(name, discount)
+ @name, @discount = name, discount
+ end
+end
+
+
+
+