Решение на Трета задача от Мария Гроздева

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

Към профила на Мария Гроздева

Резултати

  • 3 точки от тестове
  • 0 бонус точки
  • 3 точки общо
  • 11 успешни тест(а)
  • 8 неуспешни тест(а)

Код

require 'bigdecimal'
require 'bigdecimal/util'
class Inventory
attr_accessor :items, :coupons
def initialize()
@items = Array.new
@coupons = Array.new
end
def get_item(name)
@items.find {|item| item.name == name}
end
def get_coupon(name)
@coupons.find {|coupon| coupon.name == name}
end
def register(product, price, promo=nil)
if self.get_item(product)
raise "Himagu ve4i beee :)"
else
if promo
@items.push(Item.new(product, price, Promotion.new_promo(promo)))
else
@items.push(Item.new(product, price))
end
end
end
def register_coupon(name, discount_type)
if self.get_coupon(name) #equal
raise "This item is already registered"
else
@coupons.push(Coupon.new_coupon(name,discount_type))
end
end
def new_cart()
Cart.new(self)
end
end
class Cart
attr_accessor :items
attr_reader :inventory, :coupon
def initialize(inv)
@items = Array.new
@inventory = inv
end
def add(product, quantity=1)
if(inv_item = @inventory.get_item(product))
if (cart_item = @items.find {|item| item.name == product})
cart_item.count += quantity
else
@items << ItemInCart.new(inv_item,quantity)
end
else
raise "There is no such item in inventory."
end
end
def use(coupon)
if not (@coupon = @inventory.get_coupon(coupon))
raise "There is no such coupon in inventory."
end
end
def gross()
items.inject(0) {|s, it| s + it.get_total - it.get_discount}
end
def total()
if @coupon
self.gross - @coupon.apply(self)
else
self.gross
end
end
def invoice()
line = "-"*63+"\n"
invoice_input = line+"| %-42s %s | %9s|\n" % ["Name","qty", "price"]+line
@items.each do |item|
invoice_input += inv_row(item)
end
c=@coupon ? "|%-48s|%9.2f |\n" %["#{@coupon.coupon_s}","-#{@coupon.apply(self)}"]:""
t = "\n| %-45s | %9.2f |\n" %["TOTAL","#{self.total}"]
invoice_input + c + line+t+line
end
def inv_row(item)
if item.promotion
i= "|%-46s %d|%9.2f |\n" %["#{item.name}","#{item.count}","#{item.get_total}"]
i+= "|%-47s | %8.2f |\n" %["#{item.promotion.promo_s}", "-#{item.get_discount}"]
i
else
"| %-46s | %8.2f | \n" % ["#{item.name}","#{item.count}", "#{item.get_total}"]
end
end
end
class Item
attr_accessor :name, :price, :promotion
def initialize(name, price, promotion = nil)
if (name.length <= 40 && price.to_d.between?( 0.01, 999.99))
@name, @price = name, price
@promotion = promotion
else
raise "Invalid parameters passed."
end
end
def price_d()
@price.to_d
end
end
class ItemInCart < Item
attr_accessor :count
def initialize(item,count)
if count < 100
super( item.name, item.price, item.promotion)
@count = count
else raise "Too much items!"
end
end
def get_total()
price_d*@count
end
def get_discount()
if @promotion
@promotion.calculate(self)
else
0
end
end
end
class Promotion
def Promotion.new_promo(type)
case type.keys[0]
when :get_one_free
GetOneFreePromo.new(type.values[0])
when :package
PackagePromo.new(type.values[0].keys[0], type.values[0].values[0])
when :threshold
TresholdPromo.new(type.values[0].keys[0], type.values[0].values[0])
end
end
end
class QuantityPromotion < Promotion
attr_accessor :count
def initialize(count)
@count = count
end
end
class GetOneFreePromo < QuantityPromotion
def initialize(count)
super
end
def calculate(item)
item.price_d*(item.count/@count)
end
def promo_s()
"(by #{@count-1}, get 1 free)"
end
end
class PackagePromo < QuantityPromotion
attr_accessor :percent
def initialize(count, percent)
super(count)
@percent = percent
end
def calculate(item)
if item.count >= @count
(item.count/@count)*@count*item.price_d*@percent/100
else
0
end
end
def promo_s()
"(get #{@percent}% off for every #{count})"
end
end
class TresholdPromo < QuantityPromotion
attr_reader :percent
def initialize(count, percent)
super(count)
@percent = percent
end
def calculate(item)
if item.count >= @count
(item.count - @count.to_f.to_d)*item.price_d*@percent/100
else
0
end
end
def promo_s()
"(#{@percent} off of every after the #{@count}th)"
end
end
class Coupon
attr_accessor :name
def initialize(name)
@name = name
end
def Coupon.new_coupon(name, type)
case type.keys[0]
when :percent
PercentageCoupon.new(name,type.values[0])
when :amount
AmountCoupon.new(name, type.values[0])
end
end
end
class PercentageCoupon < Coupon
attr_accessor :percent
def initialize(name,percent)
super(name)
@percent = percent
end
def apply(cart)
cart.gross*@percent/100
end
def coupon_s()
"Coupon #{@name} -#{@percent}% off"
end
end
class AmountCoupon < Coupon
attr_accessor :amount
def initialize(name,amount)
super(name)
@amount = amount
end
def apply(cart)
[cart.gross, @amount.to_d].min
end
def coupon_s()
"Coupon #{@name} -#{@amount} off"
end
end

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

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

Failures:

  1) Inventory with no discounts has some constraints on prices and counts
     Failure/Error: expect { cart.add 'Existing', -1 }.to raise_error
       expected Exception but nothing was raised
     # /tmp/d20111115-5847-1s7ejjh/spec.rb:61: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 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.00 | \n| Earl Grey                                      |     3.00 | \n| Black Coffee                                   |     2.00 | \n---------------------------------------------------------------\n\n| TOTAL                                         |      7.74 |\n---------------------------------------------------------------\n"
       
       (compared using ==)
       
       Diff:
       @@ -1,10 +1,11 @@
       -+------------------------------------------------+----------+
       -| Name                                       qty |    price |
       -+------------------------------------------------+----------+
       -| Green Tea                                    1 |     0.79 |
       -| Earl Grey                                    3 |     2.97 |
       -| Black Coffee                                 2 |     3.98 |
       -+------------------------------------------------+----------+
       -| TOTAL                                          |     7.74 |
       -+------------------------------------------------+----------+
       +---------------------------------------------------------------
       +| Name                                       qty |     price|
       +---------------------------------------------------------------
       +| Green Tea                                      |     1.00 | 
       +| Earl Grey                                      |     3.00 | 
       +| Black Coffee                                   |     2.00 | 
       +---------------------------------------------------------------
       +
       +| TOTAL                                         |      7.74 |
       +---------------------------------------------------------------
     # /tmp/d20111115-5847-1s7ejjh/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)>'

  3) 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|(by 2, get 1 free)                              |    -1.00 |\n|Red Tea                                        8|    16.00 |\n|(by 4, get 1 free)                              |    -2.00 |\n---------------------------------------------------------------\n\n| TOTAL                                         |     16.00 |\n---------------------------------------------------------------\n"
       
       (compared using ==)
       
       Diff:
       @@ -1,11 +1,12 @@
       -+------------------------------------------------+----------+
       -| 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 |
       -+------------------------------------------------+----------+
       -| TOTAL                                          |    16.00 |
       -+------------------------------------------------+----------+
       +---------------------------------------------------------------
       +| Name                                       qty |     price|
       +---------------------------------------------------------------
       +|Green Tea                                      3|     3.00 |
       +|(by 2, get 1 free)                              |    -1.00 |
       +|Red Tea                                        8|    16.00 |
       +|(by 4, get 1 free)                              |    -2.00 |
       +---------------------------------------------------------------
       +
       +| TOTAL                                         |     16.00 |
       +---------------------------------------------------------------
     # /tmp/d20111115-5847-1s7ejjh/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)>'

  4) 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\n| TOTAL                                         |     17.60 |\n---------------------------------------------------------------\n"
       
       (compared using ==)
       
       Diff:
       @@ -1,11 +1,12 @@
       -+------------------------------------------------+----------+
       -| 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 |
       -+------------------------------------------------+----------+
       -| TOTAL                                          |    17.60 |
       -+------------------------------------------------+----------+
       +---------------------------------------------------------------
       +| 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 |
       +---------------------------------------------------------------
       +
       +| TOTAL                                         |     17.60 |
       +---------------------------------------------------------------
     # /tmp/d20111115-5847-1s7ejjh/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)>'

  5) 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\n| TOTAL                                         |     49.80 |\n---------------------------------------------------------------\n"
       
       (compared using ==)
       
       Diff:
       @@ -1,11 +1,12 @@
       -+------------------------------------------------+----------+
       -| 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 |
       -+------------------------------------------------+----------+
       -| TOTAL                                          |    49.80 |
       -+------------------------------------------------+----------+
       +---------------------------------------------------------------
       +| 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 |
       +---------------------------------------------------------------
       +
       +| TOTAL                                         |     49.80 |
       +---------------------------------------------------------------
     # /tmp/d20111115-5847-1s7ejjh/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)>'

  6) 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.00 | \n|Coupon TEA-TIME -20% off                        |    -2.00 |\n---------------------------------------------------------------\n\n| TOTAL                                         |      8.00 |\n---------------------------------------------------------------\n"
       
       (compared using ==)
       
       Diff:
       @@ -1,9 +1,10 @@
       -+------------------------------------------------+----------+
       -| Name                                       qty |    price |
       -+------------------------------------------------+----------+
       -| Green Tea                                   10 |    10.00 |
       -| Coupon TEA-TIME - 20% off                      |    -2.00 |
       -+------------------------------------------------+----------+
       -| TOTAL                                          |     8.00 |
       -+------------------------------------------------+----------+
       +---------------------------------------------------------------
       +| Name                                       qty |     price|
       +---------------------------------------------------------------
       +| Green Tea                                      |    10.00 | 
       +|Coupon TEA-TIME -20% off                        |    -2.00 |
       +---------------------------------------------------------------
       +
       +| TOTAL                                         |      8.00 |
       +---------------------------------------------------------------
     # /tmp/d20111115-5847-1s7ejjh/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)>'

  7) 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.00 | \n|Coupon TEA-TIME -0.1E2 off                      |    -5.00 |\n---------------------------------------------------------------\n\n| TOTAL                                         |      0.00 |\n---------------------------------------------------------------\n"
       
       (compared using ==)
       
       Diff:
       @@ -1,9 +1,10 @@
       -+------------------------------------------------+----------+
       -| Name                                       qty |    price |
       -+------------------------------------------------+----------+
       -| Green Tea                                    5 |     5.00 |
       -| Coupon TEA-TIME - 10.00 off                    |    -5.00 |
       -+------------------------------------------------+----------+
       -| TOTAL                                          |     0.00 |
       -+------------------------------------------------+----------+
       +---------------------------------------------------------------
       +| Name                                       qty |     price|
       +---------------------------------------------------------------
       +| Green Tea                                      |     5.00 | 
       +|Coupon TEA-TIME -0.1E2 off                      |    -5.00 |
       +---------------------------------------------------------------
       +
       +| TOTAL                                         |      0.00 |
       +---------------------------------------------------------------
     # /tmp/d20111115-5847-1s7ejjh/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)>'

  8) 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|(by 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 3th)                 |    -1.07 |\n| Cereal                                         |     3.00 | \n|Coupon BREAKFAST -10% off                       |    -3.91 |\n---------------------------------------------------------------\n\n| TOTAL                                         |     35.16 |\n---------------------------------------------------------------\n"
       
       (compared using ==)
       
       Diff:
       @@ -1,15 +1,16 @@
       -+------------------------------------------------+----------+
       -| 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 |
       -+------------------------------------------------+----------+
       -| TOTAL                                          |    35.16 |
       -+------------------------------------------------+----------+
       +---------------------------------------------------------------
       +| Name                                       qty |     price|
       +---------------------------------------------------------------
       +|Green Tea                                      8|    22.32 |
       +|(by 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 3th)                 |    -1.07 |
       +| Cereal                                         |     3.00 | 
       +|Coupon BREAKFAST -10% off                       |    -3.91 |
       +---------------------------------------------------------------
       +
       +| TOTAL                                         |     35.16 |
       +---------------------------------------------------------------
     # /tmp/d20111115-5847-1s7ejjh/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.57576 seconds
19 examples, 8 failures

Failed examples:

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

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

Мария обнови решението на 07.11.2011 16:47 (преди около 13 години)

+require 'bigdecimal'
+require 'bigdecimal/util'
+
+class Inventory
+ attr_accessor :items, :coupons
+
+ def initialize()
+ @items = Array.new
+ @coupons = Array.new
+ end
+
+ def get_item(name)
+ @items.find {|item| item.name == name}
+ end
+
+ def get_coupon(name)
+ @coupons.find {|coupon| coupon.name == name}
+ end
+
+ def register(product, price, promo=nil)
+ if self.get_item(product)
+ raise "Himagu ve4i beee :)"
+ else
+ if promo
+ @items.push(Item.new(product, price, Promotion.new_promo(promo)))
+ else
+ @items.push(Item.new(product, price))
+ end
+ end
+ end
+
+ def register_coupon(name, discount_type)
+ if self.get_coupon(name) #equal
+ raise "This item is already registered"
+ else
+ @coupons.push(Coupon.new_coupon(name,discount_type))
+ end
+ end
+
+ def new_cart()
+ Cart.new(self)
+ end
+
+end
+
+class Cart
+ attr_accessor :items
+ attr_reader :inventory, :coupon
+
+ def initialize(inv)
+ @items = Array.new
+ @inventory = inv
+ end
+
+ def add(product, quantity=1)
+ if(inv_item = @inventory.get_item(product))
+ if (cart_item = @items.find {|item| item.name == product})
+ cart_item.count += quantity
+ else
+ @items << ItemInCart.new(inv_item,quantity)
+ end
+ else
+ raise "There is no such item in inventory."
+ end
+ end
+
+ def use(coupon)
+ if not (@coupon = @inventory.get_coupon(coupon))
+ raise "There is no such coupon in inventory."
+ end
+ end
+
+ def gross()
+ items.inject(0) {|s, it| s + it.get_total - it.get_discount}
+ end
+
+ def total()
+ if @coupon
+ self.gross - @coupon.apply(self)
+ else
+ self.gross
+ end
+ end
+
+ def invoice()
+ line = "-"*63+"\n"
+ invoice_input = line+"| %-42s %s | %9s|\n" % ["Name","qty", "price"]+line
+
+ @items.each do |item|
+ invoice_input += inv_row(item)
+ end
+ c=@coupon ? "|%-48s|%9.2f |\n" %["#{@coupon.coupon_s}","-#{@coupon.apply(self)}"]:""
+ t = "\n| %-45s | %9.2f |\n" %["TOTAL","#{self.total}"]
+ invoice_input + c + line+t+line
+ end
+
+ def inv_row(item)
+ if item.promotion
+ i= "|%-46s %d|%9.2f |\n" %["#{item.name}","#{item.count}","#{item.get_total}"]
+ i+= "|%-47s | %8.2f |\n" %["#{item.promotion.promo_s}", "-#{item.get_discount}"]
+ i
+ else
+ "| %-46s | %8.2f | \n" % ["#{item.name}","#{item.count}", "#{item.get_total}"]
+ end
+ end
+end
+
+class Item
+ attr_accessor :name, :price, :promotion
+ def initialize(name, price, promotion = nil)
+ if (name.length <= 40 && price.to_d.between?( 0.01, 999.99))
+ @name, @price = name, price
+ @promotion = promotion
+ else
+ raise "Invalid parameters passed."
+ end
+ end
+ def price_d()
+ @price.to_d
+ end
+end
+
+class ItemInCart < Item
+ attr_accessor :count
+ def initialize(item,count)
+ if count < 100
+ super( item.name, item.price, item.promotion)
+ @count = count
+ else raise "Too much items!"
+ end
+ end
+
+ def get_total()
+ price_d*@count
+ end
+
+ def get_discount()
+ if @promotion
+ @promotion.calculate(self)
+ else
+ 0
+ end
+ end
+end
+
+class Promotion
+ def Promotion.new_promo(type)
+ case type.keys[0]
+ when :get_one_free
+ GetOneFreePromo.new(type.values[0])
+ when :package
+ PackagePromo.new(type.values[0].keys[0], type.values[0].values[0])
+ when :threshold
+ TresholdPromo.new(type.values[0].keys[0], type.values[0].values[0])
+ end
+ end
+ end
+
+class QuantityPromotion < Promotion
+ attr_accessor :count
+ def initialize(count)
+ @count = count
+ end
+end
+
+class GetOneFreePromo < QuantityPromotion
+ def initialize(count)
+ super
+ end
+ def calculate(item)
+ item.price_d*(item.count/@count)
+ end
+ def promo_s()
+ "(by #{@count-1}, get 1 free)"
+ end
+end
+
+class PackagePromo < QuantityPromotion
+ attr_accessor :percent
+ def initialize(count, percent)
+ super(count)
+ @percent = percent
+ end
+
+ def calculate(item)
+ if item.count >= @count
+ (item.count/@count)*@count*item.price_d*@percent/100
+ else
+ 0
+ end
+ end
+ def promo_s()
+ "(get #{@percent}% off for every #{count})"
+ end
+end
+
+class TresholdPromo < QuantityPromotion
+ attr_reader :percent
+ def initialize(count, percent)
+ super(count)
+ @percent = percent
+ end
+ def calculate(item)
+ if item.count >= @count
+ (item.count - @count.to_f.to_d)*item.price_d*@percent/100
+ else
+ 0
+ end
+ end
+ def promo_s()
+ "(#{@percent} off of every after the #{@count}th)"
+ end
+end
+
+class Coupon
+ attr_accessor :name
+ def initialize(name)
+ @name = name
+ end
+ def Coupon.new_coupon(name, type)
+ case type.keys[0]
+ when :percent
+ PercentageCoupon.new(name,type.values[0])
+ when :amount
+ AmountCoupon.new(name, type.values[0])
+ end
+ end
+end
+
+class PercentageCoupon < Coupon
+ attr_accessor :percent
+ def initialize(name,percent)
+ super(name)
+ @percent = percent
+ end
+ def apply(cart)
+ cart.gross*@percent/100
+ end
+ def coupon_s()
+ "Coupon #{@name} -#{@percent}% off"
+ end
+end
+
+class AmountCoupon < Coupon
+ attr_accessor :amount
+ def initialize(name,amount)
+ super(name)
+ @amount = amount
+ end
+ def apply(cart)
+ [cart.gross, @amount.to_d].min
+ end
+ def coupon_s()
+ "Coupon #{@name} -#{@amount} off"
+ end
+end