Skip to content

Commit 2adc0f0

Browse files
committed
Refactor
1 parent 929f6f4 commit 2adc0f0

20 files changed

+255
-124
lines changed

ecommerce/pricing/lib/pricing.rb

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,7 @@ def call(event_store, command_bus)
115115
PercentageDiscountReset,
116116
PercentageDiscountChanged,
117117
ProductMadeFreeForOrder,
118-
FreeProductRemovedFromOrder,
119-
TimePromotionDiscountSet,
120-
TimePromotionDiscountReset
118+
FreeProductRemovedFromOrder
121119
])
122120
event_store.subscribe(CalculateOrderTotalSubAmountsValue, to: [
123121
PriceItemAdded,
@@ -126,9 +124,7 @@ def call(event_store, command_bus)
126124
PercentageDiscountReset,
127125
PercentageDiscountChanged,
128126
ProductMadeFreeForOrder,
129-
FreeProductRemovedFromOrder,
130-
TimePromotionDiscountSet,
131-
TimePromotionDiscountReset
127+
FreeProductRemovedFromOrder
132128
])
133129
end
134130
end

ecommerce/pricing/lib/pricing/apply_time_promotion.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ class ApplyTimePromotion
33
def call(event)
44
discount = PromotionsCalendar.new(event_store).current_time_promotions_discount
55

6-
if discount.exists?
7-
command_bus.(SetTimePromotionDiscount.new(order_id: event.data.fetch(:order_id), amount: discount.value))
6+
if discount
7+
command_bus.(SetTimePromotionDiscount.new(order_id: event.data.fetch(:order_id), amount: discount))
88
else
99
command_bus.(ResetTimePromotionDiscount.new(order_id: event.data.fetch(:order_id)))
1010
end
11+
12+
rescue NotPossibleToAssignDiscountTwice, NotPossibleToResetWithoutDiscount
1113
end
1214

1315
private

ecommerce/pricing/lib/pricing/discounts.rb

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,10 @@
11
module Pricing
22
module Discounts
3-
class UnacceptableDiscountRange < StandardError
4-
end
3+
GENERAL_DISCOUNT = "general_discount"
4+
TIME_PROMOTION_DISCOUNT = "time_promotion_discount"
55

6-
class Discount
7-
def self.build(discount)
8-
if discount.zero?
9-
NoPercentageDiscount.new
10-
else
11-
PercentageDiscount.new(discount)
12-
end
13-
end
6+
class UnacceptableDiscountRange < StandardError
147
end
15-
168
class PercentageDiscount
179
attr_reader :value
1810

@@ -37,10 +29,6 @@ def ==(other)
3729
value == other.value
3830
end
3931

40-
def exists?
41-
true
42-
end
43-
4432
private
4533

4634
def discount(total)
@@ -64,10 +52,6 @@ def value
6452
def ==(other)
6553
value == other.value
6654
end
67-
68-
def exists?
69-
false
70-
end
7155
end
7256
end
7357
end

ecommerce/pricing/lib/pricing/events.rb

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,10 @@ class PriceItemValueCalculated < Infra::Event
3434

3535
class PercentageDiscountSet < Infra::Event
3636
attribute :order_id, Infra::Types::UUID
37+
attribute :type, Infra::Types::String
3738
attribute :amount, Infra::Types::PercentageDiscount
3839
end
3940

40-
class TimePromotionDiscountSet < Infra::Event
41-
attribute :order_id, Infra::Types::UUID
42-
attribute :amount, Infra::Types::PercentageDiscount
43-
end
44-
45-
class TimePromotionDiscountReset < Infra::Event
46-
attribute :order_id, Infra::Types::UUID
47-
end
48-
4941
class PriceItemAdded < Infra::Event
5042
attribute :order_id, Infra::Types::UUID
5143
attribute :product_id, Infra::Types::UUID
@@ -58,10 +50,12 @@ class PriceItemRemoved < Infra::Event
5850

5951
class PercentageDiscountReset < Infra::Event
6052
attribute :order_id, Infra::Types::UUID
53+
attribute :type, Infra::Types::String
6154
end
6255

6356
class PercentageDiscountChanged < Infra::Event
6457
attribute :order_id, Infra::Types::UUID
58+
attribute :type, Infra::Types::String
6559
attribute :amount, Infra::Types::Price
6660
end
6761

ecommerce/pricing/lib/pricing/offer.rb

Lines changed: 21 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ class Offer
55
def initialize(id)
66
@id = id
77
@list = List.new
8-
@discount = Discounts::NoPercentageDiscount.new
9-
@time_promotion_discount = Discounts::NoPercentageDiscount.new
8+
@discounts = {}
109
end
1110

1211
def add_item(product_id)
@@ -27,50 +26,34 @@ def remove_item(product_id)
2726
)
2827
end
2928

30-
def apply_discount(discount)
31-
raise NotPossibleToAssignDiscountTwice if @discount.exists?
29+
def apply_discount(type, discount)
30+
raise NotPossibleToAssignDiscountTwice if @discounts.include?(type)
3231
apply PercentageDiscountSet.new(
3332
data: {
3433
order_id: @id,
34+
type: type,
3535
amount: discount.value
3636
}
3737
)
3838
end
3939

40-
def apply_time_promotion_discount(time_promotion)
41-
return if time_promotion == @time_promotion_discount
42-
apply TimePromotionDiscountSet.new(
43-
data: {
44-
order_id: @id,
45-
amount: time_promotion.value
46-
}
47-
)
48-
end
49-
50-
def reset_time_promotion_discount
51-
return unless @time_promotion_discount.exists?
52-
apply TimePromotionDiscountReset.new(
53-
data: {
54-
order_id: @id
55-
}
56-
)
57-
end
58-
59-
def change_discount(discount)
60-
raise NotPossibleToChangeDiscount unless @discount.exists?
40+
def change_discount(type, discount)
41+
raise NotPossibleToChangeDiscount unless @discounts.include?(type)
6142
apply PercentageDiscountChanged.new(
6243
data: {
6344
order_id: @id,
45+
type: type,
6446
amount: discount.value
6547
}
6648
)
6749
end
6850

69-
def reset_discount
70-
raise NotPossibleToResetWithoutDiscount unless @discount.exists?
51+
def reset_discount(type)
52+
raise NotPossibleToResetWithoutDiscount unless @discounts.include?(type)
7153
apply PercentageDiscountReset.new(
7254
data: {
73-
order_id: @id
55+
order_id: @id,
56+
type: type
7457
}
7558
)
7659
end
@@ -97,22 +80,22 @@ def remove_free_product(order_id, product_id)
9780

9881
def calculate_total_value(pricing_catalog)
9982
total_value = @list.base_sum(pricing_catalog)
83+
discounted_value = @discounts.values.inject(Discounts::NoPercentageDiscount.new, :add).apply(total_value)
10084

101-
discounted_value = @discount.add(@time_promotion_discount).apply(total_value)
10285
apply(
10386
OrderTotalValueCalculated.new(
10487
data: {
10588
order_id: @id,
10689
total_amount: total_value,
107-
discounted_amount: discounted_value
90+
discounted_amount: discounted_value || total_value
10891
}
10992
)
11093
)
11194
end
11295

11396
def calculate_sub_amounts(pricing_catalog)
11497
sub_amounts_total = @list.sub_amounts_total(pricing_catalog)
115-
sub_discounts = calculate_total_sub_discounts(pricing_catalog, @time_promotion_discount)
98+
sub_discounts = calculate_total_sub_discounts(pricing_catalog)
11699

117100
products = @list.products
118101
quantities = @list.quantities
@@ -158,23 +141,15 @@ def use_coupon(coupon_id, discount)
158141
end
159142

160143
on PercentageDiscountSet do |event|
161-
@discount = Discounts::PercentageDiscount.new(event.data.fetch(:amount))
144+
@discounts[event.data.fetch(:type)] = Discounts::PercentageDiscount.new(event.data.fetch(:amount))
162145
end
163146

164147
on PercentageDiscountChanged do |event|
165-
@discount = Discounts::PercentageDiscount.new(event.data.fetch(:amount))
166-
end
167-
168-
on TimePromotionDiscountSet do |event|
169-
@time_promotion_discount = Discounts::PercentageDiscount.new(event.data.fetch(:amount))
170-
end
171-
172-
on TimePromotionDiscountReset do |event|
173-
@time_promotion_discount = Discounts::NoPercentageDiscount.new
148+
@discounts[event.data.fetch(:type)] = Discounts::PercentageDiscount.new(event.data.fetch(:amount))
174149
end
175150

176151
on PercentageDiscountReset do |event|
177-
@discount = Discounts::NoPercentageDiscount.new
152+
@discounts.delete(event.data.fetch(:type))
178153
end
179154

180155
on ProductMadeFreeForOrder do |event|
@@ -185,8 +160,8 @@ def use_coupon(coupon_id, discount)
185160
@list.replace(FreeProduct, Product, event.data.fetch(:product_id))
186161
end
187162

188-
def calculate_total_sub_discounts(pricing_catalog, time_promotions_discount)
189-
@list.sub_discounts(pricing_catalog, time_promotions_discount, @discount)
163+
def calculate_total_sub_discounts(pricing_catalog)
164+
@list.sub_discounts(pricing_catalog, @discounts)
190165
end
191166

192167
on CouponUsed do |event|
@@ -237,10 +212,10 @@ def sub_amounts_total(pricing_catalog)
237212
@products_quantities.map { |product, quantity| quantity * pricing_catalog.price_for(product) }
238213
end
239214

240-
def sub_discounts(pricing_catalog, time_promotions_discount, discount)
215+
def sub_discounts(pricing_catalog, discounts)
241216
@products_quantities.map do |product, quantity|
242217
catalog_price_for_single = pricing_catalog.price_for(product)
243-
with_total_discount_single = discount.add(time_promotions_discount).apply(catalog_price_for_single)
218+
with_total_discount_single = discounts.values.inject(Discounts::NoPercentageDiscount.new, :add).apply(catalog_price_for_single)
244219
quantity * (catalog_price_for_single - with_total_discount_single)
245220
end
246221
end

ecommerce/pricing/lib/pricing/promotions_calendar.rb

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@ def initialize(event_store)
55
end
66

77
def current_time_promotions_discount
8-
Discounts::Discount.build(
9-
PromotionsStrategy.biggest_for_client(all_promotions)
10-
)
8+
PromotionsStrategy.biggest_for_client(all_promotions)
119
end
1210

1311
private
@@ -23,7 +21,7 @@ class PromotionsStrategy
2321
def self.biggest_for_client(promotions)
2422
promotions
2523
.filter { |promotion| promotion.running?(Time.current) }
26-
.map { |promotion| promotion.discount }.max || 0
24+
.map { |promotion| promotion.discount }.max
2725
end
2826
end
2927

ecommerce/pricing/lib/pricing/services.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def initialize(event_store)
2121

2222
def call(cmd)
2323
@repository.with_aggregate(Offer, cmd.aggregate_id) do |order|
24-
order.apply_discount(Discounts::PercentageDiscount.new(cmd.amount))
24+
order.apply_discount(Discounts::GENERAL_DISCOUNT, Discounts::PercentageDiscount.new(cmd.amount))
2525
end
2626
end
2727
end
@@ -33,7 +33,7 @@ def initialize(event_store)
3333

3434
def call(cmd)
3535
@repository.with_aggregate(Offer, cmd.aggregate_id) do |order|
36-
order.reset_discount
36+
order.reset_discount(Discounts::GENERAL_DISCOUNT)
3737
end
3838
end
3939
end
@@ -45,7 +45,7 @@ def initialize(event_store)
4545

4646
def call(cmd)
4747
@repository.with_aggregate(Offer, cmd.aggregate_id) do |order|
48-
order.change_discount(Discounts::PercentageDiscount.new(cmd.amount))
48+
order.change_discount(Discounts::GENERAL_DISCOUNT, Discounts::PercentageDiscount.new(cmd.amount))
4949
end
5050
end
5151
end
@@ -57,7 +57,7 @@ def initialize(event_store)
5757

5858
def call(cmd)
5959
@repository.with_aggregate(Offer, cmd.aggregate_id) do |order|
60-
order.apply_time_promotion_discount(Discounts::PercentageDiscount.new(cmd.amount))
60+
order.apply_discount(Discounts::TIME_PROMOTION_DISCOUNT, Discounts::PercentageDiscount.new(cmd.amount))
6161
end
6262
end
6363
end
@@ -69,7 +69,7 @@ def initialize(event_store)
6969

7070
def call(cmd)
7171
@repository.with_aggregate(Offer, cmd.aggregate_id) do |order|
72-
order.reset_time_promotion_discount
72+
order.reset_discount(Discounts::TIME_PROMOTION_DISCOUNT)
7373
end
7474
end
7575
end

ecommerce/pricing/test/apply_time_promotion_test.rb

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,21 @@ def test_applies_biggest_time_promotion_discount
1212
create_active_time_promotion(50)
1313
create_active_time_promotion(30)
1414

15-
assert_events_contain(stream_name(order_id), time_promotion_discount_set_event(order_id, 50)) do
16-
Pricing::ApplyTimePromotion.new.call(item_added_to_basket_event(order_id, product_id))
15+
assert_events_contain(stream_name(order_id), percentage_discount_set_event(order_id, 50)) do
16+
Pricing::ApplyTimePromotion.new.call(item_added_to_basket_event(order_id, product_id))
1717
end
1818
end
1919

2020
def test_resets_time_promotion_discount
2121
order_id = SecureRandom.uuid
2222
product_id = SecureRandom.uuid
23+
create_active_time_promotion(50)
2324
set_time_promotion_discount(order_id, 50)
2425

25-
assert_events_contain(stream_name(order_id), time_promotion_discount_reset_event(order_id)) do
26+
Timecop.travel(1.minute.from_now) do
27+
assert_events_contain(stream_name(order_id), percentage_discount_reset_event(order_id)) do
2628
Pricing::ApplyTimePromotion.new.call(item_added_to_basket_event(order_id, product_id))
29+
end
2730
end
2831
end
2932

@@ -63,22 +66,24 @@ def item_added_to_basket_event(order_id, product_id)
6366
end
6467

6568
def set_time_promotion_discount(order_id, discount)
66-
run_command(SetTimePromotionDiscount.new(order_id: order_id, amount: 50))
69+
run_command(SetTimePromotionDiscount.new(order_id: order_id, amount: discount))
6770
end
6871

69-
def time_promotion_discount_set_event(order_id, amount)
70-
TimePromotionDiscountSet.new(
72+
def percentage_discount_set_event(order_id, amount)
73+
PercentageDiscountSet.new(
7174
data: {
7275
order_id: order_id,
76+
type: Pricing::Discounts::TIME_PROMOTION_DISCOUNT,
7377
amount: amount
7478
}
7579
)
7680
end
7781

78-
def time_promotion_discount_reset_event(order_id)
79-
TimePromotionDiscountReset.new(
82+
def percentage_discount_reset_event(order_id)
83+
PercentageDiscountReset.new(
8084
data: {
81-
order_id: order_id
85+
order_id: order_id,
86+
type: Pricing::Discounts::TIME_PROMOTION_DISCOUNT
8287
}
8388
)
8489
end

ecommerce/pricing/test/discounts_test.rb

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,6 @@ def test_is_not_equal_to_another_discount
9191

9292
refute_equal(first_discount, second_discount)
9393
end
94-
95-
def test_exists_returns_false
96-
assert_equal false, NoPercentageDiscount.new.exists?
97-
end
9894
end
9995
end
10096
end

0 commit comments

Comments
 (0)