Skip to content

Commit

Permalink
Display time promotion on order page
Browse files Browse the repository at this point in the history
  • Loading branch information
marlena-b committed Oct 6, 2024
1 parent 9df0c40 commit 45fd881
Show file tree
Hide file tree
Showing 20 changed files with 486 additions and 138 deletions.
26 changes: 24 additions & 2 deletions ecommerce/pricing/lib/pricing.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
require_relative "pricing/promotions_calendar"
require_relative "pricing/calculate_order_sub_amounts_value"
require_relative "pricing/calculate_order_total_value"
require_relative "pricing/apply_time_promotion"

module Pricing
def self.command_bus=(value)
Expand Down Expand Up @@ -90,7 +91,15 @@ def call(event_store, command_bus)
UseCoupon,
UseCouponHandler.new(event_store)
)
event_store.subscribe(CalculateOrderTotalValue, to: [
command_bus.register(
SetTimePromotionDiscount,
SetTimePromotionDiscountHandler.new(event_store)
)
command_bus.register(
ResetTimePromotionDiscount,
ResetTimePromotionDiscountHandler.new(event_store)
)
event_store.subscribe(ApplyTimePromotion, to: [
PriceItemAdded,
PriceItemRemoved,
PercentageDiscountSet,
Expand All @@ -99,14 +108,27 @@ def call(event_store, command_bus)
ProductMadeFreeForOrder,
FreeProductRemovedFromOrder
])
event_store.subscribe(CalculateOrderTotalValue, to: [
PriceItemAdded,
PriceItemRemoved,
PercentageDiscountSet,
PercentageDiscountReset,
PercentageDiscountChanged,
ProductMadeFreeForOrder,
FreeProductRemovedFromOrder,
TimePromotionDiscountSet,
TimePromotionDiscountReset
])
event_store.subscribe(CalculateOrderTotalSubAmountsValue, to: [
PriceItemAdded,
PriceItemRemoved,
PercentageDiscountSet,
PercentageDiscountReset,
PercentageDiscountChanged,
ProductMadeFreeForOrder,
FreeProductRemovedFromOrder
FreeProductRemovedFromOrder,
TimePromotionDiscountSet,
TimePromotionDiscountReset
])
end
end
Expand Down
23 changes: 23 additions & 0 deletions ecommerce/pricing/lib/pricing/apply_time_promotion.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module Pricing
class ApplyTimePromotion
def call(event)
discount = PromotionsCalendar.new(event_store).current_time_promotions_discount

if discount.exists?
command_bus.(SetTimePromotionDiscount.new(order_id: event.data.fetch(:order_id), amount: discount.value))
else
command_bus.(ResetTimePromotionDiscount.new(order_id: event.data.fetch(:order_id)))
end
end

private

def command_bus
Pricing.command_bus
end

def event_store
Pricing.event_store
end
end
end
13 changes: 13 additions & 0 deletions ecommerce/pricing/lib/pricing/commands.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,19 @@ class ResetPercentageDiscount < Infra::Command
alias aggregate_id order_id
end

class SetTimePromotionDiscount < Infra::Command
attribute :order_id, Infra::Types::UUID
attribute :amount, Infra::Types::PercentageDiscount

alias aggregate_id order_id
end

class ResetTimePromotionDiscount < Infra::Command
attribute :order_id, Infra::Types::UUID

alias aggregate_id order_id
end

class RegisterCoupon < Infra::Command
attribute :coupon_id, Infra::Types::UUID
attribute :name, Infra::Types::String
Expand Down
9 changes: 9 additions & 0 deletions ecommerce/pricing/lib/pricing/discounts.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ def add(other_discount)
PercentageDiscount.new(new_value)
end

def ==(other)
value == other.value
end

def exists?
true
end
Expand All @@ -57,7 +61,12 @@ def value
0
end

def ==(other)
value == other.value
end

def exists?
false
end
end
end
Expand Down
11 changes: 10 additions & 1 deletion ecommerce/pricing/lib/pricing/events.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,16 @@ class PriceItemValueCalculated < Infra::Event

class PercentageDiscountSet < Infra::Event
attribute :order_id, Infra::Types::UUID
attribute :amount, Infra::Types::Price
attribute :amount, Infra::Types::PercentageDiscount
end

class TimePromotionDiscountSet < Infra::Event
attribute :order_id, Infra::Types::UUID
attribute :amount, Infra::Types::PercentageDiscount
end

class TimePromotionDiscountReset < Infra::Event
attribute :order_id, Infra::Types::UUID
end

class PriceItemAdded < Infra::Event
Expand Down
36 changes: 32 additions & 4 deletions ecommerce/pricing/lib/pricing/offer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ def initialize(id)
@id = id
@list = List.new
@discount = Discounts::NoPercentageDiscount.new
@time_promotion_discount = Discounts::NoPercentageDiscount.new
end

def add_item(product_id)
Expand Down Expand Up @@ -36,6 +37,25 @@ def apply_discount(discount)
)
end

def apply_time_promotion_discount(time_promotion)
return if time_promotion == @time_promotion_discount
apply TimePromotionDiscountSet.new(
data: {
order_id: @id,
amount: time_promotion.value
}
)
end

def reset_time_promotion_discount
return unless @time_promotion_discount.exists?
apply TimePromotionDiscountReset.new(
data: {
order_id: @id
}
)
end

def change_discount(discount)
raise NotPossibleToChangeDiscount unless @discount.exists?
apply PercentageDiscountChanged.new(
Expand Down Expand Up @@ -75,10 +95,10 @@ def remove_free_product(order_id, product_id)
)
end

def calculate_total_value(pricing_catalog, time_promotion_discount)
def calculate_total_value(pricing_catalog)
total_value = @list.base_sum(pricing_catalog)

discounted_value = @discount.add(time_promotion_discount).apply(total_value)
discounted_value = @discount.add(@time_promotion_discount).apply(total_value)
apply(
OrderTotalValueCalculated.new(
data: {
Expand All @@ -90,9 +110,9 @@ def calculate_total_value(pricing_catalog, time_promotion_discount)
)
end

def calculate_sub_amounts(pricing_catalog, time_promotions_discount)
def calculate_sub_amounts(pricing_catalog)
sub_amounts_total = @list.sub_amounts_total(pricing_catalog)
sub_discounts = calculate_total_sub_discounts(pricing_catalog, time_promotions_discount)
sub_discounts = calculate_total_sub_discounts(pricing_catalog, @time_promotion_discount)

products = @list.products
quantities = @list.quantities
Expand Down Expand Up @@ -145,6 +165,14 @@ def use_coupon(coupon_id, discount)
@discount = Discounts::PercentageDiscount.new(event.data.fetch(:amount))
end

on TimePromotionDiscountSet do |event|
@time_promotion_discount = Discounts::PercentageDiscount.new(event.data.fetch(:amount))
end

on TimePromotionDiscountReset do |event|
@time_promotion_discount = Discounts::NoPercentageDiscount.new
end

on PercentageDiscountReset do |event|
@discount = Discounts::NoPercentageDiscount.new
end
Expand Down
37 changes: 26 additions & 11 deletions ecommerce/pricing/lib/pricing/services.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,30 @@ def call(cmd)
end
end

class SetTimePromotionDiscountHandler
def initialize(event_store)
@repository = Infra::AggregateRootRepository.new(event_store)
end

def call(cmd)
@repository.with_aggregate(Offer, cmd.aggregate_id) do |order|
order.apply_time_promotion_discount(Discounts::PercentageDiscount.new(cmd.amount))
end
end
end

class ResetTimePromotionDiscountHandler
def initialize(event_store)
@repository = Infra::AggregateRootRepository.new(event_store)
end

def call(cmd)
@repository.with_aggregate(Offer, cmd.aggregate_id) do |order|
order.reset_time_promotion_discount
end
end
end

class SetPriceHandler
def initialize(event_store)
@repository = Infra::AggregateRootRepository.new(event_store)
Expand Down Expand Up @@ -124,27 +148,18 @@ def initialize(event_store)
def call(command)
with_retry do
@repository.with_aggregate(Offer, command.aggregate_id) do |order|
order.calculate_total_value(PricingCatalog.new(@event_store), time_promotions_discount)
order.calculate_total_value(PricingCatalog.new(@event_store))
end
end
end



def calculate_sub_amounts(command)
with_retry do
@repository.with_aggregate(Offer, command.aggregate_id) do |order|
order.calculate_sub_amounts(PricingCatalog.new(@event_store), time_promotions_discount)
order.calculate_sub_amounts(PricingCatalog.new(@event_store))
end
end
end

private

def time_promotions_discount
PromotionsCalendar.new(@event_store).current_time_promotions_discount
end

end

class OnCouponRegister
Expand Down
90 changes: 90 additions & 0 deletions ecommerce/pricing/test/apply_time_promotion_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
require_relative "test_helper"

module Pricing
class ApplyTimePromotionTest < Test
cover "Pricing*"

def test_applies_biggest_time_promotion_discount
order_id = SecureRandom.uuid
product_id = SecureRandom.uuid
create_inactive_time_promotion(60)
create_active_time_promotion(10)
create_active_time_promotion(50)
create_active_time_promotion(30)

assert_events_contain(stream_name(order_id), time_promotion_discount_set_event(order_id, 50)) do
Pricing::ApplyTimePromotion.new.call(item_added_to_basket_event(order_id, product_id))
end
end

def test_resets_time_promotion_discount
order_id = SecureRandom.uuid
product_id = SecureRandom.uuid
set_time_promotion_discount(order_id, 50)

assert_events_contain(stream_name(order_id), time_promotion_discount_reset_event(order_id)) do
Pricing::ApplyTimePromotion.new.call(item_added_to_basket_event(order_id, product_id))
end
end

private

def create_inactive_time_promotion(discount)
run_command(
Pricing::CreateTimePromotion.new(
time_promotion_id: SecureRandom.uuid,
discount: discount,
start_time: Time.current - 2,
end_time: Time.current - 1,
label: "Past Promotion"
)
)
end

def create_active_time_promotion(discount)
run_command(
Pricing::CreateTimePromotion.new(
time_promotion_id: SecureRandom.uuid,
discount: discount,
start_time: Time.current - 1,
end_time: Time.current + 1,
label: "Last Minute"
)
)
end

def item_added_to_basket_event(order_id, product_id)
Pricing::PriceItemAdded.new(
data: {
product_id: product_id,
order_id: order_id
}
)
end

def set_time_promotion_discount(order_id, discount)
run_command(SetTimePromotionDiscount.new(order_id: order_id, amount: 50))
end

def time_promotion_discount_set_event(order_id, amount)
TimePromotionDiscountSet.new(
data: {
order_id: order_id,
amount: amount
}
)
end

def time_promotion_discount_reset_event(order_id)
TimePromotionDiscountReset.new(
data: {
order_id: order_id
}
)
end

def stream_name(order_id)
"Pricing::Offer$#{order_id}"
end
end
end
Loading

0 comments on commit 45fd881

Please sign in to comment.