Skip to content

Commit b49a1f3

Browse files
committed
Support additional cases
1. When 4 products are added (one is free) and 5th one is added 2. When 7 producs are added (one is free) and 8th is added as free
1 parent c281497 commit b49a1f3

File tree

3 files changed

+120
-6
lines changed

3 files changed

+120
-6
lines changed

ecommerce/pricing/lib/pricing/discounts.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,10 @@ def exists?
6464
class ThreePlusOneGratis
6565
def apply(product_quantities, product_id, base_price)
6666
product = product_quantities.find { |product_quantity| product_quantity[:product_id] == product_id }
67-
return base_price if product.nil?
68-
product[:quantity] == 3 ? 0 : base_price
67+
return [false, price: base_price] if product.nil?
68+
quantity = product[:quantity] + 1
69+
return [false, base_price] if quantity < 4
70+
return [true, 0] if quantity % 4 == 0
6971
end
7072
end
7173
end

ecommerce/pricing/lib/pricing/offer.rb

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@ def initialize(id)
1414

1515
def add_item(product_id, base_price, promotion = nil)
1616
if promotion
17-
price = promotion.apply(@list.quantities, product_id, base_price)
18-
else
17+
promotion_applies, price = promotion.apply(@list.quantities, product_id, base_price)
18+
end
19+
20+
unless promotion_applies
1921
price = @discounts.inject(Discounts::NoPercentageDiscount.new, :add).apply(base_price)
2022
end
2123

@@ -27,8 +29,8 @@ def add_item(product_id, base_price, promotion = nil)
2729
base_total_value: @list.base_sum + base_price,
2830
total_value: @list.actual_sum + price,
2931
}
30-
31-
data[:applied_promotion] = promotion.class.name if promotion
32+
33+
data[:applied_promotion] = promotion.class.name if promotion_applies
3234

3335
apply PriceItemAdded.new(data:)
3436
end

ecommerce/pricing/test/three_plus_one_test.rb

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,5 +285,115 @@ def test_given_3_plus_one__when_10_percent_discount_for_offer__then_offer_price_
285285
)
286286
) { set_percentage_discount(order_id, 10) }
287287
end
288+
289+
def test_given_three_plus_one_promotion_when_five_items_are_added_then_only_one_item_is_free
290+
product_id = SecureRandom.uuid
291+
set_price(product_id, 20)
292+
order_id = SecureRandom.uuid
293+
stream = "Pricing::Offer$#{order_id}"
294+
295+
3.times { add_item(order_id, product_id, promotion: true) }
296+
297+
assert_events(
298+
stream,
299+
PriceItemAdded.new(
300+
data: {
301+
order_id: order_id,
302+
product_id: product_id,
303+
base_price: 20,
304+
price: 0,
305+
base_total_value: 80,
306+
total_value: 60,
307+
applied_promotion: Pricing::Discounts::ThreePlusOneGratis.to_s
308+
}
309+
),
310+
OrderTotalValueCalculated.new(
311+
data: {
312+
order_id: order_id,
313+
total_amount: 80,
314+
discounted_amount: 60
315+
}
316+
),
317+
PriceItemValueCalculated.new(
318+
data: {
319+
order_id: order_id,
320+
product_id: product_id,
321+
quantity: 4,
322+
amount: 80,
323+
discounted_amount: 60,
324+
}
325+
)
326+
) { add_item(order_id, product_id, promotion: true) }
327+
328+
assert_events(
329+
stream,
330+
PriceItemAdded.new(
331+
data: {
332+
order_id: order_id,
333+
product_id: product_id,
334+
base_price: 20,
335+
price: 20,
336+
base_total_value: 100,
337+
total_value: 80,
338+
}
339+
),
340+
OrderTotalValueCalculated.new(
341+
data: {
342+
order_id: order_id,
343+
total_amount: 100,
344+
discounted_amount: 80
345+
}
346+
),
347+
PriceItemValueCalculated.new(
348+
data: {
349+
order_id: order_id,
350+
product_id: product_id,
351+
quantity: 5,
352+
amount: 100,
353+
discounted_amount: 80,
354+
}
355+
)
356+
) { add_item(order_id, product_id, promotion: true) }
357+
end
358+
359+
def test_given_three_plus_one_promotion_when_eight_items_are_added_then_two_items_are_free
360+
product_id = SecureRandom.uuid
361+
set_price(product_id, 20)
362+
order_id = SecureRandom.uuid
363+
stream = "Pricing::Offer$#{order_id}"
364+
365+
7.times { add_item(order_id, product_id, promotion: true) }
366+
367+
assert_events(
368+
stream,
369+
PriceItemAdded.new(
370+
data: {
371+
order_id: order_id,
372+
product_id: product_id,
373+
base_price: 20,
374+
price: 0,
375+
base_total_value: 160,
376+
total_value: 120,
377+
applied_promotion: Pricing::Discounts::ThreePlusOneGratis.to_s
378+
}
379+
),
380+
OrderTotalValueCalculated.new(
381+
data: {
382+
order_id: order_id,
383+
total_amount: 160,
384+
discounted_amount: 120
385+
}
386+
),
387+
PriceItemValueCalculated.new(
388+
data: {
389+
order_id: order_id,
390+
product_id: product_id,
391+
quantity: 8,
392+
amount: 160,
393+
discounted_amount: 120,
394+
}
395+
)
396+
) { add_item(order_id, product_id, promotion: true) }
397+
end
288398
end
289399
end

0 commit comments

Comments
 (0)