From 45fd88178d393458973b7a89138e373f4292c420 Mon Sep 17 00:00:00 2001 From: marlena-b Date: Sun, 6 Oct 2024 14:23:48 +0200 Subject: [PATCH] Display time promotion on order page --- ecommerce/pricing/lib/pricing.rb | 26 ++- .../lib/pricing/apply_time_promotion.rb | 23 +++ ecommerce/pricing/lib/pricing/commands.rb | 13 ++ ecommerce/pricing/lib/pricing/discounts.rb | 9 + ecommerce/pricing/lib/pricing/events.rb | 11 +- ecommerce/pricing/lib/pricing/offer.rb | 36 +++- ecommerce/pricing/lib/pricing/services.rb | 37 ++-- .../pricing/test/apply_time_promotion_test.rb | 90 ++++++++++ ecommerce/pricing/test/discounts_test.rb | 32 ++++ ecommerce/pricing/test/pricing_test.rb | 46 +++++ .../pricing/test/promotions_calendar_test.rb | 30 ++++ ecommerce/pricing/test/test_helper.rb | 8 + ecommerce/pricing/test/time_promotion_test.rb | 167 ++++++------------ .../app/read_models/orders/configuration.rb | 1 + .../update_time_promotion_discount_value.rb | 10 ++ .../app/views/orders/show.html.erb | 6 + ..._value_to_time_promotion_discount_value.rb | 5 + rails_application/db/schema.rb | 4 +- .../test/integration/orders_test.rb | 9 +- ...date_time_promotion_discount_value_test.rb | 61 +++++++ 20 files changed, 486 insertions(+), 138 deletions(-) create mode 100644 ecommerce/pricing/lib/pricing/apply_time_promotion.rb create mode 100644 ecommerce/pricing/test/apply_time_promotion_test.rb create mode 100644 ecommerce/pricing/test/promotions_calendar_test.rb create mode 100644 rails_application/app/read_models/orders/update_time_promotion_discount_value.rb create mode 100644 rails_application/db/migrate/20241002130622_rename_happy_hour_value_to_time_promotion_discount_value.rb create mode 100644 rails_application/test/orders/update_time_promotion_discount_value_test.rb diff --git a/ecommerce/pricing/lib/pricing.rb b/ecommerce/pricing/lib/pricing.rb index 64b5735e6..c58722a6c 100644 --- a/ecommerce/pricing/lib/pricing.rb +++ b/ecommerce/pricing/lib/pricing.rb @@ -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) @@ -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, @@ -99,6 +108,17 @@ 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, @@ -106,7 +126,9 @@ def call(event_store, command_bus) PercentageDiscountReset, PercentageDiscountChanged, ProductMadeFreeForOrder, - FreeProductRemovedFromOrder + FreeProductRemovedFromOrder, + TimePromotionDiscountSet, + TimePromotionDiscountReset ]) end end diff --git a/ecommerce/pricing/lib/pricing/apply_time_promotion.rb b/ecommerce/pricing/lib/pricing/apply_time_promotion.rb new file mode 100644 index 000000000..2630faf3a --- /dev/null +++ b/ecommerce/pricing/lib/pricing/apply_time_promotion.rb @@ -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 diff --git a/ecommerce/pricing/lib/pricing/commands.rb b/ecommerce/pricing/lib/pricing/commands.rb index 94bb2596f..832f94739 100644 --- a/ecommerce/pricing/lib/pricing/commands.rb +++ b/ecommerce/pricing/lib/pricing/commands.rb @@ -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 diff --git a/ecommerce/pricing/lib/pricing/discounts.rb b/ecommerce/pricing/lib/pricing/discounts.rb index 8134c7edd..ec5084e2f 100644 --- a/ecommerce/pricing/lib/pricing/discounts.rb +++ b/ecommerce/pricing/lib/pricing/discounts.rb @@ -33,6 +33,10 @@ def add(other_discount) PercentageDiscount.new(new_value) end + def ==(other) + value == other.value + end + def exists? true end @@ -57,7 +61,12 @@ def value 0 end + def ==(other) + value == other.value + end + def exists? + false end end end diff --git a/ecommerce/pricing/lib/pricing/events.rb b/ecommerce/pricing/lib/pricing/events.rb index 79120e3f5..246a6b433 100644 --- a/ecommerce/pricing/lib/pricing/events.rb +++ b/ecommerce/pricing/lib/pricing/events.rb @@ -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 diff --git a/ecommerce/pricing/lib/pricing/offer.rb b/ecommerce/pricing/lib/pricing/offer.rb index 34675493a..dc672ca27 100644 --- a/ecommerce/pricing/lib/pricing/offer.rb +++ b/ecommerce/pricing/lib/pricing/offer.rb @@ -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) @@ -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( @@ -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: { @@ -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 @@ -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 diff --git a/ecommerce/pricing/lib/pricing/services.rb b/ecommerce/pricing/lib/pricing/services.rb index bfd29ebbc..1e5a1be6f 100644 --- a/ecommerce/pricing/lib/pricing/services.rb +++ b/ecommerce/pricing/lib/pricing/services.rb @@ -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) @@ -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 diff --git a/ecommerce/pricing/test/apply_time_promotion_test.rb b/ecommerce/pricing/test/apply_time_promotion_test.rb new file mode 100644 index 000000000..25f6f1374 --- /dev/null +++ b/ecommerce/pricing/test/apply_time_promotion_test.rb @@ -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 diff --git a/ecommerce/pricing/test/discounts_test.rb b/ecommerce/pricing/test/discounts_test.rb index b7387cc70..cf0fa7c02 100644 --- a/ecommerce/pricing/test/discounts_test.rb +++ b/ecommerce/pricing/test/discounts_test.rb @@ -55,6 +55,20 @@ def test_cannot_add_to_more_than_100 assert_equal(0, combined.apply(100)) end + + def test_is_equal_to_another_discount + first_discount = PercentageDiscount.new(50) + second_discount = PercentageDiscount.new(50) + + assert_equal(first_discount, second_discount) + end + + def test_is_not_equal_to_another_discount + first_discount = PercentageDiscount.new(50) + second_discount = PercentageDiscount.new(60) + + refute_equal(first_discount, second_discount) + end end class NoPercentageDiscountTest < Test @@ -63,6 +77,24 @@ class NoPercentageDiscountTest < Test def test_doesnt_change_total assert_equal(100, NoPercentageDiscount.new.apply(100)) end + + def test_is_equal_to_another_discount + first_discount = NoPercentageDiscount.new + second_discount = NoPercentageDiscount.new + + assert_equal(first_discount, second_discount) + end + + def test_is_not_equal_to_another_discount + first_discount = NoPercentageDiscount.new + second_discount = PercentageDiscount.new(50) + + refute_equal(first_discount, second_discount) + end + + def test_exists_returns_false + assert_equal false, NoPercentageDiscount.new.exists? + end end end end diff --git a/ecommerce/pricing/test/pricing_test.rb b/ecommerce/pricing/test/pricing_test.rb index 14f2326e3..f2397a0d6 100644 --- a/ecommerce/pricing/test/pricing_test.rb +++ b/ecommerce/pricing/test/pricing_test.rb @@ -93,6 +93,52 @@ def test_calculates_sub_amounts ) { calculate_sub_amounts(order_id) } end + def test_sets_time_promotion_discount + order_id = SecureRandom.uuid + stream = stream_name(order_id) + + assert_events_contain( + stream, + TimePromotionDiscountSet.new( + data: { + order_id: order_id, + amount: 25 + } + ) + ) { set_time_promotion_discount(order_id, 25) } + end + + def test_does_not_set_the_same_time_promotion_discount_twice + order_id = SecureRandom.uuid + stream = stream_name(order_id) + set_time_promotion_discount(order_id, 25) + + assert_events(stream) { set_time_promotion_discount(order_id, 25) } + end + + def test_resets_time_promotion_discount + order_id = SecureRandom.uuid + stream = stream_name(order_id) + set_time_promotion_discount(order_id, 25) + + + assert_events_contain( + stream, + TimePromotionDiscountReset.new( + data: { + order_id: order_id + } + ) + ) { reset_time_promotion_discount(order_id) } + end + + def test_does_not_reset_time_promotion_discount_if_there_is_none + order_id = SecureRandom.uuid + stream = stream_name(order_id) + + assert_events(stream) { reset_time_promotion_discount(order_id) } + end + def test_calculates_total_value_with_discount product_1_id = SecureRandom.uuid set_price(product_1_id, 20) diff --git a/ecommerce/pricing/test/promotions_calendar_test.rb b/ecommerce/pricing/test/promotions_calendar_test.rb new file mode 100644 index 000000000..b58298045 --- /dev/null +++ b/ecommerce/pricing/test/promotions_calendar_test.rb @@ -0,0 +1,30 @@ +require_relative "test_helper" + +module Pricing + class PromotionsCalendarTest < Test + cover "Pricing::PromotionsCalendar*" + + def test_time_promotion_running + time_current = Time.current + promotion = Pricing::PromotionsCalendar::Promotion.from_event(time_promotion_created_event(time_current)) + + assert(promotion.running?(time_current)) + refute(promotion.running?(time_current + 1)) + refute(promotion.running?(time_current - 2)) + refute(promotion.running?(time_current + 2)) + end + + private + + def time_promotion_created_event(time_current) + TimePromotionCreated.new( + data: { + time_promotion_id: SecureRandom.uuid, + start_time: time_current - 1, + end_time: time_current + 1, + discount: 10 + } + ) + end + end +end diff --git a/ecommerce/pricing/test/test_helper.rb b/ecommerce/pricing/test/test_helper.rb index eb9e385f5..66b1c8b58 100644 --- a/ecommerce/pricing/test/test_helper.rb +++ b/ecommerce/pricing/test/test_helper.rb @@ -42,6 +42,14 @@ def register_coupon(uid, name, code, discount) run_command(RegisterCoupon.new(coupon_id: uid, name: name, code: code, discount: discount)) end + def set_time_promotion_discount(order_id, amount) + run_command(SetTimePromotionDiscount.new(order_id: order_id, amount: amount)) + end + + def reset_time_promotion_discount(order_id) + run_command(ResetTimePromotionDiscount.new(order_id: order_id)) + end + def fake_name "Fake name" end diff --git a/ecommerce/pricing/test/time_promotion_test.rb b/ecommerce/pricing/test/time_promotion_test.rb index 2399bf1bf..58c3efb2f 100644 --- a/ecommerce/pricing/test/time_promotion_test.rb +++ b/ecommerce/pricing/test/time_promotion_test.rb @@ -41,127 +41,66 @@ class DiscountWithTimePromotionTest < Test cover "Pricing*" def test_calculates_total_value_with_time_promotion - timestamp = Time.utc(2022, 5, 30, 15, 33) - - Timecop.freeze(timestamp) do - product_1_id = SecureRandom.uuid - set_price(product_1_id, 20) - order_id = SecureRandom.uuid - add_item(order_id, product_1_id) - stream = stream_name(order_id) - - assert_events( - stream, - OrderTotalValueCalculated.new( - data: { - order_id: order_id, - discounted_amount: 20, - total_amount: 20 - } - ) - ) { calculate_total_value(order_id) } - - # Current promotions - first_time_promotion_id = SecureRandom.uuid - start_time = timestamp - 1 - end_time = timestamp + 1 - set_time_promotion_range(first_time_promotion_id, start_time, end_time, 40) - - time_promotion_id = SecureRandom.uuid - start_time = timestamp - end_time = timestamp + 1 - set_time_promotion_range(time_promotion_id, start_time, end_time, 1) - - - time_promotion_id = SecureRandom.uuid - start_time = timestamp - end_time = timestamp + 1 - set_time_promotion_range(time_promotion_id, start_time, end_time, 50) - - # Not applicable promotions - set_not_applicable_promotions(timestamp) - - assert_events( - stream, - OrderTotalValueCalculated.new( - data: { - order_id: order_id, - total_amount: 20, - discounted_amount: 10, - } - ) - ) { calculate_total_value(order_id) } - end + order_id = SecureRandom.uuid + product_1_id = SecureRandom.uuid + set_price(product_1_id, 20) + add_item(order_id, product_1_id) + stream = stream_name(order_id) + + run_command(SetTimePromotionDiscount.new(order_id: order_id, amount: 50)) + + assert_events_contain( + stream, + OrderTotalValueCalculated.new( + data: { + order_id: order_id, + total_amount: 20, + discounted_amount: 10 + } + ) + ) { calculate_total_value(order_id) } end def test_calculates_sub_amounts_with_combined_discounts - timestamp = Time.utc(2022, 5, 30, 15, 33) - Timecop.freeze(timestamp) do - - product_1_id = SecureRandom.uuid - product_2_id = SecureRandom.uuid - set_price(product_1_id, 20) - set_price(product_2_id, 30) - order_id = SecureRandom.uuid - stream = stream_name(order_id) + product_1_id = SecureRandom.uuid + product_2_id = SecureRandom.uuid + set_price(product_1_id, 20) + set_price(product_2_id, 30) + order_id = SecureRandom.uuid + stream = stream_name(order_id) - assert_events(stream) { calculate_sub_amounts(order_id) } + run_command(CreateTimePromotion.new(time_promotion_id: SecureRandom.uuid, discount: 50, start_time: Time.current - 1, end_time: Time.current + 1, label: "test")) - add_item(order_id, product_1_id) - add_item(order_id, product_2_id) - add_item(order_id, product_2_id) - assert_events( - stream, - PriceItemValueCalculated.new( - data: { - order_id: order_id, - product_id: product_1_id, - quantity: 1, - amount: 20, - discounted_amount: 20 - } - ), - PriceItemValueCalculated.new( - data: { - order_id: order_id, - product_id: product_2_id, - quantity: 2, - amount: 60, - discounted_amount: 60 - } - ) - ) { calculate_sub_amounts(order_id) } - run_command( - Pricing::SetPercentageDiscount.new(order_id: order_id, amount: 10) - ) + add_item(order_id, product_1_id) + add_item(order_id, product_2_id) + add_item(order_id, product_2_id) + run_command(SetTimePromotionDiscount.new(order_id: order_id, amount: 50)) - first_time_promotion_id = SecureRandom.uuid - start_time = timestamp - 1 - end_time = timestamp + 1 - set_time_promotion_range(first_time_promotion_id, start_time, end_time, 50) + run_command( + Pricing::SetPercentageDiscount.new(order_id: order_id, amount: 10) + ) - assert_events( - stream, - PriceItemValueCalculated.new( - data: { - order_id: order_id, - product_id: product_1_id, - quantity: 1, - amount: 20, - discounted_amount: 8 - } - ), - PriceItemValueCalculated.new( - data: { - order_id: order_id, - product_id: product_2_id, - quantity: 2, - amount: 60, - discounted_amount: 24 - } - ) - ) { calculate_sub_amounts(order_id) } - end + assert_events_contain( + stream, + PriceItemValueCalculated.new( + data: { + order_id: order_id, + product_id: product_1_id, + quantity: 1, + amount: 20, + discounted_amount: 8 + } + ), + PriceItemValueCalculated.new( + data: { + order_id: order_id, + product_id: product_2_id, + quantity: 2, + amount: 60, + discounted_amount: 24 + } + ) + ) { calculate_sub_amounts(order_id) } end def test_cant_create_twice diff --git a/rails_application/app/read_models/orders/configuration.rb b/rails_application/app/read_models/orders/configuration.rb index a4bd8ed2f..87553986c 100644 --- a/rails_application/app/read_models/orders/configuration.rb +++ b/rails_application/app/read_models/orders/configuration.rb @@ -46,6 +46,7 @@ def call(event_store) event_store.subscribe(ExpireOrder.new, to: [Ordering::OrderExpired]) event_store.subscribe(ConfirmOrder.new, to: [Fulfillment::OrderConfirmed]) event_store.subscribe(CancelOrder.new, to: [Fulfillment::OrderCancelled]) + event_store.subscribe(UpdateTimePromotionDiscountValue.new, to: [Pricing::TimePromotionDiscountSet]) subscribe( diff --git a/rails_application/app/read_models/orders/update_time_promotion_discount_value.rb b/rails_application/app/read_models/orders/update_time_promotion_discount_value.rb new file mode 100644 index 000000000..5fb4a62ca --- /dev/null +++ b/rails_application/app/read_models/orders/update_time_promotion_discount_value.rb @@ -0,0 +1,10 @@ +module Orders + class UpdateTimePromotionDiscountValue + def call(event) + order = Order.find_or_create_by(uid: event.data.fetch(:order_id)) + + order.time_promotion_discount_value = event.data.fetch(:amount) + order.save! + end + end +end diff --git a/rails_application/app/views/orders/show.html.erb b/rails_application/app/views/orders/show.html.erb index 8d4188222..3847b7b93 100644 --- a/rails_application/app/views/orders/show.html.erb +++ b/rails_application/app/views/orders/show.html.erb @@ -104,6 +104,12 @@ <%= @order.percentage_discount %>% <% end %> + <% if @order.time_promotion_discount_value %> + + Time Promotion discount + <%= @order.time_promotion_discount_value %>% + + <% end %> Total diff --git a/rails_application/db/migrate/20241002130622_rename_happy_hour_value_to_time_promotion_discount_value.rb b/rails_application/db/migrate/20241002130622_rename_happy_hour_value_to_time_promotion_discount_value.rb new file mode 100644 index 000000000..a9601df86 --- /dev/null +++ b/rails_application/db/migrate/20241002130622_rename_happy_hour_value_to_time_promotion_discount_value.rb @@ -0,0 +1,5 @@ +class RenameHappyHourValueToTimePromotionDiscountValue < ActiveRecord::Migration[7.2] + def change + rename_column :orders, :happy_hour_value, :time_promotion_discount_value + end +end diff --git a/rails_application/db/schema.rb b/rails_application/db/schema.rb index 99d056d90..89d3473f2 100644 --- a/rails_application/db/schema.rb +++ b/rails_application/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.2].define(version: 2024_08_27_090619) do +ActiveRecord::Schema[7.2].define(version: 2024_10_02_130622) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" enable_extension "plpgsql" @@ -160,7 +160,7 @@ t.decimal "percentage_discount", precision: 8, scale: 2 t.decimal "total_value", precision: 8, scale: 2 t.decimal "discounted_value", precision: 8, scale: 2 - t.decimal "happy_hour_value", precision: 8, scale: 2 + t.decimal "time_promotion_discount_value", precision: 8, scale: 2 t.datetime "total_value_updated_at" t.datetime "discount_updated_at" t.index ["uid"], name: "index_orders_on_uid", unique: true diff --git a/rails_application/test/integration/orders_test.rb b/rails_application/test/integration/orders_test.rb index f3b257cab..aaf738a91 100644 --- a/rails_application/test/integration/orders_test.rb +++ b/rails_application/test/integration/orders_test.rb @@ -251,7 +251,7 @@ def test_current_time_promotion_is_applied async_remote_id = register_product("Async Remote", 39, 10) shopify_id = register_customer("Shopify") - create_current_time_promotion + create_active_time_promotion(50) post "/orders/#{order_id}/add_item?product_id=#{async_remote_id}" post "/orders", @@ -265,6 +265,7 @@ def test_current_time_promotion_is_applied assert_select("td", "$19.50") assert_select("dd", "Submitted") + assert_select("td", "50.0%") end private @@ -378,12 +379,12 @@ def apply_discount_10_percent(order_id) post "/orders/#{order_id}/update_discount?amount=10" end - def create_current_time_promotion(discount: 50, start_time: Time.current - 1.day, end_time: Time.current + 1.day) + def create_active_time_promotion(discount) post "/time_promotions", params: { label: "Last Minute", discount: discount, - start_time: start_time, - end_time: end_time + start_time: Time.current - 1, + end_time: Time.current + 1 } end end diff --git a/rails_application/test/orders/update_time_promotion_discount_value_test.rb b/rails_application/test/orders/update_time_promotion_discount_value_test.rb new file mode 100644 index 000000000..cb650b8d2 --- /dev/null +++ b/rails_application/test/orders/update_time_promotion_discount_value_test.rb @@ -0,0 +1,61 @@ +require "test_helper" + +module Orders + class UpdateTimePromotionDiscountValueTest < InMemoryTestCase + cover "Orders*" + + def test_updates_time_promotion_discount_value + customer_id = SecureRandom.uuid + product_id = SecureRandom.uuid + order_id = SecureRandom.uuid + create_active_time_promotion + customer_registered(customer_id) + prepare_product(product_id) + item_added_to_basket(order_id, product_id) + + order = Orders::Order.find_by(uid: order_id) + assert_equal 50, order.time_promotion_discount_value + end + + private + + def item_added_to_basket(order_id, product_id) + event_store.publish(Pricing::PriceItemAdded.new(data: { product_id: product_id, order_id: order_id })) + end + + def prepare_product(product_id) + run_command( + ProductCatalog::RegisterProduct.new( + product_id: product_id, + ) + ) + run_command( + ProductCatalog::NameProduct.new( + product_id: product_id, + name: "test" + ) + ) + run_command(Pricing::SetPrice.new(product_id: product_id, price: 50)) + end + + def customer_registered(customer_id) + event_store.publish(Crm::CustomerRegistered.new(data: { customer_id: customer_id, name: "Arkency" })) + end + + def create_active_time_promotion + run_command( + Pricing::CreateTimePromotion.new( + time_promotion_id: SecureRandom.uuid, + discount: 50, + start_time: Time.current - 1, + end_time: Time.current + 1, + label: "Last Minute" + ) + ) + end + + def event_store + Rails.configuration.event_store + end + end +end