Решение на Трета задача от Петър Костов

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

Към профила на Петър Костов

Резултати

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

Код

require 'bigdecimal'
require 'bigdecimal/util'
class Item
attr_reader :name, :price, :promotion
def initialize(name, price, promotion = nil)
@name, @price, @promotion = name, BigDecimal(price), promotion
end
end
class Coupon
attr_reader :name, :type
def initialize(name, type)
@name = name
@type = type
end
end
class Cart
def initialize(inventory_items, inventory_coupons)
@inventory_items = inventory_items
@inventory_coupons = inventory_coupons
@cart_items = Hash.new(0)
@used_coupon = nil
end
def add(name, amount = 1)
validate_item(name, amount)
@cart_items[name] += amount
end
def use(name)
validate_coupon(name)
@used_coupon = @inventory_coupons.select { |coupon| coupon.name == name }[0]
end
def total
inv_test = InvoiceCalc.new(@inventory_items, @cart_items, @used_coupon)
inv_test.calculate_per_item
inv_test.calculate_promotion
inv_test.calculate_total.keys[0]
end
def invoice
#do somthing
#invoiceCalc = InvoiceCalc.new(@inventory_items, @cart_items, @used_coupon)
invoice_print = InvoicePrint.new(@inventory_items, @cart_items, @used_coupon)
invoice_print.print
end
private
def validate_item(name, amount)
dont_exist = @inventory_items.all? { |item| item.name != name }
amount_negative = amount<=0
big_amount = @cart_items[name] + amount > 99
raise "Invalide parameters passed!" if dont_exist or amount_negative or big_amount
end
def validate_coupon(coupon_name)
exist = @inventory_coupons.any? { |coupon| coupon.name == coupon_name }
raise "Invalide coupon is used!" if !exist
end
end
class Inventory
def initialize()
@items = []
@coupons = []
end
def register(name, price, promotion = nil)
validate_name(name)
validate_price(BigDecimal(price))
validate_promotion(promotion)
@items << Item.new(name, price, promotion)
end
def register_coupon(name, type)
validate_coupon_name(name)
validate_coupon_type(type)
@coupons << Coupon.new(name, type)
end
def new_cart
Cart.new(@items, @coupons)
end
private
def validate_name(name)
name_size = name.size>40
dublicate_item = @items.any? { |item| item.name == name }
raise "Invalide name passed!" if name_size or dublicate_item
end
def validate_price(price)
if price < BigDecimal('0.01') or price > BigDecimal('999.99')
raise "Invalide price passed!"
end
end
def validate_promotion(promotion)
#posle
#if promotion != nil
# is_promotion = [:get_one_free, :package, :threshold].include?(promotion.keys)
# raise "Invalude promotion passed!"
#end
end
def validate_coupon_name(name)
if @coupons.any? { |item| item.name == name }
raise "Invalide coupon name passed!"
end
end
def validate_coupon_type(type)
#nakraq
end
end
class InvoiceCalc
def initialize(inventory_items, cart_items, used_coupon)
@inventory_items = inventory_items
@cart_items = cart_items
@used_coupon = used_coupon
@per_item_calculations = {}
@promotion_calculations = {}
end
def calculate_per_item
@cart_items.each do |name, amount|
price = @inventory_items.select { |item| item.name == name }[0].price
@per_item_calculations[name] = price*BigDecimal(amount.to_s)
end
@per_item_calculations
end
def calculate_promotion
@cart_items.each do |name, amount|
item = @inventory_items.select { |item| item.name == name }[0]
calculate_one_free(item, amount)
calculate_package(item, amount)
calculate_threshold(item, amount)
end
@promotion_calculations
end
def calculate_coupon(total_price)
return BigDecimal('0.0') if @used_coupon == nil
if @used_coupon.type.keys[0] == :percent
percent = BigDecimal(@used_coupon.type[:percent].to_s)/BigDecimal('100')
total_price*percent
else
return BigDecimal(@used_coupon.type[:amount].to_s)
end
end
def calculate_total
total_per_item = total(@per_item_calculations)
total_promotion = total(@promotion_calculations)
diffrence = total_per_item - total_promotion
coupon_price = calculate_coupon(diffrence)
if diffrence - coupon_price >= BigDecimal('0.0')
{diffrence - coupon_price=> coupon_price}
else
{BigDecimal('0.0') => (diffrence - coupon_price).abs}
end
end
private
def total(hash)
hash.inject(BigDecimal.new('0.0')) do |memo, (name, price)|
memo += price
memo
end
end
def calculate_threshold(item, amount)
return if item.promotion == nil or item.promotion.keys[0] != :threshold
threshold = item.promotion[:threshold]
threshold_percent = BigDecimal(threshold.values[0].to_s)/BigDecimal('100')
diffrence = (item.price*threshold_percent)
threshold_amount = amount - threshold.keys[0]
final_price = diffrence * BigDecimal(threshold_amount.to_s)
@promotion_calculations[item.name] = final_price if threshold_amount>0
end
def calculate_package(item, amount)
return if item.promotion == nil or item.promotion.keys[0] != :package
package = item.promotion[:package]
package_percent = BigDecimal(package.values[0].to_s)/BigDecimal('100')
promotion_price = item.price*BigDecimal(package.keys[0].to_s) * package_percent
package_amount = amount/package.keys[0]
@promotion_calculations[item.name] = promotion_price * BigDecimal(package_amount.to_s)
end
def calculate_one_free(item, amount)
return if item.promotion == nil or item.promotion.keys[0] != :get_one_free
free_count_promotion = item.promotion[:get_one_free]
free_count = amount/free_count_promotion
@promotion_calculations[item.name] = item.price * BigDecimal(free_count.to_s)
end
end
class InvoicePrint
def initialize(inventory_items, cart_items, used_coupon)
@inventory_items = inventory_items
@cart_items = cart_items
@used_coupon = used_coupon
@invoice_calculator = InvoiceCalc.new(inventory_items, cart_items, used_coupon)
@map_string = {1=>'st', 2=>'nd', 3=>'rd'}
end
def print
invoice_string = <<-header
+------------------------------------------------+----------+
| Name qty | price |
+------------------------------------------------+----------+
header
invoice_string << create_body
invoice_string << create_total
end
private
#def price_field(price_string)
# price_string = "|#{''*(10-price_string.size)}#{price_string} |\n"
#end
def create_body
body_string = ""
per_item = @invoice_calculator.calculate_per_item
promotions = @invoice_calculator.calculate_promotion
@cart_items.each do |name, amount|
body_string << create_item_row(name, amount, per_item[name])
body_string << create_promotion_row(promotions, name)
end
body_string << create_coupon_row
end
def create_coupon_row
return "" if @used_coupon == nil
total_coupon = @invoice_calculator.calculate_total
char = @used_coupon.type.keys[0]==:percent ? '%':''
formated_price = "-%0.2f" % total_coupon.values[0]
price_field = "|#{' '*(9-formated_price.size)}#{formated_price} |\n"
text = "Coupon #{@used_coupon.name} - #{@used_coupon.type.values[0]}#{char} off"
"| #{text}#{' '*(46-text.size)} " << price_field
end
def create_total
total_coupon = @invoice_calculator.calculate_total
formate_price = "%0.2f" % total_coupon.keys[0]
price_field = "|#{' '*(9-formate_price.size)}#{formate_price} |"
total_string = <<-TOTAL
+------------------------------------------------+----------+
| TOTAL #{price_field}
TOTAL
total_string << "+------------------------------------------------+----------+\n"
end
def create_promotion_row(promotion_array, name)
return "" if promotion_array[name] == nil
item = @inventory_items.select { |item| item.name == name }[0]
promotion = item.promotion
if promotion.keys[0] == :get_one_free
create_get_one_free_row(promotion[:get_one_free], promotion_array[name])
elsif promotion.keys[0] == :package
create_package_row(promotion[:package], promotion_array[name])
else
create_threshold_row(promotion[:threshold], promotion_array[name])
end
end
def create_item_row(name, amount, price)
used_chars = name.size + amount.to_s.size + 2
name_amount_string = "| #{name}#{' '*(48-used_chars)}#{amount} "
formated_price = "%0.2f" % price
price_field = "|#{' '*(9-formated_price.size)}#{formated_price} |\n"
name_amount_string+price_field
end
def create_get_one_free_row(promotion, price)
formate_price = "-%0.2f" % price
price_field = "|#{' '*(9-formate_price.size)}#{formate_price} |\n"
text = "(buy #{promotion-1}, get 1 free)"
"| #{text}#{' '*(45-text.size)}" << price_field
end
def create_package_row(hash, price)
formated_price = "-%0.2f" % price
price_field = "|#{' '*(9-formated_price.size)}#{formated_price} |\n"
amount = hash.keys[0]
text = "(get #{hash.values[0]}% off for every #{amount})"
package_row = "| #{text}#{' '*(45-text.size)}"
package_row + price_field
end
def create_threshold_row(hash, price)
formated_price = "-%0.2f" % price
price_field = "|#{' '*(9-formated_price.size)}#{formated_price} |\n"
order = @map_string[hash.keys[0]] == nil ? "th" : @map_string[hash.keys[0]]
amount = hash.keys[0].to_s + order
text = "(#{hash.values[0]}% off of every after the #{amount})"
package_row = "| #{text}#{' '*(45-text.size)}"
package_row + price_field
end
end

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

.................F.

Failures:

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

Finished in 0.57461 seconds
19 examples, 1 failure

Failed examples:

rspec /tmp/d20111115-5847-128ivyh/spec.rb:274 # Inventory with an 'amount off' coupon shows the discount in the invoice

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

Петър обнови решението на 07.11.2011 15:25 (преди около 13 години)

+require 'bigdecimal'
+require 'bigdecimal/util'
+
+class Item
+ attr_reader :name, :price, :promotion
+
+ def initialize(name, price, promotion = nil)
+ @name, @price, @promotion = name, BigDecimal(price), promotion
+ end
+
+end
+
+class Coupon
+ attr_reader :name, :type
+
+ def initialize(name, type)
+ @name = name
+ @type = type
+ end
+
+end
+
+class Cart
+ def initialize(inventory_items, inventory_coupons)
+ @inventory_items = inventory_items
+ @inventory_coupons = inventory_coupons
+ @cart_items = Hash.new(0)
+ @used_coupon = nil
+ end
+
+ def add(name, amount = 1)
+ validate_item(name, amount)
+ @cart_items[name] += amount
+ end
+
+ def use(name)
+ validate_coupon(name)
+ @used_coupon = @inventory_coupons.select { |coupon| coupon.name == name }[0]
+ end
+
+ def total
+ inv_test = InvoiceCalc.new(@inventory_items, @cart_items, @used_coupon)
+ inv_test.calculate_per_item
+ inv_test.calculate_promotion
+ inv_test.calculate_total.keys[0]
+ end
+
+ def invoice
+ #do somthing
+ #invoiceCalc = InvoiceCalc.new(@inventory_items, @cart_items, @used_coupon)
+ invoice_print = InvoicePrint.new(@inventory_items, @cart_items, @used_coupon)
+ invoice_print.print
+ end
+
+ private
+
+ def validate_item(name, amount)
+ dont_exist = @inventory_items.all? { |item| item.name != name }
+ amount_negative = amount<=0
+ big_amount = @cart_items[name] + amount > 99
+ raise "Invalide parameters passed!" if dont_exist or amount_negative or big_amount
+ end
+
+ def validate_coupon(coupon_name)
+ exist = @inventory_coupons.any? { |coupon| coupon.name == coupon_name }
+ raise "Invalide coupon is used!" if !exist
+ end
+
+end
+
+class Inventory
+
+ def initialize()
+ @items = []
+ @coupons = []
+ end
+
+ def register(name, price, promotion = nil)
+ validate_name(name)
+ validate_price(BigDecimal(price))
+ validate_promotion(promotion)
+ @items << Item.new(name, price, promotion)
+ end
+
+ def register_coupon(name, type)
+ validate_coupon_name(name)
+ validate_coupon_type(type)
+ @coupons << Coupon.new(name, type)
+ end
+
+
+ def new_cart
+ Cart.new(@items, @coupons)
+ end
+
+ private
+
+ def validate_name(name)
+ name_size = name.size>40
+ dublicate_item = @items.any? { |item| item.name == name }
+ raise "Invalide name passed!" if name_size or dublicate_item
+ end
+
+ def validate_price(price)
+ if price < BigDecimal('0.01') or price > BigDecimal('999.99')
+ raise "Invalide price passed!"
+ end
+ end
+
+ def validate_promotion(promotion)
+ #posle
+ #if promotion != nil
+ # is_promotion = [:get_one_free, :package, :threshold].include?(promotion.keys)
+ # raise "Invalude promotion passed!"
+ #end
+ end
+
+ def validate_coupon_name(name)
+ if @coupons.any? { |item| item.name == name }
+ raise "Invalide coupon name passed!"
+ end
+ end
+
+ def validate_coupon_type(type)
+ #nakraq
+ end
+end
+
+class InvoiceCalc
+ def initialize(inventory_items, cart_items, used_coupon)
+ @inventory_items = inventory_items
+ @cart_items = cart_items
+ @used_coupon = used_coupon
+ @per_item_calculations = {}
+ @promotion_calculations = {}
+ end
+
+ def calculate_per_item
+ @cart_items.each do |name, amount|
+ price = @inventory_items.select { |item| item.name == name }[0].price
+ @per_item_calculations[name] = price*BigDecimal(amount.to_s)
+ end
+ @per_item_calculations
+ end
+
+ def calculate_promotion
+ @cart_items.each do |name, amount|
+ item = @inventory_items.select { |item| item.name == name }[0]
+
+ calculate_one_free(item, amount)
+ calculate_package(item, amount)
+ calculate_threshold(item, amount)
+ end
+ @promotion_calculations
+ end
+
+ def calculate_coupon(total_price)
+ return BigDecimal('0.0') if @used_coupon == nil
+ if @used_coupon.type.keys[0] == :percent
+ percent = BigDecimal(@used_coupon.type[:percent].to_s)/BigDecimal('100')
+ total_price*percent
+ else
+ return BigDecimal(@used_coupon.type[:amount].to_s)
+ end
+ end
+
+ def calculate_total
+ total_per_item = total(@per_item_calculations)
+ total_promotion = total(@promotion_calculations)
+ diffrence = total_per_item - total_promotion
+ coupon_price = calculate_coupon(diffrence)
+
+ if diffrence - coupon_price >= BigDecimal('0.0')
+ {diffrence - coupon_price=> coupon_price}
+ else
+ {BigDecimal('0.0') => (diffrence - coupon_price).abs}
+ end
+ end
+
+ private
+
+
+ def total(hash)
+ hash.inject(BigDecimal.new('0.0')) do |memo, (name, price)|
+ memo += price
+ memo
+ end
+ end
+
+ def calculate_threshold(item, amount)
+ return if item.promotion == nil or item.promotion.keys[0] != :threshold
+ threshold = item.promotion[:threshold]
+ threshold_percent = BigDecimal(threshold.values[0].to_s)/BigDecimal('100')
+ diffrence = (item.price*threshold_percent)
+ threshold_amount = amount - threshold.keys[0]
+ final_price = diffrence * BigDecimal(threshold_amount.to_s)
+ @promotion_calculations[item.name] = final_price if threshold_amount>0
+
+ end
+
+ def calculate_package(item, amount)
+ return if item.promotion == nil or item.promotion.keys[0] != :package
+ package = item.promotion[:package]
+ package_percent = BigDecimal(package.values[0].to_s)/BigDecimal('100')
+ promotion_price = item.price*BigDecimal(package.keys[0].to_s) * package_percent
+ package_amount = amount/package.keys[0]
+ @promotion_calculations[item.name] = promotion_price * BigDecimal(package_amount.to_s)
+ end
+
+ def calculate_one_free(item, amount)
+ return if item.promotion == nil or item.promotion.keys[0] != :get_one_free
+ free_count_promotion = item.promotion[:get_one_free]
+ free_count = amount/free_count_promotion
+ @promotion_calculations[item.name] = item.price * BigDecimal(free_count.to_s)
+ end
+end
+
+class InvoicePrint
+ def initialize(inventory_items, cart_items, used_coupon)
+ @inventory_items = inventory_items
+ @cart_items = cart_items
+ @used_coupon = used_coupon
+ @invoice_calculator = InvoiceCalc.new(inventory_items, cart_items, used_coupon)
+ @map_string = {1=>'st', 2=>'nd', 3=>'rd'}
+ end
+
+ def print
+ invoice_string = <<-header
++------------------------------------------------+----------+
+| Name qty | price |
++------------------------------------------------+----------+
+ header
+ invoice_string << create_body
+ invoice_string << create_total
+ end
+
+ private
+
+ #def price_field(price_string)
+ # price_string = "|#{''*(10-price_string.size)}#{price_string} |\n"
+ #end
+
+ def create_body
+ body_string = ""
+ per_item = @invoice_calculator.calculate_per_item
+ promotions = @invoice_calculator.calculate_promotion
+ @cart_items.each do |name, amount|
+ body_string << create_item_row(name, amount, per_item[name])
+ body_string << create_promotion_row(promotions, name)
+ end
+ body_string << create_coupon_row
+ end
+
+ def create_coupon_row
+ return "" if @used_coupon == nil
+ total_coupon = @invoice_calculator.calculate_total
+ char = @used_coupon.type.keys[0]==:percent ? '%':''
+ formated_price = "-%0.2f" % total_coupon.values[0]
+ price_field = "|#{' '*(9-formated_price.size)}#{formated_price} |\n"
+ text = "Coupon #{@used_coupon.name} - #{@used_coupon.type.values[0]}#{char} off"
+ "| #{text}#{' '*(46-text.size)} " << price_field
+ end
+
+ def create_total
+ total_coupon = @invoice_calculator.calculate_total
+ formate_price = "%0.2f" % total_coupon.keys[0]
+ price_field = "|#{' '*(9-formate_price.size)}#{formate_price} |"
+ total_string = <<-TOTAL
++------------------------------------------------+----------+
+| TOTAL #{price_field}
+ TOTAL
+
+ total_string << "+------------------------------------------------+----------+\n"
+ end
+
+ def create_promotion_row(promotion_array, name)
+ return "" if promotion_array[name] == nil
+ item = @inventory_items.select { |item| item.name == name }[0]
+ promotion = item.promotion
+ if promotion.keys[0] == :get_one_free
+ create_get_one_free_row(promotion[:get_one_free], promotion_array[name])
+ elsif promotion.keys[0] == :package
+ create_package_row(promotion[:package], promotion_array[name])
+ else
+ create_threshold_row(promotion[:threshold], promotion_array[name])
+ end
+ end
+
+ def create_item_row(name, amount, price)
+ used_chars = name.size + amount.to_s.size + 2
+ name_amount_string = "| #{name}#{' '*(48-used_chars)}#{amount} "
+ formated_price = "%0.2f" % price
+ price_field = "|#{' '*(9-formated_price.size)}#{formated_price} |\n"
+ name_amount_string+price_field
+ end
+
+ def create_get_one_free_row(promotion, price)
+ formate_price = "-%0.2f" % price
+ price_field = "|#{' '*(9-formate_price.size)}#{formate_price} |\n"
+ text = "(buy #{promotion-1}, get 1 free)"
+ "| #{text}#{' '*(45-text.size)}" << price_field
+ end
+
+ def create_package_row(hash, price)
+ formated_price = "-%0.2f" % price
+ price_field = "|#{' '*(9-formated_price.size)}#{formated_price} |\n"
+ amount = hash.keys[0]
+ text = "(get #{hash.values[0]}% off for every #{amount})"
+ package_row = "| #{text}#{' '*(45-text.size)}"
+ package_row + price_field
+ end
+
+ def create_threshold_row(hash, price)
+ formated_price = "-%0.2f" % price
+ price_field = "|#{' '*(9-formated_price.size)}#{formated_price} |\n"
+ order = @map_string[hash.keys[0]] == nil ? "th" : @map_string[hash.keys[0]]
+ amount = hash.keys[0].to_s + order
+ text = "(#{hash.values[0]}% off of every after the #{amount})"
+ package_row = "| #{text}#{' '*(45-text.size)}"
+ package_row + price_field
+ end
+
+end