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

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

Към профила на Недислав Стойчев

Резултати

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

Код

class Inventory
attr_accessor :inventory
attr_accessor :coupon
attr_accessor :promo
def initialize
@inventory = Hash[]
@coupon = Hash[]
@promo = Hash[]
end
def register(name, price, pr_promo = Hash[])
if inventory.has_key? name then raise "Duplicate products!" end
if check_name? name and check_price? price then inventory[name] = price.to_d end
if pr_promo != Hash[] then product_promo(name, pr_promo) end
end
def product_promo(name, pr_promo)
if pr_promo.has_key? :get_one_free
promo[name] = Hash[:get_one_free, pr_promo[:get_one_free]]
end
if pr_promo.has_key? :package
promo[name] = Hash[:package, pr_promo[:package]]
end
if pr_promo.has_key? :threshold
promo[name] = Hash[:threshold, pr_promo[:threshold]]
end
end
def check_name?(name)
if name.size > 0 and name.size <= 40
return true
end
raise "Wrong 'name' input!"
end
def check_price?(price)
if price.to_d > 0.00 and price.to_d <= 999.99
return true
end
raise"Wrong 'price' input!"
end
def register_coupon(name, kind)
if kind.has_key? :amount or kind.has_key? :percent
coupon[name.upcase] = kind
end
end
def new_cart
return Cart.new inventory, promo, coupon
end
end
class Cart
attr_accessor :cart
attr_reader :inventory
attr_reader :promo
attr_reader :promotion
attr_reader :coupon
attr_reader :coupon_discount
attr_accessor :coupon_used
def initialize(inventory, promo, coupon)
@cart = Hash[]
@inventory = inventory
@promo = promo
@promotion = Promotion.new
@coupon = coupon
@coupon_discount = 0
@coupon_used = false
end
def add(name, qty = 1)
if inventory.has_key? name
if !cart.has_key? name and qty > 0
cart[name] = qty
else
cart_add name, qty
end
else
raise "No such product in inventory!"
end
end
def cart_add(name, qty)
if ((cart[name]+qty) < 99) and qty > 0
cart[name] += qty
else
raise "Product quantity reached 99 or input 'qty' under 0!"
end
end
def use(name)
if coupon.has_key? name.upcase and coupon[name.upcase].has_key? :amount
@coupon_used = true
if coupon[name.upcase][:amount] > total
@coupon_discount = total
else
@coupon_discount = coupon[name.upcase][:amount]
end
end
if coupon.has_key? name.upcase and coupon[name.upcase].has_key? :percent
@coupon_used = true
@coupon_discount = (total * (coupon[name.upcase][:percent] / 100.0)).to_d
end
end
def print_coupon
if coupon_used
if coupon[coupon.keys[0]].has_key? :amount
name = coupon.keys[0]
amount = coupon[name][:amount]
output = "| Coupon #{name} - #{amount}".ljust(49)+"|"
puts output+("-%.2f" % @coupon_discount).rjust(9)+" |"
end
if coupon[coupon.keys[0]].has_key? :percent
print_coupon_percent
end
end
end
def print_coupon_percent
name = coupon.keys[0]
percent = coupon[name][:percent]
output = "| Coupon #{name} - #{percent}% off".ljust(49)+"|"
puts output+("-%.2f" % @coupon_discount).rjust(9)+" |"
end
def total
result = 0
cart.each do |key, value|
pr_promo = if promo.has_key? key then calc_promo(key, value) else 0 end
result += inventory[key]*value-pr_promo
end
return (result - coupon_discount).to_d
end
def calc_promo(key, value)
result = 0
if promo[key].has_key? :get_one_free
result = promotion.calc_get_one_free(inventory, cart, promo, key, value)
end
if promo[key].has_key? :package
result = promotion.calc_package(inventory, cart, promo, key, value)
end
if promo[key].has_key? :threshold and promo[key][:threshold].keys[0]<cart[key]
result = promotion.calc_threshold(inventory, cart, promo, key, value)
end
return result
end
def invoice
puts "+#{"-"*48}+----------+
| Name#{" "*39}qty | price |
+#{"-"*48}+----------+
"
print_products
print_coupon
puts "+#{"-"*48}+----------+
| TOTAL#{" "*42}|#{(" %.2f" % total.to_s).rjust(9) + " |"}
+#{"-"*48}+----------+
"
end
def print_products
cart.each do |key, value|
sum = value*inventory[key]
puts "| #{key.ljust(44)+value.to_s.rjust(2)} |"+("%.2f" % sum).rjust(9)+" |"
promotion.print_promotions(inventory, cart, promo, key, value)
end
end
end
class Promotion
def calc_get_one_free(inventory, cart, promo, key, value)
free = promo[key][:get_one_free]
return (cart[key]/free)*inventory[key]
end
def calc_package(inventory, cart, promo, key, value)
pack = promo[key][:package].keys[0]
percent = promo[key][:package].values[0]
result = (cart[key]/pack)*pack*inventory[key]*(percent/100.0)
return result
end
def calc_threshold(inventory, cart, promo, key, value)
price = inventory[key]
discount = promo[key][:threshold].values[0] / 100.0
threshold = promo[key][:threshold].keys[0]
result = (discount/price)*(cart[key] - threshold)
return result
end
def print_promotions(inventory, cart, promo, key, value)
if promo.has_key? key
if promo[key].has_key? :get_one_free
puts_get_one_free(inventory, cart, promo, key, value)
end
if promo[key].has_key? :package
puts_package(inventory, cart, promo, key, value)
end
if promo[key].has_key? :threshold
puts_threshold(inventory, cart, promo, key, value)
end
end
end
def puts_get_one_free(inventory, cart, promo, key, value)
free = promo[key][:get_one_free]
result = (cart[key]/free)*inventory[key]
puts "| (buy #{free - 1}, get 1 free)#{" "*26}|"+("-%.2f" % result).rjust(9)+" |"
end
def puts_package(inventory, cart, promo, key, value)
pack = promo[key][:package].keys[0]
percent = promo[key][:package].values[0]
result = (cart[key]/pack)*pack*inventory[key]*(percent/100.0)
output = "| (get #{percent}% off for every #{pack})#{" "*20}|"
puts output+("-%.2f" % result).rjust(9)+" |"
end
def puts_threshold(inventory, cart, promo, key, value)
price = inventory[key]
discount = promo[key][:threshold].values[0]
threshold = promo[key][:threshold].keys[0]
result = ((discount/100.0)/price)*(cart[key] - threshold)
output = "| (#{discount}% off of every after the #{threshold}rd)#{" "*13}|"
puts output+("-%.2f" % result).rjust(9)+" |"
end
end

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

FFFFFFFFFFFFFFFFFFF

Failures:

  1) Inventory with no discounts can tell the total price of all products
     Failure/Error: inventory.register 'The Best of Coltrane CD', '1.99'
     NoMethodError:
       undefined method `to_d' for "1.99":String
     # /tmp/d20111115-5847-xw27j7/solution.rb:38:in `check_price?'
     # /tmp/d20111115-5847-xw27j7/solution.rb:14:in `register'
     # /tmp/d20111115-5847-xw27j7/spec.rb:39: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 has some constraints on prices and counts
     Failure/Error: inventory.register 'Existing', '1.00'
     NoMethodError:
       undefined method `to_d' for "1.00":String
     # /tmp/d20111115-5847-xw27j7/solution.rb:38:in `check_price?'
     # /tmp/d20111115-5847-xw27j7/solution.rb:14:in `register'
     # /tmp/d20111115-5847-xw27j7/spec.rb:48: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 no discounts can print an invoice
     Failure/Error: inventory.register 'Green Tea',    '0.79'
     NoMethodError:
       undefined method `to_d' for "0.79":String
     # /tmp/d20111115-5847-xw27j7/solution.rb:38:in `check_price?'
     # /tmp/d20111115-5847-xw27j7/solution.rb:14:in `register'
     # /tmp/d20111115-5847-xw27j7/spec.rb:65: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 'buy X, get one free' promotion grants every nth item for free
     Failure/Error: inventory.register 'Gum', '1.00', get_one_free: 4
     NoMethodError:
       undefined method `to_d' for "1.00":String
     # /tmp/d20111115-5847-xw27j7/solution.rb:38:in `check_price?'
     # /tmp/d20111115-5847-xw27j7/solution.rb:14:in `register'
     # /tmp/d20111115-5847-xw27j7/spec.rb:89: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 'buy X, get one free' promotion grants 2 items free, when 8 purchased and every 3rd is free
     Failure/Error: inventory.register 'Gum', '1.00', get_one_free: 3
     NoMethodError:
       undefined method `to_d' for "1.00":String
     # /tmp/d20111115-5847-xw27j7/solution.rb:38:in `check_price?'
     # /tmp/d20111115-5847-xw27j7/solution.rb:14:in `register'
     # /tmp/d20111115-5847-xw27j7/spec.rb:97: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 'buy X, get one free' promotion shows the discount in the invoice
     Failure/Error: inventory.register 'Green Tea', '1.00', get_one_free: 3
     NoMethodError:
       undefined method `to_d' for "1.00":String
     # /tmp/d20111115-5847-xw27j7/solution.rb:38:in `check_price?'
     # /tmp/d20111115-5847-xw27j7/solution.rb:14:in `register'
     # /tmp/d20111115-5847-xw27j7/spec.rb:105: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 a '% off for every n' promotion gives % off for every group of n
     Failure/Error: inventory.register 'Sandwich', '1.00', package: {4 => 20}
     NoMethodError:
       undefined method `to_d' for "1.00":String
     # /tmp/d20111115-5847-xw27j7/solution.rb:38:in `check_price?'
     # /tmp/d20111115-5847-xw27j7/solution.rb:14:in `register'
     # /tmp/d20111115-5847-xw27j7/spec.rb:128: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 a '% off for every n' promotion does not discount for extra items, that don't fit in a group
     Failure/Error: inventory.register 'Sandwich', '0.50', package: {4 => 10}
     NoMethodError:
       undefined method `to_d' for "0.50":String
     # /tmp/d20111115-5847-xw27j7/solution.rb:38:in `check_price?'
     # /tmp/d20111115-5847-xw27j7/solution.rb:14:in `register'
     # /tmp/d20111115-5847-xw27j7/spec.rb:138: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)>'

  9) Inventory with a '% off for every n' promotion shows the discount in the invoice
     Failure/Error: inventory.register 'Green Tea', '1.00', package: {4 => 10}
     NoMethodError:
       undefined method `to_d' for "1.00":String
     # /tmp/d20111115-5847-xw27j7/solution.rb:38:in `check_price?'
     # /tmp/d20111115-5847-xw27j7/solution.rb:14:in `register'
     # /tmp/d20111115-5847-xw27j7/spec.rb:148: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)>'

  10) Inventory with a '% off of every item after the nth' promotion gives a discount for every item after the nth
     Failure/Error: inventory.register 'Coke', '2.00', threshold: {5 => 10}
     NoMethodError:
       undefined method `to_d' for "2.00":String
     # /tmp/d20111115-5847-xw27j7/solution.rb:38:in `check_price?'
     # /tmp/d20111115-5847-xw27j7/solution.rb:14:in `register'
     # /tmp/d20111115-5847-xw27j7/spec.rb:171: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)>'

  11) Inventory with a '% off of every item after the nth' promotion does not give a discount if there are no more than n items in the cart
     Failure/Error: inventory.register 'Coke', '1.00', threshold: {10 => 20}
     NoMethodError:
       undefined method `to_d' for "1.00":String
     # /tmp/d20111115-5847-xw27j7/solution.rb:38:in `check_price?'
     # /tmp/d20111115-5847-xw27j7/solution.rb:14:in `register'
     # /tmp/d20111115-5847-xw27j7/spec.rb:178: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)>'

  12) Inventory with a '% off of every item after the nth' promotion shows the discount in the ivnoice
     Failure/Error: inventory.register 'Green Tea', '1.00', threshold: {10 => 10}
     NoMethodError:
       undefined method `to_d' for "1.00":String
     # /tmp/d20111115-5847-xw27j7/solution.rb:38:in `check_price?'
     # /tmp/d20111115-5847-xw27j7/solution.rb:14:in `register'
     # /tmp/d20111115-5847-xw27j7/spec.rb:191: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)>'

  13) Inventory with a '% off' coupon gives % off of the total
     Failure/Error: inventory.register 'Tea', '1.00'
     NoMethodError:
       undefined method `to_d' for "1.00":String
     # /tmp/d20111115-5847-xw27j7/solution.rb:38:in `check_price?'
     # /tmp/d20111115-5847-xw27j7/solution.rb:14:in `register'
     # /tmp/d20111115-5847-xw27j7/spec.rb:214: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)>'

  14) Inventory with a '% off' coupon applies the coupon discount after product promotions
     Failure/Error: inventory.register 'Tea', '1.00', get_one_free: 6
     NoMethodError:
       undefined method `to_d' for "1.00":String
     # /tmp/d20111115-5847-xw27j7/solution.rb:38:in `check_price?'
     # /tmp/d20111115-5847-xw27j7/solution.rb:14:in `register'
     # /tmp/d20111115-5847-xw27j7/spec.rb:224: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)>'

  15) Inventory with a '% off' coupon shows the discount in the invoice
     Failure/Error: inventory.register 'Green Tea', '1.00'
     NoMethodError:
       undefined method `to_d' for "1.00":String
     # /tmp/d20111115-5847-xw27j7/solution.rb:38:in `check_price?'
     # /tmp/d20111115-5847-xw27j7/solution.rb:14:in `register'
     # /tmp/d20111115-5847-xw27j7/spec.rb:234: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)>'

  16) Inventory with an 'amount off' coupon subtracts the amount form the total
     Failure/Error: inventory.register 'Tea', '1.00'
     NoMethodError:
       undefined method `to_d' for "1.00":String
     # /tmp/d20111115-5847-xw27j7/solution.rb:38:in `check_price?'
     # /tmp/d20111115-5847-xw27j7/solution.rb:14:in `register'
     # /tmp/d20111115-5847-xw27j7/spec.rb:255: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)>'

  17) Inventory with an 'amount off' coupon does not result in a negative total
     Failure/Error: inventory.register 'Tea', '1.00'
     NoMethodError:
       undefined method `to_d' for "1.00":String
     # /tmp/d20111115-5847-xw27j7/solution.rb:38:in `check_price?'
     # /tmp/d20111115-5847-xw27j7/solution.rb:14:in `register'
     # /tmp/d20111115-5847-xw27j7/spec.rb:265: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)>'

  18) Inventory with an 'amount off' coupon shows the discount in the invoice
     Failure/Error: inventory.register 'Green Tea', '1.00'
     NoMethodError:
       undefined method `to_d' for "1.00":String
     # /tmp/d20111115-5847-xw27j7/solution.rb:38:in `check_price?'
     # /tmp/d20111115-5847-xw27j7/solution.rb:14:in `register'
     # /tmp/d20111115-5847-xw27j7/spec.rb:275: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)>'

  19) Inventory with multiple discounts can print an invoice
     Failure/Error: inventory.register 'Green Tea',    '2.79', get_one_free: 2
     NoMethodError:
       undefined method `to_d' for "2.79":String
     # /tmp/d20111115-5847-xw27j7/solution.rb:38:in `check_price?'
     # /tmp/d20111115-5847-xw27j7/solution.rb:14:in `register'
     # /tmp/d20111115-5847-xw27j7/spec.rb:296: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.55444 seconds
19 examples, 19 failures

Failed examples:

rspec /tmp/d20111115-5847-xw27j7/spec.rb:38 # Inventory with no discounts can tell the total price of all products
rspec /tmp/d20111115-5847-xw27j7/spec.rb:47 # Inventory with no discounts has some constraints on prices and counts
rspec /tmp/d20111115-5847-xw27j7/spec.rb:64 # Inventory with no discounts can print an invoice
rspec /tmp/d20111115-5847-xw27j7/spec.rb:88 # Inventory with a 'buy X, get one free' promotion grants every nth item for free
rspec /tmp/d20111115-5847-xw27j7/spec.rb:96 # Inventory with a 'buy X, get one free' promotion grants 2 items free, when 8 purchased and every 3rd is free
rspec /tmp/d20111115-5847-xw27j7/spec.rb:104 # Inventory with a 'buy X, get one free' promotion shows the discount in the invoice
rspec /tmp/d20111115-5847-xw27j7/spec.rb:127 # Inventory with a '% off for every n' promotion gives % off for every group of n
rspec /tmp/d20111115-5847-xw27j7/spec.rb:137 # Inventory with a '% off for every n' promotion does not discount for extra items, that don't fit in a group
rspec /tmp/d20111115-5847-xw27j7/spec.rb:147 # Inventory with a '% off for every n' promotion shows the discount in the invoice
rspec /tmp/d20111115-5847-xw27j7/spec.rb:170 # Inventory with a '% off of every item after the nth' promotion gives a discount for every item after the nth
rspec /tmp/d20111115-5847-xw27j7/spec.rb:177 # Inventory with a '% off of every item after the nth' promotion does not give a discount if there are no more than n items in the cart
rspec /tmp/d20111115-5847-xw27j7/spec.rb:190 # Inventory with a '% off of every item after the nth' promotion shows the discount in the ivnoice
rspec /tmp/d20111115-5847-xw27j7/spec.rb:213 # Inventory with a '% off' coupon gives % off of the total
rspec /tmp/d20111115-5847-xw27j7/spec.rb:223 # Inventory with a '% off' coupon applies the coupon discount after product promotions
rspec /tmp/d20111115-5847-xw27j7/spec.rb:233 # Inventory with a '% off' coupon shows the discount in the invoice
rspec /tmp/d20111115-5847-xw27j7/spec.rb:254 # Inventory with an 'amount off' coupon subtracts the amount form the total
rspec /tmp/d20111115-5847-xw27j7/spec.rb:264 # Inventory with an 'amount off' coupon does not result in a negative total
rspec /tmp/d20111115-5847-xw27j7/spec.rb:274 # Inventory with an 'amount off' coupon shows the discount in the invoice
rspec /tmp/d20111115-5847-xw27j7/spec.rb:295 # Inventory with multiple discounts can print an invoice

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

Недислав обнови решението на 06.11.2011 18:52 (преди над 12 години)

+class Inventory
+ attr_accessor :inventory
+ attr_accessor :coupon
+ attr_accessor :promo
+
+ def initialize
+ @inventory = Hash[]
+ @coupon = Hash[]
+ @promo = Hash[]
+ end
+
+ def register(name, price, pr_promo = Hash[])
+ if inventory.has_key? name then raise "Duplicate products!" end
+ if check_name? name and check_price? price then inventory[name] = price.to_d end
+ if pr_promo != Hash[] then product_promo(name, pr_promo) end
+ end
+
+ def product_promo(name, pr_promo)
+ if pr_promo.has_key? :get_one_free
+ promo[name] = Hash[:get_one_free, pr_promo[:get_one_free]]
+ end
+ if pr_promo.has_key? :package
+ promo[name] = Hash[:package, pr_promo[:package]]
+ end
+ if pr_promo.has_key? :threshold
+ promo[name] = Hash[:threshold, pr_promo[:threshold]]
+ end
+ end
+
+ def check_name?(name)
+ if name.size > 0 and name.size <= 40
+ return true
+ end
+ raise "Wrong 'name' input!"
+ end
+
+ def check_price?(price)
+ if price.to_d > 0.00 and price.to_d <= 999.99
+ return true
+ end
+ raise"Wrong 'price' input!"
+ end
+
+ def register_coupon(name, kind)
+ if kind.has_key? :amount or kind.has_key? :percent
+ coupon[name.upcase] = kind
+ end
+ end
+
+ def new_cart
+ return Cart.new inventory, promo, coupon
+ end
+end
+
+class Cart
+ attr_accessor :cart
+ attr_reader :inventory
+ attr_reader :promo
+ attr_reader :promotion
+ attr_reader :coupon
+ attr_reader :coupon_discount
+ attr_accessor :coupon_used
+
+ def initialize(inventory, promo, coupon)
+ @cart = Hash[]
+ @inventory = inventory
+ @promo = promo
+ @promotion = Promotion.new
+ @coupon = coupon
+ @coupon_discount = 0
+ @coupon_used = false
+ end
+
+ def add(name, qty = 1)
+ if inventory.has_key? name
+ if !cart.has_key? name and qty > 0
+ cart[name] = qty
+ else
+ cart_add name, qty
+ end
+ else
+ raise "No such product in inventory!"
+ end
+ end
+
+ def cart_add(name, qty)
+ if ((cart[name]+qty) < 99) and qty > 0
+ cart[name] += qty
+ else
+ raise "Product quantity reached 99 or input 'qty' under 0!"
+ end
+ end
+
+ def use(name)
+ if coupon.has_key? name.upcase and coupon[name.upcase].has_key? :amount
+ @coupon_used = true
+ if coupon[name.upcase][:amount] > total
+ @coupon_discount = total
+ else
+ @coupon_discount = coupon[name.upcase][:amount]
+ end
+ end
+ if coupon.has_key? name.upcase and coupon[name.upcase].has_key? :percent
+ @coupon_used = true
+ @coupon_discount = (total * (coupon[name.upcase][:percent] / 100.0)).to_d
+ end
+ end
+
+ def print_coupon
+ if coupon_used
+ if coupon[coupon.keys[0]].has_key? :amount
+ name = coupon.keys[0]
+ amount = coupon[name][:amount]
+ output = "| Coupon #{name} - #{amount}".ljust(49)+"|"
+ puts output+("-%.2f" % @coupon_discount).rjust(9)+" |"
+ end
+ if coupon[coupon.keys[0]].has_key? :percent
+ print_coupon_percent
+ end
+ end
+ end
+
+ def print_coupon_percent
+ name = coupon.keys[0]
+ percent = coupon[name][:percent]
+ output = "| Coupon #{name} - #{percent}% off".ljust(49)+"|"
+ puts output+("-%.2f" % @coupon_discount).rjust(9)+" |"
+ end
+
+ def total
+ result = 0
+ cart.each do |key, value|
+ pr_promo = if promo.has_key? key then calc_promo(key, value) else 0 end
+ result += inventory[key]*value-pr_promo
+ end
+ return (result - coupon_discount).to_d
+ end
+
+ def calc_promo(key, value)
+ result = 0
+ if promo[key].has_key? :get_one_free
+ result = promotion.calc_get_one_free(inventory, cart, promo, key, value)
+ end
+ if promo[key].has_key? :package
+ result = promotion.calc_package(inventory, cart, promo, key, value)
+ end
+ if promo[key].has_key? :threshold and promo[key][:threshold].keys[0]<cart[key]
+ result = promotion.calc_threshold(inventory, cart, promo, key, value)
+ end
+ return result
+ end
+
+ def invoice
+ puts "+#{"-"*48}+----------+
+| Name#{" "*39}qty | price |
++#{"-"*48}+----------+
+"
+ print_products
+ print_coupon
+ puts "+#{"-"*48}+----------+
+| TOTAL#{" "*42}|#{(" %.2f" % total.to_s).rjust(9) + " |"}
++#{"-"*48}+----------+
+"
+ end
+
+ def print_products
+ cart.each do |key, value|
+ sum = value*inventory[key]
+ puts "| #{key.ljust(44)+value.to_s.rjust(2)} |"+("%.2f" % sum).rjust(9)+" |"
+ promotion.print_promotions(inventory, cart, promo, key, value)
+ end
+ end
+end
+
+class Promotion
+
+ def calc_get_one_free(inventory, cart, promo, key, value)
+ free = promo[key][:get_one_free]
+ return (cart[key]/free)*inventory[key]
+ end
+
+ def calc_package(inventory, cart, promo, key, value)
+ pack = promo[key][:package].keys[0]
+ percent = promo[key][:package].values[0]
+ result = (cart[key]/pack)*pack*inventory[key]*(percent/100.0)
+ return result
+ end
+
+ def calc_threshold(inventory, cart, promo, key, value)
+ price = inventory[key]
+ discount = promo[key][:threshold].values[0] / 100.0
+ threshold = promo[key][:threshold].keys[0]
+ result = (discount/price)*(cart[key] - threshold)
+ return result
+ end
+
+ def print_promotions(inventory, cart, promo, key, value)
+ if promo.has_key? key
+ if promo[key].has_key? :get_one_free
+ puts_get_one_free(inventory, cart, promo, key, value)
+ end
+ if promo[key].has_key? :package
+ puts_package(inventory, cart, promo, key, value)
+ end
+ if promo[key].has_key? :threshold
+ puts_threshold(inventory, cart, promo, key, value)
+ end
+ end
+ end
+
+ def puts_get_one_free(inventory, cart, promo, key, value)
+ free = promo[key][:get_one_free]
+ result = (cart[key]/free)*inventory[key]
+ puts "| (buy #{free - 1}, get 1 free)#{" "*26}|"+("-%.2f" % result).rjust(9)+" |"
+ end
+
+ def puts_package(inventory, cart, promo, key, value)
+ pack = promo[key][:package].keys[0]
+ percent = promo[key][:package].values[0]
+ result = (cart[key]/pack)*pack*inventory[key]*(percent/100.0)
+ output = "| (get #{percent}% off for every #{pack})#{" "*20}|"
+ puts output+("-%.2f" % result).rjust(9)+" |"
+ end
+
+ def puts_threshold(inventory, cart, promo, key, value)
+ price = inventory[key]
+ discount = promo[key][:threshold].values[0]
+ threshold = promo[key][:threshold].keys[0]
+ result = ((discount/100.0)/price)*(cart[key] - threshold)
+ output = "| (#{discount}% off of every after the #{threshold}rd)#{" "*13}|"
+ puts output+("-%.2f" % result).rjust(9)+" |"
+ end
+end