Skip to content

Commit

Permalink
Add discount priority indicating discount apply order
Browse files Browse the repository at this point in the history
  • Loading branch information
developertogo committed Aug 24, 2019
1 parent d8b0deb commit e03647f
Show file tree
Hide file tree
Showing 12 changed files with 88 additions and 70 deletions.
4 changes: 2 additions & 2 deletions lib/basket.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def show
end
end
puts '------------------------------------------'
output_total = ('$' + total.round(2).to_s).rjust(8)
puts " \t\t \t\t #{output_total}"
output_format = format('$%.2f', total).rjust(8)
puts " \t\t \t\t #{output_format}"
end
end
2 changes: 1 addition & 1 deletion lib/checkout.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def show

def total
@items.each(&:reset)
@sales_rules.each { |rule| rule.apply(@items) }
@sales_rules.sort_by(&:priority).each { |rule| rule.apply(@items) }
@basket.total = @items.inject(0.0) { |total, item| total + item.price }.round(2)
end

Expand Down
3 changes: 2 additions & 1 deletion lib/discounts/base_discount.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
class BaseDiscount
attr_reader :discount_type
attr_reader :priority

@discount_type = ''
@priority = 0
@decription = ''
@min_items = 1
@limit = nil
Expand Down
3 changes: 2 additions & 1 deletion lib/discounts/buy_this_get_that_percent_discount.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
require_relative '../discounts/base_discount'

class BuyThisGetThatPercentDiscount < BaseDiscount
def initialize(discount_type:, description: '', this_code:, this_min_items: 1, that_code:, that_max_items: 1, percent_discount:, limit: nil)
def initialize(discount_type:, description: '', priority:, this_code:, this_min_items: 1, that_code:, that_max_items: 1, percent_discount:, limit: nil)
@discount_type = discount_type
@description = description
@priority = priority
@this_code = this_code
@this_min_items = this_min_items
@that_code = that_code
Expand Down
9 changes: 6 additions & 3 deletions lib/discounts/item_discount.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
require_relative '../discounts/base_discount'

class ItemDiscount < BaseDiscount
def initialize(discount_type:, description: '', code:, min_items:, discount:, limit: nil)
def initialize(discount_type:, description: '', priority:, code:, min_items:, discount:, limit: nil)
@discount_type = discount_type
@description = description
@priority = priority
@code = code
@min_items = min_items
@discount = discount
Expand All @@ -18,13 +19,15 @@ def apply(items)
private

def apply_discount(orders)
count = 0
discount_amount = @discount / @min_items
orders.each_with_index do |order, i|
next unless i < @min_items && order.discount_type.empty?
orders.each do |order|
next unless count < @min_items && order.discount_type.empty?

order.discount_type = @discount_type
order.discount_amount = discount_amount
order.price -= discount_amount
count += 1
end
orders
end
Expand Down
3 changes: 2 additions & 1 deletion lib/discounts/two_for_one_discount.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
require_relative '../discounts/base_discount'

class TwoForOneDiscount < BaseDiscount
def initialize(discount_type:, description: '', code:, limit: nil)
def initialize(discount_type:, description: '', priority:, code:, limit: nil)
@discount_type = discount_type
@description = description
@priority = priority
@code = code
@min_items = 2
@limit = limit
Expand Down
99 changes: 55 additions & 44 deletions spec/checkout_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,16 @@
describe Checkout do
subject(:checkout) do
sales_rules = [
TwoForOneDiscount.new(discount_type: 'BOGO', code: 'CF1'),
ItemDiscount.new(discount_type: 'APPL', code: 'AP1', min_items: 3, discount: 4.50),
BuyThisGetThatPercentDiscount.new(discount_type: 'CHMK', this_code: 'CH1', this_min_items: 1,
that_code: 'MK1', that_max_items: 1, percent_discount: 100, limit: 1),
BuyThisGetThatPercentDiscount.new(discount_type: 'APOM', this_code: 'OM1', this_min_items: 1,
that_code: 'AP1', that_max_items: 1, percent_discount: 50)
TwoForOneDiscount.new(discount_type: 'BOGO', priority: 3, code: 'CF1'),
ItemDiscount.new(discount_type: 'APPL', priority: 2, code: 'AP1', min_items: 3, discount: 4.50),
BuyThisGetThatPercentDiscount.new(discount_type: 'CHMK', priority: 4,
this_code: 'CH1', this_min_items: 1,
that_code: 'MK1', that_max_items: 1,
percent_discount: 100, limit: 1),
BuyThisGetThatPercentDiscount.new(discount_type: 'APOM', priority: 1,
this_code: 'OM1', this_min_items: 1,
that_code: 'AP1', that_max_items: 1,
percent_discount: 50)
]
products = [
Product.new('CH1', 'Chai', 3.11),
Expand Down Expand Up @@ -53,20 +57,6 @@
end

context 'when basket is not empty and no discounts' do
subject(:checkout) do
sales_rules = []
products = [
Product.new('CH1', 'Chai', 3.11),
Product.new('AP1', 'Apples', 6.00),
Product.new('CF1', 'Coffee', 11.23),
Product.new('MK1', 'Milk', 4.75),
Product.new('OM1', 'Oatmeal', 3.69)
]
store = Store.new(sales_rules, products)

Checkout.new(store)
end

it 'returns a nonzero total' do
checkout.scan('CH1')
checkout.scan('AP1')
Expand All @@ -76,8 +66,7 @@
items = [
Item.new('CH1', 3.11),
Item.new('AP1', 6.00),
Item.new('CF1', 11.23),
Item.new('MK1', 4.75)
Item.new('CF1', 11.23)
]
total = items.inject(0.0) { |sum, item| sum + item.price }

Expand All @@ -86,27 +75,6 @@
end

context 'when basket has sale items' do
subject(:checkout) do
sales_rules = [
TwoForOneDiscount.new(discount_type: 'BOGO', code: 'CF1'),
ItemDiscount.new(discount_type: 'APPL', code: 'AP1', min_items: 3, discount: 4.50),
BuyThisGetThatPercentDiscount.new(discount_type: 'CHMK', this_code: 'CH1', this_min_items: 1,
that_code: 'MK1', that_max_items: 1, percent_discount: 100, limit: 1),
BuyThisGetThatPercentDiscount.new(discount_type: 'APOM', this_code: 'OM1', this_min_items: 1,
that_code: 'AP1', that_max_items: 1, percent_discount: 50)
]
products = [
Product.new('CH1', 'Chai', 3.11),
Product.new('AP1', 'Apples', 6.00),
Product.new('CF1', 'Coffee', 11.23),
Product.new('MK1', 'Milk', 4.75),
Product.new('OM1', 'Oatmeal', 3.69)
]
store = Store.new(sales_rules, products)

Checkout.new(store)
end

it 'applies buy chai get milk free discount' do
checkout.scan('CH1')
checkout.scan('AP1')
Expand Down Expand Up @@ -159,7 +127,26 @@
checkout.show
end

it 'applies 3+ apples get $4.50 discount' do
it 'applies one get one free discount' do
checkout.scan('CF1')
checkout.scan('CH1')
checkout.scan('CH1')
checkout.scan('CF1')
checkout.scan('CH1')
checkout.scan('CF1')
checkout.scan('CH1')
checkout.scan('CF1')
checkout.scan('CH1')
checkout.scan('CF1')
checkout.scan('CH1')
checkout.scan('CF1')
checkout.scan('CF1')
checkout.show

expect(checkout.total).to eq(63.58)
end

it 'applies 3 apples get $4.50 discount' do
checkout.scan('AP1')
checkout.scan('AP1')
checkout.scan('CH1')
Expand All @@ -179,6 +166,18 @@
checkout.show
end

it 'applies 3 or more (5) apples get $4.50 discount' do
checkout.scan('AP1')
checkout.scan('AP1')
checkout.scan('CH1')
checkout.scan('AP1')
checkout.scan('AP1')
checkout.scan('AP1')
checkout.show

expect(checkout.total).to eq(28.61)
end

it 'applies buy oakmeal get 50% off apple discount' do
checkout.scan('OM1')
checkout.scan('AP1')
Expand All @@ -199,6 +198,18 @@

checkout.show
end

it 'applies both 3+ apples get $4.50 discount and buy oakmeal get 50% off apple discount' do
checkout.scan('AP1')
checkout.scan('AP1')
checkout.scan('CH1')
checkout.scan('AP1')
checkout.scan('OM1')
checkout.scan('AP1')
checkout.show

expect(checkout.total).to eq(23.30)
end
end
end

Expand Down
6 changes: 3 additions & 3 deletions spec/discounts/buy_this_get_that_percent_discount_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

describe BuyThisGetThatPercentDiscount do
subject(:buy_this_get_that_percent_discount) do
BuyThisGetThatPercentDiscount.new(discount_type: 'CHMK', this_code: 'CH1',
BuyThisGetThatPercentDiscount.new(discount_type: 'CHMK', priority: 4, this_code: 'CH1',
that_code: 'MK1', percent_discount: 100, limit: 1)
end

Expand Down Expand Up @@ -56,7 +56,7 @@
describe '#apply_discount (private method)' do
context 'when min this items and max that items are met and unlimited' do
subject(:buy_this_get_that_percent_discount) do
BuyThisGetThatPercentDiscount.new(discount_type: 'APOM', this_code: 'OM1',
BuyThisGetThatPercentDiscount.new(discount_type: 'APOM', priority: 4, this_code: 'OM1',
that_code: 'AP1', percent_discount: 50)
end

Expand Down Expand Up @@ -187,7 +187,7 @@

context 'when that item is 50% off unlimited offer' do
subject(:buy_this_get_that_percent_discount) do
BuyThisGetThatPercentDiscount.new(discount_type: 'APOM', this_code: 'OM1',
BuyThisGetThatPercentDiscount.new(discount_type: 'APOM', priority: 4, this_code: 'OM1',
that_code: 'AP1', percent_discount: 50)
end

Expand Down
2 changes: 1 addition & 1 deletion spec/discounts/item_discount_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
require_relative '../../lib/item'

describe ItemDiscount do
subject(:item_discount) { ItemDiscount.new(discount_type: 'APPL', code: 'AP1', min_items: 3, discount: 4.50) }
subject(:item_discount) { ItemDiscount.new(discount_type: 'APPL', priority: 2, code: 'AP1', min_items: 3, discount: 4.50) }

describe '#apply_discount? (private)' do
context 'when min items is met' do
Expand Down
4 changes: 2 additions & 2 deletions spec/discounts/two_for_one_discount_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
require_relative '../../lib/item'

describe TwoForOneDiscount do
subject(:two_for_one_discount) { TwoForOneDiscount.new(discount_type: 'BOGO', code: 'CF1') }
subject(:two_for_one_discount) { TwoForOneDiscount.new(discount_type: 'BOGO', priority: 3, code: 'CF1') }

describe '#apply_discount? (private)' do
context 'when min items is met' do
Expand Down Expand Up @@ -65,7 +65,7 @@

context 'when min items is met and limit one offer' do
let(:limit) { 1 }
subject(:two_for_one_discount) { TwoForOneDiscount.new(discount_type: 'BOGO', code: 'CF1', limit: limit) }
subject(:two_for_one_discount) { TwoForOneDiscount.new(discount_type: 'BOGO', priority: 3, code: 'CF1', limit: limit) }

it 'returns just the 1st order with 2nd item free' do
orders = two_for_one_discount.send(:apply_discount, @orders)
Expand Down
13 changes: 7 additions & 6 deletions spec/store_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@
describe Store do
subject(:store) do
sales_rules = [
TwoForOneDiscount.new(discount_type: 'BOGO', code: 'CF1'),
ItemDiscount.new(discount_type: 'APPL', code: 'AP1', min_items: 3, discount: 4.50),
BuyThisGetThatPercentDiscount.new(discount_type: 'CHMK',
TwoForOneDiscount.new(discount_type: 'BOGO', priority: 3, code: 'CF1'),
ItemDiscount.new(discount_type: 'APPL', priority: 2, code: 'AP1', min_items: 3, discount: 4.50),
BuyThisGetThatPercentDiscount.new(discount_type: 'CHMK', priority: 4,
this_code: 'CH1', this_min_items: 1,
that_code: 'MK1', that_max_items: 1,
percent_discount: 100, limit: 1),
BuyThisGetThatPercentDiscount.new(discount_type: 'APOM', this_code: 'OM1',
this_min_items: 1, that_code: 'AP1',
that_max_items: 1, percent_discount: 50)
BuyThisGetThatPercentDiscount.new(discount_type: 'APOM', priority: 1,
this_code: 'OM1', this_min_items: 1,
that_code: 'AP1', that_max_items: 1,
percent_discount: 50)
]
products = [
Product.new('CH1', 'Chai', 3.11),
Expand Down
10 changes: 5 additions & 5 deletions yacs_register.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ def newline
end

sales_rules = [
TwoForOneDiscount.new(discount_type: 'BOGO', code: 'CF1',
TwoForOneDiscount.new(discount_type: 'BOGO', code: 'CF1', priority: 3,
description: 'Buy-One-Get-One-Free Special on Coffee. (Unlimited)'),
ItemDiscount.new(discount_type: 'APPL', code: 'AP1', min_items: 3, discount: 4.50,
ItemDiscount.new(discount_type: 'APPL', code: 'AP1', min_items: 3, discount: 4.50, priority: 2,
description: 'If you buy 3 or more bags of Apples, the price drops to $4.50'),
BuyThisGetThatPercentDiscount.new(discount_type: 'CHMK', this_code: 'CH1', this_min_items: 1,
that_code: 'MK1', that_max_items: 1, percent_discount: 100, limit: 1,
BuyThisGetThatPercentDiscount.new(discount_type: 'CHMK', this_code: 'CH1', this_min_items: 1, that_code: 'MK1',
that_max_items: 1, percent_discount: 100, limit: 1, priority: 4,
description: 'Purchase a box of Chai and get milk free. (Limit 1)'),
BuyThisGetThatPercentDiscount.new(discount_type: 'APOM', this_code: 'OM1', this_min_items: 1,
that_code: 'AP1', that_max_items: 1, percent_discount: 50,
that_code: 'AP1', that_max_items: 1, percent_discount: 50, priority: 1,
description: 'Purchase a bag of Oatmeal and get 50% off a bag of Apples')
]
products = [
Expand Down

0 comments on commit e03647f

Please sign in to comment.