Created
August 20, 2014 15:27
-
-
Save JakubOboza/af1f8b90f9de7f472dcb to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'minitest/autorun' | |
# Money are in floats for simplicity, it should be bigint | |
# Promotions are prioritized in order [A,B] => A rule is applied first, B rule is applied second | |
class Item | |
attr_accessor :name, :price, :product_code | |
def initialize(name, price, product_code) | |
@name = name | |
@price = price | |
@product_code = product_code | |
end | |
end | |
class OverLimitPromoRule | |
attr_reader :limit | |
def initialize(limit = 60) | |
@limit = limit | |
end | |
attr_accessor :cart | |
def discount(total, cart) | |
@cart = cart | |
if total > @limit | |
return total * 0.1 | |
end | |
end | |
end | |
class TwoOrMorePromoRule | |
attr_accessor :cart, :product_code, :unit_discount | |
def initialize(product_code, unit_discount) | |
@product_code = product_code | |
@unit_discount = unit_discount | |
end | |
def discount(total, cart) | |
promo_items = cart.select {|item| item.product_code == @product_code } | |
if promo_items.size > 1 | |
return promo_items.size * @unit_discount | |
end | |
end | |
end | |
class Checkout | |
attr_reader :promo_rules, :cart | |
def initialize(promo_rules) | |
@cart = [] | |
@promo_rules = promo_rules | |
end | |
def scan(item) | |
@cart << item | |
end | |
def total | |
raw_total = @cart.inject(0){|acc, item| acc += item.price } | |
total = @promo_rules.inject(raw_total){|total, rule| total -= rule.discount(total, @cart).to_f }.round(2) | |
end | |
end | |
describe Item do | |
it "has name, price and product code" do | |
[:name, :price, :product_code].each do |field| | |
Item.new("Travel Card Holder", 9.25, "001" ).must_respond_to field | |
end | |
end | |
end | |
describe OverLimitPromoRule do | |
it "can produce discount for a cart" do | |
cart = [ | |
Item.new("Travel Card Holder", 40.0, "001"), | |
Item.new("Travel Card Holder Holder", 60.0, "002") | |
] | |
OverLimitPromoRule.new.discount(100, cart).must_equal 10.0 | |
end | |
it "don't give any discount if you are below limit" do | |
cart = [ | |
Item.new("Travel Card Holder", 4.0, "001"), | |
Item.new("Travel Card Holder Holder", 6.0, "002") | |
] | |
OverLimitPromoRule.new.discount(10, cart).must_be_nil | |
end | |
end | |
describe TwoOrMorePromoRule do | |
it "can produce discount for a cart" do | |
cart = [ | |
Item.new("Travel Card Holder", 9.25, "001"), | |
Item.new("Travel Card Holder", 9.25, "001"), | |
Item.new("Travel Card Holder Holder", 60.0, "002") | |
] | |
TwoOrMorePromoRule.new("001", 0.75).discount(100, cart).must_equal 1.50 | |
end | |
it "don't give any discount if you are below limit" do | |
cart = [ | |
Item.new("Travel Card Holder", 4.0, "001"), | |
Item.new("Travel Card Holder Holder", 6.0, "002") | |
] | |
TwoOrMorePromoRule.new("001", 0.75).discount(100, cart).must_be_nil | |
end | |
end | |
describe Checkout do | |
before do | |
@promotional_rules = [ | |
TwoOrMorePromoRule.new("001", 0.75), | |
OverLimitPromoRule.new | |
] | |
@item1 = Item.new("Travel Card Holder", 9.25, "001") | |
@item2 = Item.new("Personalised cufflinks", 45.00, "002") | |
@item3 = Item.new("Kids T-shirt", 19.95, "003") | |
@co = Checkout.new(@promotional_rules) | |
end | |
describe "it can checkout!" do | |
it "must not explode and give you back value" do | |
@co.scan(@item1) | |
@co.scan(@item2) | |
price = @co.total | |
price.wont_be_nil | |
end | |
it "must give back for 66.78 basket 001,002,003" do | |
@co.scan(@item1) | |
@co.scan(@item2) | |
@co.scan(@item3) | |
@co.total.must_equal 66.78 | |
end | |
it "must give back for 36.95 basket 001,003,001" do | |
@co.scan(@item1) | |
@co.scan(@item3) | |
@co.scan(@item1) | |
@co.total.must_equal 36.95 | |
end | |
it "must give back for 73.76 basket 001,002,001,003" do | |
@co.scan(@item1) | |
@co.scan(@item2) | |
@co.scan(@item1) | |
@co.scan(@item3) | |
@co.total.must_equal 73.76 | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment