Решение на Трета задача от Дарина Нейчева

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

Към профила на Дарина Нейчева

Резултати

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

Код

#!/usr/local/rvm/rubies/ruby-1.9.2-p290/bin/ruby
require 'bigdecimal'
require 'bigdecimal/util'
class Product
attr_accessor :name, :value, :promotion
def initialize(name, value, promotion=nil)
if name.length <= 40 and value.to_d >= 0.01 and value.to_d <= 999.99
@name = name
@value = value.to_d
else raise "Invalid parameters passed."
end
@promotion = promotion
end
def promotion?
return true if @promotion
false
end
def get_one_free?
return true if @promotion[:get_one_free]
false
end
def package?
return true if @promotion[:package]
false
end
end
class Inventory
attr_accessor :all_products, :coupons
def initialize
@all_products = []
@coupons=[]
end
def register(name, value, promotion=nil)
if @all_products.any? { |product| product.name == name }
raise "Dublicate names."
else @all_products << Product.new(name, value, promotion)
end
end
def new_cart
cart = Cart.new(@all_products, @coupons)
end
def register_coupon(name, type)
if @coupons.any? { |coupon| coupon.name == name }
raise "Dublicate names of coupons."
else @coupons << Coupon.new(name, type)
end
end
end
class Coupon
attr_accessor :name, :type, :value
def initialize(name, type)
@name = name
@type = type
@value = type.values[0]
end
def amount?
return true if @type[:amount]
false
end
end
class Cart
attr_accessor :inventory, :coupons, :coupon_name, :cart_products, :invoice, :total
def initialize(inventory, coupons)
@cart_products = []
@inventory = inventory
@coupons = coupons
end
def add(product_name, count = 1)
if @inventory.none? { |product| product.name == product_name }
raise "There isn't such a product in the inventory."
elsif not_allowable_count?(count)
raise "Quantity must be between 1 and 99 inclusive."
else helper_add(product_name, count)
end
end
def helper_add(name, count)
if @cart_products.any? { |prod| prod[:product] == name }
current = @cart_products.select { |pr| pr[:product] == name }
current[0][:count]+=count
else @cart_products << { product: name, count: count }
end
end
def use(coupon_name)
if @coupon_name
raise "Caupon has been already add to this cart."
elsif @coupons.none? { |coupon| coupon.name == coupon_name}
raise "There isn't such an coupon in the inventory"
else @coupon_name = coupon_name
end
end
def not_allowable_count?(count)
return false if count >=1 and count <= 99
true
end
def init_invoice
@invoice = Invoice.new(self)
end
def invoice
init_invoice
@invoice.print_invoice
end
def total
init_invoice
@invoice.total
end
end
class Invoice
attr_accessor :cart, :printer
def initialize(cart)
@cart = cart
@printer = Printer.new
end
def total
invoice_total=0
@cart.cart_products.each do |product|
current = @cart.inventory.select { |prod| product[:product] == prod.name }
invoice_total += current[0].value * product[:count]
count = product[:count]
current[0].promotion? ? invoice_total -= cur_promotion(current[0], count) : next
end
cart.coupon_name ? coupon_total(invoice_total) : invoice_total
end
def cur_promotion(current, count)
if current.get_one_free?
calc_one_free(current, count)
elsif current.package?
calc_package(current, count)
else calc_threshold(current, count)
end
end
def calc_one_free(current, count)
count / current.promotion.values[0] * current.value
end
def calc_package(current, count)
package = current.promotion.values[0].keys[0]
percent = current.promotion.values[0].values[0]
((count/package) * package) * ("0.#{percent}".to_d * current.value)
end
def calc_threshold(current, count)
package = current.promotion.values[0].keys[0]
percent = current.promotion.values[0].values[0]
count > package ? (count - package) * ("0.#{percent}".to_d * current.value) : 0
end
def coupon_total(total_without_coupon)
tmp = @cart.coupons.select { |coupon| coupon.name == @cart.coupon_name}
if tmp[0].amount?
total = total_without_coupon - tmp[0].value.to_d
else
@without_coupon2 = "0.#{tmp[0].value}".to_d * total_without_coupon
total = total_without_coupon - @without_coupon2
end
@without_coupon1 = total
total < 0 ? '0.00'.to_d : total
end
def print_invoice
invoice = @printer.invoice_top
@cart.cart_products.each do |product|
count = product[:count]
current = @cart.inventory.select { |prod| product[:product] == prod.name }
invoice << @printer.pr_product(product[:product], count, current[0].value * count)
current[0].promotion? ? invoice << print_promotion(current[0], count) : next
end
if @cart.coupon_name then invoice << print_coupon(total)
end
invoice << @printer.invoice_bottom(total)
end
def print_promotion(current, count)
if current.get_one_free?
@printer.promotion_get(current.promotion.values[0], cur_promotion(current, count))
else
broika = current.promotion.values[0].values[0]
percent = current.promotion.values[0].keys[0]
if current.package?
@printer.promotion_package(broika, percent, cur_promotion(current, count))
else
@printer.promotion_threshold(broika, percent, cur_promotion(current, count))
end
end
end
def print_coupon(total)
current = @cart.coupons.select { |coupon| @cart.coupon_name == coupon.name }
if current[0].amount?
@printer.coupon_amount(current[0].name, current[0].value, @without_coupon1)
else @printer.coupon_percent(current[0].name, current[0].value, @without_coupon2)
end
end
end
class Printer
attr_accessor :lines, :symbol
def initialize
@lines = "+------------------------------------------------+----------+\n"
@symbol = "%"
end
def invoice_top
sprintf("%s| Name qty | price |\n%s", @lines, @lines)
end
def invoice_bottom(total)
sprintf("%s| TOTAL | %.2f |\n%s", @lines, total, @lines)
end
def pr_product(name, qty, price)
sprintf("| %s %d | %.2f |\n", name, qty, price)
end
def coupon_amount(name, price, discount)
sprintf("| Coupon %s - %.2f off | %.2f |\n", name, price, discount)
end
def coupon_percent(name, price, discount)
sprintf("| Coupon %s - %d%s off | -%.2f |\n", name, price, @symbol, discount)
end
def promotion_get(value, discount)
sprintf("| (buy %d, get 1 free) | -%.2f |\n", value - 1, discount)
end
def promotion_package(percent, value, discount)
package = "| (get #{percent}% off for every #{value}) |"
sprintf("%s -%.2f |\n",package, discount)
end
def promotion_threshold(percent, value, discount)
symbol = "%"
case value
when 1 then ending = "st"
when 2 then ending = "nd"
when 3 then ending = "rd"
else ending = "th"
end
threshold = "| (#{percent}% off of every after the #{value}"
sprintf("%s%s) | -%.2f |\n", threshold, ending, 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-127y6mi/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-127y6mi/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-127y6mi/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-127y6mi/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-127y6mi/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-127y6mi/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-127y6mi/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.56974 seconds
19 examples, 7 failures

Failed examples:

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

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

Дарина обнови решението на 05.11.2011 00:34 (преди около 13 години)

+#!/usr/local/rvm/rubies/ruby-1.9.2-p290/bin/ruby
+
+require 'bigdecimal'
+require 'bigdecimal/util'
+
+class Product
+
+ attr_accessor :name, :value, :promotion
+
+ def initialize(name, value, promotion=nil)
+ if name.length <= 40 and value.to_d >= 0.01 and value.to_d <= 999.99
+ @name = name
+ @value = value.to_d
+ else raise "Invalid parameters passed."
+ end
+ @promotion = promotion
+ end
+
+ def promotion?
+ return true if @promotion
+ false
+ end
+
+ def get_one_free?
+ return true if @promotion[:get_one_free]
+ false
+ end
+
+ def package?
+ return true if @promotion[:package]
+ false
+ end
+
+end
+
+
+class Inventory
+
+ attr_accessor :all_products, :coupons
+
+ def initialize
+ @all_products = []
+ @coupons=[]
+ end
+
+ def register(name, value, promotion=nil)
+ if @all_products.any? { |product| product.name == name }
+ raise "Dublicate names."
+ else @all_products << Product.new(name, value, promotion)
+ end
+ end
+
+ def new_cart
+ cart = Cart.new(@all_products, @coupons)
+ end
+
+ def register_coupon(name, type)
+ if @coupons.any? { |coupon| coupon.name == name }
+ raise "Dublicate names of coupons."
+ else @coupons << Coupon.new(name, type)
+ end
+ end
+
+end
+
+class Coupon
+
+ attr_accessor :name, :type, :value
+
+ def initialize(name, type)
+ @name = name
+ @type = type
+ @value = type.values[0]
+ end
+
+ def amount?
+ return true if @type[:amount]
+ false
+ end
+
+end
+
+class Cart
+
+ attr_accessor :inventory, :coupons, :coupon_name, :cart_products, :invoice, :total
+
+ def initialize(inventory, coupons)
+ @cart_products = []
+ @inventory = inventory
+ @coupons = coupons
+ end
+
+ def add(product_name, count = 1)
+ if @inventory.none? { |product| product.name == product_name }
+ raise "There isn't such a product in the inventory."
+ elsif not_allowable_count?(count)
+ raise "Quantity must be between 1 and 99 inclusive."
+ else helper_add(product_name, count)
+ end
+ end
+
+ def helper_add(name, count)
+ if @cart_products.any? { |prod| prod[:product] == name }
+ current = @cart_products.select { |pr| pr[:product] == name }
+ current[0][:count]+=count
+ else @cart_products << { product: name, count: count }
+ end
+ end
+
+ def use(coupon_name)
+ if @coupon_name
+ raise "Caupon has been already add to this cart."
+ elsif @coupons.none? { |coupon| coupon.name == coupon_name}
+ raise "There isn't such an coupon in the inventory"
+ else @coupon_name = coupon_name
+ end
+ end
+
+ def not_allowable_count?(count)
+ return false if count >=1 and count <= 99
+ true
+ end
+
+ def init_invoice
+ @invoice = Invoice.new(self)
+ end
+
+ def invoice
+ init_invoice
+ @invoice.print_invoice
+ end
+
+ def total
+ init_invoice
+ @invoice.total
+ end
+
+end
+
+class Invoice
+
+ attr_accessor :cart, :printer
+
+ def initialize(cart)
+ @cart = cart
+ @printer = Printer.new
+ end
+
+ def total
+ invoice_total=0
+ @cart.cart_products.each do |product|
+ current = @cart.inventory.select { |prod| product[:product] == prod.name }
+ invoice_total += current[0].value * product[:count]
+ count = product[:count]
+ current[0].promotion? ? invoice_total -= cur_promotion(current[0], count) : next
+ end
+ cart.coupon_name ? coupon_total(invoice_total) : invoice_total
+ end
+
+ def cur_promotion(current, count)
+ if current.get_one_free?
+ calc_one_free(current, count)
+ elsif current.package?
+ calc_package(current, count)
+ else calc_threshold(current, count)
+ end
+ end
+
+ def calc_one_free(current, count)
+ count / current.promotion.values[0] * current.value
+ end
+
+ def calc_package(current, count)
+ package = current.promotion.values[0].keys[0]
+ percent = current.promotion.values[0].values[0]
+ ((count/package) * package) * ("0.#{percent}".to_d * current.value)
+ end
+
+ def calc_threshold(current, count)
+ package = current.promotion.values[0].keys[0]
+ percent = current.promotion.values[0].values[0]
+ count > package ? (count - package) * ("0.#{percent}".to_d * current.value) : 0
+ end
+
+ def coupon_total(total_without_coupon)
+ tmp = @cart.coupons.select { |coupon| coupon.name == @cart.coupon_name}
+ if tmp[0].amount?
+ total = total_without_coupon - tmp[0].value.to_d
+ else
+ @without_coupon2 = "0.#{tmp[0].value}".to_d * total_without_coupon
+ total = total_without_coupon - @without_coupon2
+ end
+ @without_coupon1 = total
+ total < 0 ? '0.00'.to_d : total
+ end
+
+ def print_invoice
+ invoice = @printer.invoice_top
+ @cart.cart_products.each do |product|
+ count = product[:count]
+ current = @cart.inventory.select { |prod| product[:product] == prod.name }
+ invoice << @printer.pr_product(product[:product], count, current[0].value * count)
+ current[0].promotion? ? invoice << print_promotion(current[0], count) : next
+ end
+ if @cart.coupon_name then invoice << print_coupon(total)
+ end
+ invoice << @printer.invoice_bottom(total)
+ end
+
+ def print_promotion(current, count)
+ if current.get_one_free?
+ @printer.promotion_get(current.promotion.values[0], cur_promotion(current, count))
+ else
+ broika = current.promotion.values[0].values[0]
+ percent = current.promotion.values[0].keys[0]
+ if current.package?
+ @printer.promotion_package(broika, percent, cur_promotion(current, count))
+ else
+ @printer.promotion_threshold(broika, percent, cur_promotion(current, count))
+ end
+ end
+ end
+
+ def print_coupon(total)
+ current = @cart.coupons.select { |coupon| @cart.coupon_name == coupon.name }
+ if current[0].amount?
+ @printer.coupon_amount(current[0].name, current[0].value, @without_coupon1)
+ else @printer.coupon_percent(current[0].name, current[0].value, @without_coupon2)
+ end
+ end
+
+end
+
+
+class Printer
+
+ attr_accessor :lines, :symbol
+
+ def initialize
+ @lines = "+------------------------------------------------+----------+\n"
+ @symbol = "%"
+ end
+
+ def invoice_top
+ sprintf("%s| Name qty | price |\n%s", @lines, @lines)
+ end
+
+ def invoice_bottom(total)
+ sprintf("%s| TOTAL | %.2f |\n%s", @lines, total, @lines)
+ end
+
+ def pr_product(name, qty, price)
+ sprintf("| %s %d | %.2f |\n", name, qty, price)
+ end
+
+ def coupon_amount(name, price, discount)
+ sprintf("| Coupon %s - %.2f off | %.2f |\n", name, price, discount)
+ end
+
+ def coupon_percent(name, price, discount)
+ sprintf("| Coupon %s - %d%s off | -%.2f |\n", name, price, @symbol, discount)
+ end
+
+ def promotion_get(value, discount)
+ sprintf("| (buy %d, get 1 free) | -%.2f |\n", value - 1, discount)
+ end
+
+ def promotion_package(percent, value, discount)
+ package = "| (get #{percent}% off for every #{value}) |"
+ sprintf("%s -%.2f |\n",package, discount)
+ end
+
+ def promotion_threshold(percent, value, discount)
+ symbol = "%"
+ case value
+ when 1 then ending = "st"
+ when 2 then ending = "nd"
+ when 3 then ending = "rd"
+ else ending = "th"
+ end
+ threshold = "| (#{percent}% off of every after the #{value}"
+ sprintf("%s%s) | -%.2f |\n", threshold, ending, discount)
+ end
+
+end
+