diff --git a/ecommerce/configuration.rb b/ecommerce/configuration.rb index b256c8b20..2af4d70bf 100644 --- a/ecommerce/configuration.rb +++ b/ecommerce/configuration.rb @@ -8,6 +8,7 @@ require_relative "shipping/lib/shipping" require_relative "invoicing/lib/invoicing" require_relative "taxes/lib/taxes" +require_relative "fulfillment/lib/fulfillment" require_relative "processes/lib/processes" module Ecommerce @@ -38,6 +39,7 @@ def configure_bounded_contexts(event_store, command_bus) Pricing::Configuration.new, Taxes::Configuration.new(@available_vat_rates), ProductCatalog::Configuration.new, + Fulfillment::Configuration.new ].each { |c| c.call(event_store, command_bus) } end diff --git a/ecommerce/fulfillment/.mutant.yml b/ecommerce/fulfillment/.mutant.yml new file mode 100644 index 000000000..6d1df49be --- /dev/null +++ b/ecommerce/fulfillment/.mutant.yml @@ -0,0 +1,12 @@ +requires: + - ./test/test_helper +integration: minitest +coverage_criteria: + process_abort: true +matcher: + subjects: + - Fulfillment* + ignore: + - Fulfillment::Test* + - Fulfillment::Configuration#call + - Fulfillment::Configuration#initialize \ No newline at end of file diff --git a/ecommerce/fulfillment/Gemfile b/ecommerce/fulfillment/Gemfile new file mode 100644 index 000000000..8fd887144 --- /dev/null +++ b/ecommerce/fulfillment/Gemfile @@ -0,0 +1,4 @@ +source "https://rubygems.org" + +eval_gemfile "../../infra/Gemfile.test" +gem "infra", path: "../../infra" \ No newline at end of file diff --git a/ecommerce/fulfillment/Gemfile.lock b/ecommerce/fulfillment/Gemfile.lock new file mode 100644 index 000000000..87553b254 --- /dev/null +++ b/ecommerce/fulfillment/Gemfile.lock @@ -0,0 +1,116 @@ +PATH + remote: ../../infra + specs: + infra (1.0.0) + aggregate_root (~> 2.13) + arkency-command_bus + dry-struct + dry-types + rake + ruby_event_store (~> 2.13) + ruby_event_store-transformations + sidekiq + +GEM + remote: https://oss:7AXfeZdAfCqL1PvHm2nvDJO6Zd9UW8IK@gem.mutant.dev/ + specs: + mutant-license (0.1.1.2.1627430819213747598431630701693729869473.6) + +GEM + remote: https://rubygems.org/ + specs: + activesupport (7.1.3.2) + base64 + bigdecimal + concurrent-ruby (~> 1.0, >= 1.0.2) + connection_pool (>= 2.2.5) + drb + i18n (>= 1.6, < 2) + minitest (>= 5.1) + mutex_m + tzinfo (~> 2.0) + aggregate_root (2.14.0) + base64 + ruby_event_store (= 2.14.0) + arkency-command_bus (0.4.1) + concurrent-ruby + ast (2.4.2) + base64 (0.2.0) + bigdecimal (3.1.7) + concurrent-ruby (1.2.3) + connection_pool (2.4.1) + diff-lcs (1.5.1) + drb (2.2.1) + dry-core (1.0.1) + concurrent-ruby (~> 1.0) + zeitwerk (~> 2.6) + dry-inflector (1.0.0) + dry-logic (1.5.0) + concurrent-ruby (~> 1.0) + dry-core (~> 1.0, < 2) + zeitwerk (~> 2.6) + dry-struct (1.6.0) + dry-core (~> 1.0, < 2) + dry-types (>= 1.7, < 2) + ice_nine (~> 0.11) + zeitwerk (~> 2.6) + dry-types (1.7.2) + bigdecimal (~> 3.0) + concurrent-ruby (~> 1.0) + dry-core (~> 1.0) + dry-inflector (~> 1.0) + dry-logic (~> 1.4) + zeitwerk (~> 2.6) + i18n (1.14.4) + concurrent-ruby (~> 1.0) + ice_nine (0.11.2) + minitest (5.15.0) + mutant (0.11.26) + diff-lcs (~> 1.3) + parser (~> 3.2.2, >= 3.2.2.4) + regexp_parser (~> 2.8.2) + sorbet-runtime (~> 0.5.0) + unparser (~> 0.6.9) + mutant-minitest (0.11.26) + minitest (~> 5.11) + mutant (= 0.11.26) + mutex_m (0.2.0) + parser (3.2.2.4) + ast (~> 2.4.1) + racc + racc (1.7.3) + rack (3.0.10) + rake (13.2.1) + redis-client (0.22.1) + connection_pool + regexp_parser (2.8.3) + ruby_event_store (2.14.0) + concurrent-ruby (~> 1.0, >= 1.1.6) + ruby_event_store-transformations (0.1.0) + activesupport (>= 5.0) + ruby_event_store (>= 2.0.0, < 3.0.0) + sidekiq (7.2.4) + concurrent-ruby (< 2) + connection_pool (>= 2.3.0) + rack (>= 2.2.4) + redis-client (>= 0.19.0) + sorbet-runtime (0.5.11368) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + unparser (0.6.12) + diff-lcs (~> 1.3) + parser (>= 3.2.2.4) + zeitwerk (2.6.13) + +PLATFORMS + arm64-darwin-23 + ruby + +DEPENDENCIES + infra! + minitest (= 5.15.0)! + mutant-license! + mutant-minitest (= 0.11.26)! + +BUNDLED WITH + 2.5.9 diff --git a/ecommerce/fulfillment/Makefile b/ecommerce/fulfillment/Makefile new file mode 100644 index 000000000..23850fab1 --- /dev/null +++ b/ecommerce/fulfillment/Makefile @@ -0,0 +1,10 @@ +install: + @bundle install + +test: + @bundle exec ruby -e "require \"rake/rake_test_loader\"" test/*_test.rb + +mutate: + @RAILS_ENV=test bundle exec mutant run + +.PHONY: install test mutate diff --git a/ecommerce/fulfillment/lib/fulfillment.rb b/ecommerce/fulfillment/lib/fulfillment.rb new file mode 100644 index 000000000..66ea3b558 --- /dev/null +++ b/ecommerce/fulfillment/lib/fulfillment.rb @@ -0,0 +1,21 @@ +require "infra" +require_relative "fulfillment/events/order_registered" +require_relative "fulfillment/events/order_confirmed" +require_relative "fulfillment/events/order_cancelled" +require_relative "fulfillment/commands/register_order" +require_relative "fulfillment/commands/confirm_order" +require_relative "fulfillment/commands/cancel_order" +require_relative "fulfillment/on_register_order" +require_relative "fulfillment/on_cancel_order" +require_relative "fulfillment/on_confirm_order" +require_relative "fulfillment/order" + +module Fulfillment + class Configuration + def call(event_store, command_bus) + command_bus.register(RegisterOrder, OnRegisterOrder.new(event_store)) + command_bus.register(ConfirmOrder, OnConfirmOrder.new(event_store)) + command_bus.register(CancelOrder, OnCancelOrder.new(event_store)) + end + end +end diff --git a/ecommerce/ordering/lib/ordering/commands/cancel_order.rb b/ecommerce/fulfillment/lib/fulfillment/commands/cancel_order.rb similarity index 71% rename from ecommerce/ordering/lib/ordering/commands/cancel_order.rb rename to ecommerce/fulfillment/lib/fulfillment/commands/cancel_order.rb index 2e51b7c2f..0d1dd8b70 100644 --- a/ecommerce/ordering/lib/ordering/commands/cancel_order.rb +++ b/ecommerce/fulfillment/lib/fulfillment/commands/cancel_order.rb @@ -1,4 +1,6 @@ -module Ordering +# frozen_string_literal: true + +module Fulfillment class CancelOrder < Infra::Command attribute :order_id, Infra::Types::UUID diff --git a/ecommerce/ordering/lib/ordering/commands/confirm_order.rb b/ecommerce/fulfillment/lib/fulfillment/commands/confirm_order.rb similarity index 71% rename from ecommerce/ordering/lib/ordering/commands/confirm_order.rb rename to ecommerce/fulfillment/lib/fulfillment/commands/confirm_order.rb index 874204d1f..729debae4 100644 --- a/ecommerce/ordering/lib/ordering/commands/confirm_order.rb +++ b/ecommerce/fulfillment/lib/fulfillment/commands/confirm_order.rb @@ -1,4 +1,6 @@ -module Ordering +# frozen_string_literal: true + +module Fulfillment class ConfirmOrder < Infra::Command attribute :order_id, Infra::Types::UUID diff --git a/ecommerce/fulfillment/lib/fulfillment/commands/register_order.rb b/ecommerce/fulfillment/lib/fulfillment/commands/register_order.rb new file mode 100644 index 000000000..18bb18370 --- /dev/null +++ b/ecommerce/fulfillment/lib/fulfillment/commands/register_order.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module Fulfillment + class RegisterOrder < Infra::Command + attribute :order_id, Infra::Types::UUID + + alias aggregate_id order_id + end +end \ No newline at end of file diff --git a/ecommerce/ordering/lib/ordering/events/order_cancelled.rb b/ecommerce/fulfillment/lib/fulfillment/events/order_cancelled.rb similarity index 64% rename from ecommerce/ordering/lib/ordering/events/order_cancelled.rb rename to ecommerce/fulfillment/lib/fulfillment/events/order_cancelled.rb index cb2054880..9a937e3f9 100644 --- a/ecommerce/ordering/lib/ordering/events/order_cancelled.rb +++ b/ecommerce/fulfillment/lib/fulfillment/events/order_cancelled.rb @@ -1,4 +1,6 @@ -module Ordering +# frozen_string_literal: true + +module Fulfillment class OrderCancelled < Infra::Event attribute :order_id, Infra::Types::UUID end diff --git a/ecommerce/ordering/lib/ordering/events/order_confirmed.rb b/ecommerce/fulfillment/lib/fulfillment/events/order_confirmed.rb similarity index 64% rename from ecommerce/ordering/lib/ordering/events/order_confirmed.rb rename to ecommerce/fulfillment/lib/fulfillment/events/order_confirmed.rb index cc7ebe1ab..1342816a5 100644 --- a/ecommerce/ordering/lib/ordering/events/order_confirmed.rb +++ b/ecommerce/fulfillment/lib/fulfillment/events/order_confirmed.rb @@ -1,4 +1,6 @@ -module Ordering +# frozen_string_literal: true + +module Fulfillment class OrderConfirmed < Infra::Event attribute :order_id, Infra::Types::UUID end diff --git a/ecommerce/fulfillment/lib/fulfillment/events/order_registered.rb b/ecommerce/fulfillment/lib/fulfillment/events/order_registered.rb new file mode 100644 index 000000000..1fce5c007 --- /dev/null +++ b/ecommerce/fulfillment/lib/fulfillment/events/order_registered.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module Fulfillment + class OrderRegistered < Infra::Event + attribute :order_id, Infra::Types::UUID + end +end diff --git a/ecommerce/fulfillment/lib/fulfillment/on_cancel_order.rb b/ecommerce/fulfillment/lib/fulfillment/on_cancel_order.rb new file mode 100644 index 000000000..91490dcab --- /dev/null +++ b/ecommerce/fulfillment/lib/fulfillment/on_cancel_order.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Fulfillment + class OnCancelOrder + def initialize(event_store) + @repository = Infra::AggregateRootRepository.new(event_store) + end + + def call(command) + @repository.with_aggregate(Order, command.aggregate_id) do |order| + order.cancel + end + end + end +end \ No newline at end of file diff --git a/ecommerce/fulfillment/lib/fulfillment/on_confirm_order.rb b/ecommerce/fulfillment/lib/fulfillment/on_confirm_order.rb new file mode 100644 index 000000000..87b82a377 --- /dev/null +++ b/ecommerce/fulfillment/lib/fulfillment/on_confirm_order.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Fulfillment + class OnConfirmOrder + def initialize(event_store) + @repository = Infra::AggregateRootRepository.new(event_store) + end + + def call(command) + @repository.with_aggregate(Order, command.aggregate_id) do |order| + order.confirm + end + end + end +end diff --git a/ecommerce/fulfillment/lib/fulfillment/on_register_order.rb b/ecommerce/fulfillment/lib/fulfillment/on_register_order.rb new file mode 100644 index 000000000..b9fa5acb7 --- /dev/null +++ b/ecommerce/fulfillment/lib/fulfillment/on_register_order.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Fulfillment + class OnRegisterOrder + def initialize(event_store) + @repository = Infra::AggregateRootRepository.new(event_store) + end + + def call(command) + @repository.with_aggregate(Order, command.aggregate_id) do |order| + order.register + end + end + end +end \ No newline at end of file diff --git a/ecommerce/fulfillment/lib/fulfillment/order.rb b/ecommerce/fulfillment/lib/fulfillment/order.rb new file mode 100644 index 000000000..688ab8f4c --- /dev/null +++ b/ecommerce/fulfillment/lib/fulfillment/order.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +module Fulfillment + class Order + include AggregateRoot + + InvalidState = Class.new(StandardError) + + def initialize(id) + @id = id + end + + def register + raise InvalidState if @state + apply OrderRegistered.new(data: { order_id: @id }) + end + + def confirm + raise InvalidState unless @state.equal?(:new) + apply OrderConfirmed.new(data: { order_id: @id }) + end + + def cancel + raise InvalidState unless @state.equal?(:new) + apply OrderCancelled.new(data: { order_id: @id }) + end + + on OrderRegistered do |event| + @state = :new + end + + on OrderConfirmed do |event| + @state = :confirmed + end + + on OrderCancelled do |event| + @state = :cancelled + end + end +end diff --git a/ecommerce/fulfillment/test/cancel_order_test.rb b/ecommerce/fulfillment/test/cancel_order_test.rb new file mode 100644 index 000000000..55369ac92 --- /dev/null +++ b/ecommerce/fulfillment/test/cancel_order_test.rb @@ -0,0 +1,41 @@ +require_relative "test_helper" + +module Fulfillment + class CancelOrderTest < Test + cover "Fulfillment::OnCancelOrder*" + + def test_not_registered_order_cant_be_cancelled + aggregate_id = SecureRandom.uuid + + assert_raises(Order::InvalidState) do + act(CancelOrder.new(order_id: aggregate_id)) + end + end + + def test_registered_order_can_be_cancelled + aggregate_id = SecureRandom.uuid + stream = "Fulfillment::Order$#{aggregate_id}" + arrange( + RegisterOrder.new(order_id: aggregate_id) + ) + + assert_events( + stream, + OrderCancelled.new(data: { order_id: aggregate_id }) + ) { act(CancelOrder.new(order_id: aggregate_id)) } + end + + def test_confirmed_order_can_not_be_cancelled + aggregate_id = SecureRandom.uuid + + arrange( + RegisterOrder.new(order_id: aggregate_id), + ConfirmOrder.new(order_id: aggregate_id) + ) + + assert_raises(Order::InvalidState) do + act(CancelOrder.new(order_id: aggregate_id)) + end + end + end +end diff --git a/ecommerce/fulfillment/test/confirm_order_test.rb b/ecommerce/fulfillment/test/confirm_order_test.rb new file mode 100644 index 000000000..ec67b49a6 --- /dev/null +++ b/ecommerce/fulfillment/test/confirm_order_test.rb @@ -0,0 +1,41 @@ +require_relative "test_helper" + +module Fulfillment + class ConfirmOrderTest < Test + cover "Fulfillment::OnConfirmOrder*" + + def test_not_registered_order_cant_be_confirmed + aggregate_id = SecureRandom.uuid + + assert_raises(Order::InvalidState) do + act(ConfirmOrder.new(order_id: aggregate_id)) + end + end + + def test_registered_order_can_be_confirmed + aggregate_id = SecureRandom.uuid + stream = "Fulfillment::Order$#{aggregate_id}" + arrange( + RegisterOrder.new(order_id: aggregate_id) + ) + + assert_events( + stream, + OrderConfirmed.new(data: { order_id: aggregate_id }) + ) { act(ConfirmOrder.new(order_id: aggregate_id)) } + end + + def test_confirmed_order_can_not_be_confirmed + aggregate_id = SecureRandom.uuid + + arrange( + RegisterOrder.new(order_id: aggregate_id), + CancelOrder.new(order_id: aggregate_id) + ) + + assert_raises(Order::InvalidState) do + act(ConfirmOrder.new(order_id: aggregate_id)) + end + end + end +end diff --git a/ecommerce/fulfillment/test/register_order_test.rb b/ecommerce/fulfillment/test/register_order_test.rb new file mode 100644 index 000000000..c82a1b3f5 --- /dev/null +++ b/ecommerce/fulfillment/test/register_order_test.rb @@ -0,0 +1,29 @@ +require_relative "test_helper" + +module Fulfillment + class ConfirmOrderTest < Test + cover "Fulfillment::OnRegisterOrder*" + + def test_new_order_can_be_registered + aggregate_id = SecureRandom.uuid + stream = "Fulfillment::Order$#{aggregate_id}" + + assert_events( + stream, + OrderRegistered.new(data: { order_id: aggregate_id }) + ) { act(RegisterOrder.new(order_id: aggregate_id)) } + end + + def test_registered_order_can_not_be_registered_again + aggregate_id = SecureRandom.uuid + + arrange( + RegisterOrder.new(order_id: aggregate_id), + ) + + assert_raises(Order::InvalidState) do + act(RegisterOrder.new(order_id: aggregate_id)) + end + end + end +end \ No newline at end of file diff --git a/ecommerce/fulfillment/test/test_helper.rb b/ecommerce/fulfillment/test/test_helper.rb new file mode 100644 index 000000000..374827131 --- /dev/null +++ b/ecommerce/fulfillment/test/test_helper.rb @@ -0,0 +1,13 @@ +require "minitest/autorun" +require "mutant/minitest/coverage" + +require_relative "../lib/fulfillment" + +module Fulfillment + class Test < Infra::InMemoryTest + def before_setup + super + Configuration.new.call(event_store, command_bus) + end + end +end diff --git a/ecommerce/ordering/lib/ordering.rb b/ecommerce/ordering/lib/ordering.rb index ac818543b..ca4ad0c1c 100644 --- a/ecommerce/ordering/lib/ordering.rb +++ b/ecommerce/ordering/lib/ordering.rb @@ -3,16 +3,12 @@ require_relative "ordering/events/item_removed_from_basket" require_relative "ordering/events/order_placed" require_relative "ordering/events/order_expired" -require_relative "ordering/events/order_confirmed" -require_relative "ordering/events/order_cancelled" require_relative "ordering/events/order_submitted" require_relative "ordering/events/order_rejected" require_relative "ordering/commands/add_item_to_basket" require_relative "ordering/commands/remove_item_from_basket" require_relative "ordering/commands/submit_order" require_relative "ordering/commands/set_order_as_expired" -require_relative "ordering/commands/confirm_order" -require_relative "ordering/commands/cancel_order" require_relative "ordering/commands/accept_order" require_relative "ordering/commands/reject_order" require_relative "ordering/fake_number_generator" @@ -34,8 +30,6 @@ def call(event_store, command_bus) command_bus.register(AddItemToBasket, OnAddItemToBasket.new(event_store)) command_bus.register(RemoveItemFromBasket, OnRemoveItemFromBasket.new(event_store)) command_bus.register(SetOrderAsExpired, OnSetOrderAsExpired.new(event_store)) - command_bus.register(ConfirmOrder, OnConfirmOrder.new(event_store)) - command_bus.register(CancelOrder, OnCancelOrder.new(event_store)) command_bus.register(AcceptOrder, OnAcceptOrder.new(event_store)) command_bus.register(RejectOrder, OnRejectOrder.new(event_store)) end diff --git a/ecommerce/ordering/lib/ordering/order.rb b/ecommerce/ordering/lib/ordering/order.rb index c0aa67e06..84060f700 100644 --- a/ecommerce/ordering/lib/ordering/order.rb +++ b/ecommerce/ordering/lib/ordering/order.rb @@ -4,7 +4,6 @@ class Order InvalidState = Class.new(StandardError) AlreadySubmitted = Class.new(InvalidState) - AlreadyConfirmed = Class.new(InvalidState) NotPlaced = Class.new(InvalidState) OrderHasExpired = Class.new(InvalidState) @@ -46,11 +45,6 @@ def reject ) end - def confirm - raise NotPlaced unless @state.equal?(:placed) - apply OrderConfirmed.new(data: { order_id: @id }) - end - def expire raise AlreadySubmitted unless @state.equal?(:draft) apply OrderExpired.new(data: { order_id: @id }) @@ -71,28 +65,14 @@ def remove_item(product_id) apply ItemRemovedFromBasket.new(data: { order_id: @id, product_id: product_id }) end - def cancel - raise AlreadyConfirmed if @state.equal?(:confirmed) - raise NotPlaced unless @state.equal?(:placed) - apply OrderCancelled.new(data: { order_id: @id }) - end - on OrderPlaced do |event| @state = :placed end - on OrderConfirmed do |event| - @state = :confirmed - end - on OrderExpired do |event| @state = :expired end - on OrderCancelled do |event| - @state = :cancelled - end - on ItemAddedToBasket do |event| @basket.increase_quantity(event.data[:product_id]) end diff --git a/ecommerce/ordering/lib/ordering/service.rb b/ecommerce/ordering/lib/ordering/service.rb index 436e65939..4ab6dde83 100644 --- a/ecommerce/ordering/lib/ordering/service.rb +++ b/ecommerce/ordering/lib/ordering/service.rb @@ -23,30 +23,6 @@ def call(command) end end - class OnCancelOrder - def initialize(event_store) - @repository = Infra::AggregateRootRepository.new(event_store) - end - - def call(command) - @repository.with_aggregate(Order, command.aggregate_id) do |order| - order.cancel - end - end - end - - class OnConfirmOrder - def initialize(event_store) - @repository = Infra::AggregateRootRepository.new(event_store) - end - - def call(command) - @repository.with_aggregate(Order, command.aggregate_id) do |order| - order.confirm - end - end - end - class OnSetOrderAsExpired def initialize(event_store) @repository = Infra::AggregateRootRepository.new(event_store) diff --git a/ecommerce/ordering/test/cancel_order_test.rb b/ecommerce/ordering/test/cancel_order_test.rb deleted file mode 100644 index 784496b97..000000000 --- a/ecommerce/ordering/test/cancel_order_test.rb +++ /dev/null @@ -1,72 +0,0 @@ -require_relative "test_helper" - -module Ordering - class CancelOrderTest < Test - cover "Ordering::CancelOrder*" - - def test_draft_order_cant_be_cancelled - aggregate_id = SecureRandom.uuid - product_id = SecureRandom.uuid - - arrange( - AddItemToBasket.new( - order_id: aggregate_id, - product_id: product_id - ) - ) - - assert_raises(Order::NotPlaced) do - act(CancelOrder.new(order_id: aggregate_id)) - end - end - - def test_submitted_order_can_be_cancelled - aggregate_id = SecureRandom.uuid - stream = "Ordering::Order$#{aggregate_id}" - product_id = SecureRandom.uuid - customer_id = SecureRandom.uuid - - arrange( - AddItemToBasket.new( - order_id: aggregate_id, - product_id: product_id - ), - SubmitOrder.new( - order_id: aggregate_id, - order_number: "2018/12/1", - customer_id: customer_id - ), - AcceptOrder.new(order_id: aggregate_id) - ) - - assert_events( - stream, - OrderCancelled.new(data: { order_id: aggregate_id }) - ) { act(CancelOrder.new(order_id: aggregate_id)) } - end - - def test_confirmed_order_cant_be_cancelled - aggregate_id = SecureRandom.uuid - product_id = SecureRandom.uuid - customer_id = SecureRandom.uuid - - arrange( - AddItemToBasket.new( - order_id: aggregate_id, - product_id: product_id - ), - SubmitOrder.new( - order_id: aggregate_id, - order_number: "2018/12/1", - customer_id: customer_id - ), - AcceptOrder.new(order_id: aggregate_id), - ConfirmOrder.new(order_id: aggregate_id) - ) - - assert_raises(Order::AlreadyConfirmed) do - act(CancelOrder.new(order_id: aggregate_id)) - end - end - end -end diff --git a/ecommerce/ordering/test/confirm_order_test.rb b/ecommerce/ordering/test/confirm_order_test.rb deleted file mode 100644 index 4b0a5c0c0..000000000 --- a/ecommerce/ordering/test/confirm_order_test.rb +++ /dev/null @@ -1,48 +0,0 @@ -require_relative "test_helper" - -module Ordering - class ConfirmOrderTest < Test - cover "Ordering::OnConfirmOrder*" - - def test_draft_order_could_not_be_confirmed - aggregate_id = SecureRandom.uuid - product_id = SecureRandom.uuid - - arrange( - AddItemToBasket.new( - order_id: aggregate_id, - product_id: product_id - ) - ) - assert_raises(Order::NotPlaced) do - act(ConfirmOrder.new(order_id: aggregate_id)) - end - end - - def test_submitted_order_will_be_confirmed - aggregate_id = SecureRandom.uuid - stream = "Ordering::Order$#{aggregate_id}" - product_id = SecureRandom.uuid - customer_id = SecureRandom.uuid - - arrange( - AddItemToBasket.new( - order_id: aggregate_id, - product_id: product_id - ), - SubmitOrder.new( - order_id: aggregate_id, - order_number: "2018/12/1", - customer_id: customer_id - ), - AcceptOrder.new( - order_id: aggregate_id - ) - ) - - assert_events(stream, OrderConfirmed.new(data: { order_id: aggregate_id })) do - act(ConfirmOrder.new(order_id: aggregate_id)) - end - end - end -end diff --git a/ecommerce/ordering/test/order_test.rb b/ecommerce/ordering/test/order_test.rb index 8cb8eda5a..342290ef2 100644 --- a/ecommerce/ordering/test/order_test.rb +++ b/ecommerce/ordering/test/order_test.rb @@ -40,51 +40,27 @@ def test_disallowed_order_state_transitions draft_order.submit(NumberGenerator.new.call) assert_raises(Order::InvalidState) { draft_order.accept } assert_raises(Order::InvalidState) { draft_order.reject } - assert_raises(Order::InvalidState) { draft_order.cancel } - assert_raises(Order::InvalidState) { draft_order.confirm } draft_order.expire assert_raises(Order::InvalidState) { submitted_order.submit(NumberGenerator.new.call) } submitted_order.accept submitted_order.reject - assert_raises(Order::InvalidState) { submitted_order.cancel } - assert_raises(Order::InvalidState) { submitted_order.confirm } assert_raises(Order::InvalidState) { submitted_order.expire } placed_order.submit(NumberGenerator.new.call) assert_raises(Order::InvalidState) { placed_order.accept } assert_raises(Order::InvalidState) { placed_order.reject } - placed_order.cancel - placed_order.confirm assert_raises(Order::InvalidState) { placed_order.expire } - confirmed_order.submit(NumberGenerator.new.call) - assert_raises(Order::InvalidState) { confirmed_order.accept } - assert_raises(Order::InvalidState) { confirmed_order.reject } - assert_raises(Order::InvalidState) { confirmed_order.cancel } - assert_raises(Order::InvalidState) { confirmed_order.confirm } - assert_raises(Order::InvalidState) { confirmed_order.expire } - assert_raises(Order::InvalidState) { expired_order.submit(NumberGenerator.new.call) } assert_raises(Order::InvalidState) { rejected_order.accept } assert_raises(Order::InvalidState) { rejected_order.reject } - assert_raises(Order::InvalidState) { rejected_order.cancel } - assert_raises(Order::InvalidState) { rejected_order.confirm } rejected_order.expire assert_raises(Order::InvalidState) { expired_order.submit(NumberGenerator.new.call) } assert_raises(Order::InvalidState) { expired_order.accept } assert_raises(Order::InvalidState) { expired_order.reject } - assert_raises(Order::InvalidState) { expired_order.cancel } - assert_raises(Order::InvalidState) { expired_order.confirm } assert_raises(Order::InvalidState) { expired_order.expire } - - cancelled_order.submit(NumberGenerator.new.call) - assert_raises(Order::InvalidState) { cancelled_order.accept } - assert_raises(Order::InvalidState) { cancelled_order.reject } - assert_raises(Order::InvalidState) { cancelled_order.confirm } - assert_raises(Order::InvalidState) { cancelled_order.cancel } - cancelled_order.expire end def draft_order @@ -109,22 +85,10 @@ def rejected_order end end - def confirmed_order - placed_order.tap do |order| - order.confirm - end - end - def expired_order draft_order.tap do |order| order.expire end end - - def cancelled_order - submitted_order.tap do |order| - order.reject - end - end end end diff --git a/ecommerce/processes/lib/processes.rb b/ecommerce/processes/lib/processes.rb index fdd385299..153c90df6 100644 --- a/ecommerce/processes/lib/processes.rb +++ b/ecommerce/processes/lib/processes.rb @@ -7,6 +7,7 @@ require_relative "../../shipping/lib/shipping" require_relative "../../taxes/lib/taxes" require_relative "../../invoicing/lib/invoicing" +require_relative "../../fulfillment/lib/fulfillment" require_relative 'processes/confirm_order_on_payment_captured' require_relative 'processes/release_payment_process' require_relative 'processes/shipment_process' @@ -32,6 +33,7 @@ def call(event_store, command_bus) set_invoice_payment_date_when_order_confirmed(event_store, command_bus) enable_product_name_sync(event_store, command_bus) confirm_order_on_payment_captured(event_store, command_bus) + register_order_on_order_placed(event_store, command_bus) enable_release_payment_process(event_store, command_bus) enable_shipment_process(event_store, command_bus) @@ -76,7 +78,7 @@ def enable_release_payment_process(event_store, command_bus) to: [ Ordering::OrderPlaced, Ordering::OrderExpired, - Ordering::OrderConfirmed, + Fulfillment::OrderConfirmed, Payments::PaymentAuthorized, Payments::PaymentReleased ] @@ -116,7 +118,7 @@ def set_invoice_payment_date_when_order_confirmed(event_store, command_bus) ) ) end, - to: [Ordering::OrderConfirmed] + to: [Fulfillment::OrderConfirmed] ) end @@ -129,10 +131,23 @@ def enable_reservation_process(event_store, command_bus) ReservationProcess.new, to: [ Ordering::OrderSubmitted, - Ordering::OrderCancelled, - Ordering::OrderConfirmed + Fulfillment::OrderCancelled, + Fulfillment::OrderConfirmed ] ) end + + def register_order_on_order_placed(event_store, command_bus) + event_store.subscribe( + ->(event) do + command_bus.call( + Fulfillment::RegisterOrder.new( + order_id: event.data.fetch(:order_id) + ) + ) + end, + to: [Ordering::OrderPlaced] + ) + end end end diff --git a/ecommerce/processes/lib/processes/confirm_order_on_payment_captured.rb b/ecommerce/processes/lib/processes/confirm_order_on_payment_captured.rb index 225c8f67e..e1d671dac 100644 --- a/ecommerce/processes/lib/processes/confirm_order_on_payment_captured.rb +++ b/ecommerce/processes/lib/processes/confirm_order_on_payment_captured.rb @@ -7,7 +7,7 @@ def initialize(command_bus) def call(event) order_id = event.data.fetch(:order_id) - command_bus.call(Ordering::ConfirmOrder.new(order_id: order_id)) + command_bus.call(Fulfillment::ConfirmOrder.new(order_id: order_id)) end private diff --git a/ecommerce/processes/lib/processes/release_payment_process.rb b/ecommerce/processes/lib/processes/release_payment_process.rb index d36edea88..e85a338b5 100644 --- a/ecommerce/processes/lib/processes/release_payment_process.rb +++ b/ecommerce/processes/lib/processes/release_payment_process.rb @@ -50,7 +50,7 @@ def call(event) @order_id = event.data.fetch(:order_id) when Ordering::OrderExpired @order = :expired - when Ordering::OrderConfirmed + when Fulfillment::OrderConfirmed @order = :confirmed end end diff --git a/ecommerce/processes/lib/processes/reservation_process.rb b/ecommerce/processes/lib/processes/reservation_process.rb index 9bc563b96..1194cccea 100644 --- a/ecommerce/processes/lib/processes/reservation_process.rb +++ b/ecommerce/processes/lib/processes/reservation_process.rb @@ -18,9 +18,9 @@ def call(event) else accept_order(state) end - when 'Ordering::OrderCancelled' + when 'Fulfillment::OrderCancelled' release_stock(state) - when 'Ordering::OrderConfirmed' + when 'Fulfillment::OrderConfirmed' dispatch_stock(state) end end @@ -83,7 +83,7 @@ def call(event) when Ordering::OrderSubmitted @order_lines = event.data.fetch(:order_lines) @order_id = event.data.fetch(:order_id) - when Ordering::OrderCancelled, Ordering::OrderConfirmed + when Fulfillment::OrderCancelled, Fulfillment::OrderConfirmed @reserved_product_ids = order_lines.keys end end diff --git a/ecommerce/processes/lib/processes/shipment_process.rb b/ecommerce/processes/lib/processes/shipment_process.rb index 1af6018f1..0a04dae74 100644 --- a/ecommerce/processes/lib/processes/shipment_process.rb +++ b/ecommerce/processes/lib/processes/shipment_process.rb @@ -9,7 +9,7 @@ def initialize(event_store, command_bus) Shipping::ShippingAddressAddedToShipment, Shipping::ShipmentSubmitted, Ordering::OrderPlaced, - Ordering::OrderConfirmed + Fulfillment::OrderConfirmed ] ) end @@ -62,7 +62,7 @@ def call(event) when Ordering::OrderPlaced @order = :placed @order_id = event.data.fetch(:order_id) - when Ordering::OrderConfirmed + when Fulfillment::OrderConfirmed @order = :confirmed end end diff --git a/ecommerce/processes/test/order_confirmation_test.rb b/ecommerce/processes/test/order_confirmation_test.rb index d9aa5fc9a..3278e67f7 100644 --- a/ecommerce/processes/test/order_confirmation_test.rb +++ b/ecommerce/processes/test/order_confirmation_test.rb @@ -9,7 +9,7 @@ def test_payment_confirms_order given([payment_authorized]).each do |event| process.call(event) end - assert_command(Ordering::ConfirmOrder.new(order_id: order_id)) + assert_command(Fulfillment::ConfirmOrder.new(order_id: order_id)) end end end diff --git a/ecommerce/processes/test/reservation_process_test.rb b/ecommerce/processes/test/reservation_process_test.rb index 93109c356..a71aa122c 100644 --- a/ecommerce/processes/test/reservation_process_test.rb +++ b/ecommerce/processes/test/reservation_process_test.rb @@ -98,7 +98,7 @@ def order_submitted end def order_cancelled - Ordering::OrderCancelled.new( + Fulfillment::OrderCancelled.new( data: { order_id: order_id } diff --git a/ecommerce/processes/test/test_helper.rb b/ecommerce/processes/test/test_helper.rb index 5d97c23c1..2c446bc06 100644 --- a/ecommerce/processes/test/test_helper.rb +++ b/ecommerce/processes/test/test_helper.rb @@ -78,11 +78,11 @@ def order_expired end def order_confirmed - Ordering::OrderConfirmed.new(data: { order_id: order_id }) + Fulfillment::OrderConfirmed.new(data: { order_id: order_id }) end def order_cancelled - Ordering::OrderCancelled.new(data: { order_id: order_id }) + Fulfillment::OrderCancelled.new(data: { order_id: order_id }) end def payment_authorized diff --git a/rails_application/app/controllers/orders_controller.rb b/rails_application/app/controllers/orders_controller.rb index cda74715b..87aa853a1 100644 --- a/rails_application/app/controllers/orders_controller.rb +++ b/rails_application/app/controllers/orders_controller.rb @@ -102,7 +102,7 @@ def pay end def cancel - command_bus.(Ordering::CancelOrder.new(order_id: params[:id])) + command_bus.(Fulfillment::CancelOrder.new(order_id: params[:id])) redirect_to root_path, notice: "Order cancelled" end diff --git a/rails_application/app/read_models/client_orders/configuration.rb b/rails_application/app/read_models/client_orders/configuration.rb index 08184d705..f2b162783 100644 --- a/rails_application/app/read_models/client_orders/configuration.rb +++ b/rails_application/app/read_models/client_orders/configuration.rb @@ -31,9 +31,9 @@ def value class Configuration def call(event_store) event_store.subscribe(ExpireOrder, to: [Ordering::OrderExpired]) - event_store.subscribe(CancelOrder, to: [Ordering::OrderCancelled]) + event_store.subscribe(CancelOrder, to: [Fulfillment::OrderCancelled]) event_store.subscribe(SubmitOrder, to: [Ordering::OrderPlaced]) - event_store.subscribe(ConfirmOrder, to: [Ordering::OrderConfirmed]) + event_store.subscribe(ConfirmOrder, to: [Fulfillment::OrderConfirmed]) event_store.subscribe(AddItemToOrder, to: [Ordering::ItemAddedToBasket]) event_store.subscribe(RemoveItemFromOrder, to: [Ordering::ItemRemovedFromBasket]) @@ -46,7 +46,7 @@ def call(event_store) event_store.subscribe(UpdateDiscount, to: [Pricing::PercentageDiscountSet, Pricing::PercentageDiscountChanged]) event_store.subscribe(ResetDiscount, to: [Pricing::PercentageDiscountReset]) event_store.subscribe(UpdateOrderTotalValue, to: [Pricing::OrderTotalValueCalculated]) - event_store.subscribe(UpdatePaidOrdersSummary, to: [Ordering::OrderConfirmed]) + event_store.subscribe(UpdatePaidOrdersSummary, to: [Fulfillment::OrderConfirmed]) end end end diff --git a/rails_application/app/read_models/customers/configuration.rb b/rails_application/app/read_models/customers/configuration.rb index 1b6970770..b3465237f 100644 --- a/rails_application/app/read_models/customers/configuration.rb +++ b/rails_application/app/read_models/customers/configuration.rb @@ -7,7 +7,7 @@ class Configuration def call(event_store) event_store.subscribe(RegisterCustomer.new, to: [Crm::CustomerRegistered]) event_store.subscribe(PromoteToVip.new, to: [Crm::CustomerPromotedToVip]) - event_store.subscribe(UpdatePaidOrdersSummary.new, to: [Ordering::OrderConfirmed]) + event_store.subscribe(UpdatePaidOrdersSummary.new, to: [Fulfillment::OrderConfirmed]) event_store.subscribe(ConnectAccount.new, to: [Authentication::AccountConnectedToClient]) end end diff --git a/rails_application/app/read_models/orders/configuration.rb b/rails_application/app/read_models/orders/configuration.rb index 526690460..29fe28bbe 100644 --- a/rails_application/app/read_models/orders/configuration.rb +++ b/rails_application/app/read_models/orders/configuration.rb @@ -44,8 +44,8 @@ def call(event_store) event_store.subscribe(AssignCustomerToOrder.new, to: [Crm::CustomerAssignedToOrder]) event_store.subscribe(SubmitOrder.new, to: [Ordering::OrderPlaced]) event_store.subscribe(ExpireOrder.new, to: [Ordering::OrderExpired]) - event_store.subscribe(ConfirmOrder.new, to: [Ordering::OrderConfirmed]) - event_store.subscribe(CancelOrder.new, to: [Ordering::OrderCancelled]) + event_store.subscribe(ConfirmOrder.new, to: [Fulfillment::OrderConfirmed]) + event_store.subscribe(CancelOrder.new, to: [Fulfillment::OrderCancelled]) subscribe( @@ -58,11 +58,11 @@ def call(event_store) ) subscribe( ->(event) { broadcast_order_state_change(event.data.fetch(:order_id), "Paid") }, - [Ordering::OrderConfirmed] + [Fulfillment::OrderConfirmed] ) subscribe( ->(event) { broadcast_order_state_change(event.data.fetch(:order_id), "Cancelled") }, - [Ordering::OrderCancelled] + [Fulfillment::OrderCancelled] ) end diff --git a/rails_application/test/client_orders/order_cancelled_test.rb b/rails_application/test/client_orders/order_cancelled_test.rb index 8820b4a18..70e474fc4 100644 --- a/rails_application/test/client_orders/order_cancelled_test.rb +++ b/rails_application/test/client_orders/order_cancelled_test.rb @@ -26,7 +26,7 @@ def test_order_confirmed run_command(Ordering::SubmitOrder.new(order_id: order_id, order_number: order_number)) event_store.publish( - Ordering::OrderCancelled.new( + Fulfillment::OrderCancelled.new( data: { order_id: order_id } diff --git a/rails_application/test/client_orders/order_paid_test.rb b/rails_application/test/client_orders/order_paid_test.rb index a28a949c0..cb126741b 100644 --- a/rails_application/test/client_orders/order_paid_test.rb +++ b/rails_application/test/client_orders/order_paid_test.rb @@ -35,7 +35,7 @@ def test_order_confirmed ) event_store.publish( - Ordering::OrderConfirmed.new( + Fulfillment::OrderConfirmed.new( data: { order_id: order_id } diff --git a/rails_application/test/client_orders/update_paid_orders_summary_test.rb b/rails_application/test/client_orders/update_paid_orders_summary_test.rb index d9023df04..6090e1c80 100644 --- a/rails_application/test/client_orders/update_paid_orders_summary_test.rb +++ b/rails_application/test/client_orders/update_paid_orders_summary_test.rb @@ -52,7 +52,7 @@ def confirm_order(customer_id, order_id, total_amount) ) run_command(Ordering::SubmitOrder.new(order_id: order_id, order_number: order_number)) event_store.publish( - order_confirmed = Ordering::OrderConfirmed.new( + order_confirmed = Fulfillment::OrderConfirmed.new( data: { order_id: order_id } diff --git a/rails_application/test/customers/update_paid_orders_summary_test.rb b/rails_application/test/customers/update_paid_orders_summary_test.rb index 21aebf400..cf1db6f43 100644 --- a/rails_application/test/customers/update_paid_orders_summary_test.rb +++ b/rails_application/test/customers/update_paid_orders_summary_test.rb @@ -50,7 +50,7 @@ def confirm_order(customer_id, order_id, total_amount) ) run_command(Ordering::SubmitOrder.new(order_id: order_id, order_number: order_number)) event_store.publish( - order_confirmed = Ordering::OrderConfirmed.new( + order_confirmed = Fulfillment::OrderConfirmed.new( data: { order_id: order_id } diff --git a/rails_application/test/integration/orders_test.rb b/rails_application/test/integration/orders_test.rb index 696fa1d1c..b37bcce16 100644 --- a/rails_application/test/integration/orders_test.rb +++ b/rails_application/test/integration/orders_test.rb @@ -299,7 +299,7 @@ def assert_res_browser_order_history get "/res/api/streams/Orders%24all/relationships/events" event_names = JSON.load(body).fetch("data").map { |data| data.fetch("attributes").fetch("event_type") } - assert(event_names.include?("Ordering::OrderConfirmed")) + assert(event_names.include?("Fulfillment::OrderConfirmed")) assert(event_names.include?("Ordering::ItemAddedToBasket")) assert(event_names.include?("Pricing::OrderTotalValueCalculated")) assert(event_names.include?("Ordering::OrderPlaced")) diff --git a/rails_application/test/orders/order_cancelled_test.rb b/rails_application/test/orders/order_cancelled_test.rb index 1b840a859..e075fd797 100644 --- a/rails_application/test/orders/order_cancelled_test.rb +++ b/rails_application/test/orders/order_cancelled_test.rb @@ -25,7 +25,7 @@ def test_cancel_confirmed_order run_command(Ordering::SubmitOrder.new(order_id: order_id, order_number: order_number)) - order_cancelled = Ordering::OrderCancelled.new( + order_cancelled = Fulfillment::OrderCancelled.new( data: { order_id: order_id } diff --git a/rails_application/test/orders/order_paid_test.rb b/rails_application/test/orders/order_paid_test.rb index 0e5d00dc4..c28553ad6 100644 --- a/rails_application/test/orders/order_paid_test.rb +++ b/rails_application/test/orders/order_paid_test.rb @@ -23,7 +23,7 @@ def test_order_confirmed ) event_store.publish(Pricing::OrderTotalValueCalculated.new(data: { order_id: order_id, discounted_amount: 0, total_amount: 10 })) - order_confirmed = Ordering::OrderConfirmed.new( + order_confirmed = Fulfillment::OrderConfirmed.new( data: { order_id: order_id } diff --git a/rails_application/test/orders/order_placed_test.rb b/rails_application/test/orders/order_placed_test.rb index f6bc0c570..1a69cf23f 100644 --- a/rails_application/test/orders/order_placed_test.rb +++ b/rails_application/test/orders/order_placed_test.rb @@ -54,54 +54,6 @@ def test_create_when_not_exists assert event_store.event_in_stream?(order_placed.event_id, "Orders$all") end - def test_skip_when_duplicated - event_store = Rails.configuration.event_store - - product_id = SecureRandom.uuid - run_command( - ProductCatalog::RegisterProduct.new( - product_id: product_id - ) - ) - run_command(Pricing::SetPrice.new(product_id: product_id, price: 20)) - - order_id = SecureRandom.uuid - order_number = Ordering::FakeNumberGenerator::FAKE_NUMBER - event_store.publish( - Ordering::ItemAddedToBasket.new( - data: { - order_id: order_id, - product_id: product_id, - quantity_before: 0 - } - ) - ) - event_store.publish( - Ordering::OrderPlaced.new( - data: { - order_id: order_id, - order_number: order_number, - order_lines: { product_id => 1 } - } - ) - ) - - event_store.publish( - Ordering::OrderPlaced.new( - data: { - order_id: order_id, - order_number: order_number, - order_lines: { product_id => 1 } - } - ) - ) - - assert_equal(Order.count, 1) - order = Order.find_by(uid: order_id) - assert_equal(order.state, "Submitted") - assert_equal(order.number, order_number) - end - private def action_broadcast_args(order_uid, state)