diff --git a/ecommerce/authentication/.mutant.yml b/ecommerce/authentication/.mutant.yml deleted file mode 100644 index 8c5b2b23f..000000000 --- a/ecommerce/authentication/.mutant.yml +++ /dev/null @@ -1,10 +0,0 @@ -requires: - - ./test/test_helper -integration: minitest -coverage_criteria: - process_abort: true -matcher: - subjects: - - Authentication* - ignore: - - Authentication::Configuration#call diff --git a/ecommerce/authentication/Gemfile b/ecommerce/authentication/Gemfile deleted file mode 100644 index 8fd887144..000000000 --- a/ecommerce/authentication/Gemfile +++ /dev/null @@ -1,4 +0,0 @@ -source "https://rubygems.org" - -eval_gemfile "../../infra/Gemfile.test" -gem "infra", path: "../../infra" \ No newline at end of file diff --git a/ecommerce/authentication/Gemfile.lock b/ecommerce/authentication/Gemfile.lock deleted file mode 100644 index 4a73abff2..000000000 --- a/ecommerce/authentication/Gemfile.lock +++ /dev/null @@ -1,119 +0,0 @@ -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.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.13.0) - ruby_event_store (= 2.13.0) - arkency-command_bus (0.4.1) - concurrent-ruby - ast (2.4.2) - base64 (0.2.0) - bigdecimal (3.1.4) - concurrent-ruby (1.2.2) - connection_pool (2.4.1) - diff-lcs (1.5.0) - drb (2.2.0) - ruby2_keywords - 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.1) - concurrent-ruby (~> 1.0) - dry-core (~> 1.0) - dry-inflector (~> 1.0) - dry-logic (~> 1.4) - zeitwerk (~> 2.6) - i18n (1.14.1) - 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.8) - rake (13.1.0) - redis-client (0.19.0) - connection_pool - regexp_parser (2.8.3) - ruby2_keywords (0.0.5) - ruby_event_store (2.13.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.0) - concurrent-ruby (< 2) - connection_pool (>= 2.3.0) - rack (>= 2.2.4) - redis-client (>= 0.14.0) - sorbet-runtime (0.5.11190) - tzinfo (2.0.6) - concurrent-ruby (~> 1.0) - unparser (0.6.12) - diff-lcs (~> 1.3) - parser (>= 3.2.2.4) - zeitwerk (2.6.12) - -PLATFORMS - arm64-darwin-20 - arm64-darwin-21 - ruby - x86_64-darwin-20 - x86_64-linux - -DEPENDENCIES - infra! - minitest (= 5.15.0)! - mutant-license! - mutant-minitest (= 0.11.26)! - -BUNDLED WITH - 2.5.9 diff --git a/ecommerce/authentication/Makefile b/ecommerce/authentication/Makefile deleted file mode 100644 index 23850fab1..000000000 --- a/ecommerce/authentication/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -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/authentication/README.md b/ecommerce/authentication/README.md deleted file mode 100644 index c8a17ba12..000000000 --- a/ecommerce/authentication/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Authentication - -#### Up and running - -``` -make install test mutate -``` diff --git a/ecommerce/authentication/lib/authentication.rb b/ecommerce/authentication/lib/authentication.rb deleted file mode 100644 index fe28d3c1d..000000000 --- a/ecommerce/authentication/lib/authentication.rb +++ /dev/null @@ -1,25 +0,0 @@ -require "infra" -require_relative "authentication/commands/connect_account_to_client" -require_relative "authentication/commands/set_login" -require_relative "authentication/commands/set_password_hash" -require_relative "authentication/commands/register_account" -require_relative "authentication/events/account_connected_to_client" -require_relative "authentication/events/account_registered" -require_relative "authentication/events/login_set" -require_relative "authentication/events/password_hash_set" -require_relative "authentication/account_service" -require_relative "authentication/account" - -module Authentication - class Configuration - def call(event_store, command_bus) - command_bus.register(RegisterAccount, RegisterAccountHandler.new(event_store)) - command_bus.register(SetLogin, SetLoginHandler.new(event_store)) - command_bus.register(SetPasswordHash, SetPasswordHashHandler.new(event_store)) - command_bus.register( - ConnectAccountToClient, - ConnectAccountToClientHandler.new(event_store) - ) - end - end -end diff --git a/ecommerce/authentication/lib/authentication/account.rb b/ecommerce/authentication/lib/authentication/account.rb deleted file mode 100644 index c790f4f82..000000000 --- a/ecommerce/authentication/lib/authentication/account.rb +++ /dev/null @@ -1,47 +0,0 @@ -module Authentication - class Account - include AggregateRoot - - AlreadyRegistered = Class.new(StandardError) - - def initialize(id) - @id = id - end - - def register - raise AlreadyRegistered if @registered - - apply AccountRegistered.new(data: { account_id: @id }) - end - - def set_login(login) - apply LoginSet.new(data: { account_id: @id, login: login }) - end - - def set_password_hash(password_hash) - apply PasswordHashSet.new(data: { account_id: @id, password_hash: password_hash }) - end - - def connect_client(client_id) - apply AccountConnectedToClient.new(data: { account_id: @id, client_id: client_id }) - end - - private - - on AccountRegistered do |event| - @registered = true - end - - on LoginSet do |event| - @login = event.data[:login] - end - - on PasswordHashSet do |event| - @password_hash = event.data[:password_hash] - end - - on AccountConnectedToClient do |event| - @client_id = event.data[:client_id] - end - end -end diff --git a/ecommerce/authentication/lib/authentication/account_service.rb b/ecommerce/authentication/lib/authentication/account_service.rb deleted file mode 100644 index 1cfabdfd1..000000000 --- a/ecommerce/authentication/lib/authentication/account_service.rb +++ /dev/null @@ -1,49 +0,0 @@ -module Authentication - class RegisterAccountHandler - def initialize(event_store) - @repository = Infra::AggregateRootRepository.new(event_store) - end - - def call(command) - @repository.with_aggregate(Account, command.aggregate_id) do |account| - account.register - end - end - end - - class SetLoginHandler - def initialize(event_store) - @repository = Infra::AggregateRootRepository.new(event_store) - end - - def call(command) - @repository.with_aggregate(Account, command.aggregate_id) do |account| - account.set_login(command.login) - end - end - end - - class SetPasswordHashHandler - def initialize(event_store) - @repository = Infra::AggregateRootRepository.new(event_store) - end - - def call(command) - @repository.with_aggregate(Account, command.aggregate_id) do |account| - account.set_password_hash(command.password_hash) - end - end - end - - class ConnectAccountToClientHandler - def initialize(event_store) - @repository = Infra::AggregateRootRepository.new(event_store) - end - - def call(command) - @repository.with_aggregate(Account, command.aggregate_id) do |account| - account.connect_client(command.client_id) - end - end - end -end diff --git a/ecommerce/authentication/lib/authentication/commands/connect_account_to_client.rb b/ecommerce/authentication/lib/authentication/commands/connect_account_to_client.rb deleted file mode 100644 index 3cea61001..000000000 --- a/ecommerce/authentication/lib/authentication/commands/connect_account_to_client.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Authentication - class ConnectAccountToClient < Infra::Command - attribute :account_id, Infra::Types::UUID - attribute :client_id, Infra::Types::UUID - alias aggregate_id account_id - end -end diff --git a/ecommerce/authentication/lib/authentication/commands/register_account.rb b/ecommerce/authentication/lib/authentication/commands/register_account.rb deleted file mode 100644 index c69492ca4..000000000 --- a/ecommerce/authentication/lib/authentication/commands/register_account.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Authentication - class RegisterAccount < Infra::Command - attribute :account_id, Infra::Types::UUID - alias aggregate_id account_id - end -end diff --git a/ecommerce/authentication/lib/authentication/commands/set_login.rb b/ecommerce/authentication/lib/authentication/commands/set_login.rb deleted file mode 100644 index 1df2f94e2..000000000 --- a/ecommerce/authentication/lib/authentication/commands/set_login.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Authentication - class SetLogin < Infra::Command - attribute :account_id, Infra::Types::UUID - attribute :login, Infra::Types::String - alias aggregate_id account_id - end -end diff --git a/ecommerce/authentication/lib/authentication/commands/set_password_hash.rb b/ecommerce/authentication/lib/authentication/commands/set_password_hash.rb deleted file mode 100644 index 15670dbdb..000000000 --- a/ecommerce/authentication/lib/authentication/commands/set_password_hash.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Authentication - class SetPasswordHash < Infra::Command - attribute :account_id, Infra::Types::UUID - attribute :password_hash, Infra::Types::String - alias aggregate_id account_id - end -end diff --git a/ecommerce/authentication/lib/authentication/events/account_connected_to_client.rb b/ecommerce/authentication/lib/authentication/events/account_connected_to_client.rb deleted file mode 100644 index 2efbffa07..000000000 --- a/ecommerce/authentication/lib/authentication/events/account_connected_to_client.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Authentication - class AccountConnectedToClient < Infra::Event - attribute :account_id, Infra::Types::UUID - attribute :client_id, Infra::Types::UUID - end -end diff --git a/ecommerce/authentication/lib/authentication/events/account_registered.rb b/ecommerce/authentication/lib/authentication/events/account_registered.rb deleted file mode 100644 index f9f6f203f..000000000 --- a/ecommerce/authentication/lib/authentication/events/account_registered.rb +++ /dev/null @@ -1,5 +0,0 @@ -module Authentication - class AccountRegistered < Infra::Event - attribute :account_id, Infra::Types::UUID - end -end diff --git a/ecommerce/authentication/lib/authentication/events/login_set.rb b/ecommerce/authentication/lib/authentication/events/login_set.rb deleted file mode 100644 index 8dfc4187f..000000000 --- a/ecommerce/authentication/lib/authentication/events/login_set.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Authentication - class LoginSet < Infra::Event - attribute :account_id, Infra::Types::UUID - attribute :login, Infra::Types::String - end -end diff --git a/ecommerce/authentication/lib/authentication/events/password_hash_set.rb b/ecommerce/authentication/lib/authentication/events/password_hash_set.rb deleted file mode 100644 index 366133de1..000000000 --- a/ecommerce/authentication/lib/authentication/events/password_hash_set.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Authentication - class PasswordHashSet < Infra::Event - attribute :account_id, Infra::Types::UUID - attribute :password_hash, Infra::Types::String - end -end diff --git a/ecommerce/authentication/test/connect_account_to_client_test.rb b/ecommerce/authentication/test/connect_account_to_client_test.rb deleted file mode 100644 index 0cbd7aeec..000000000 --- a/ecommerce/authentication/test/connect_account_to_client_test.rb +++ /dev/null @@ -1,20 +0,0 @@ -require_relative "test_helper" - -module Authentication - class ConnectAccountToClientTest < Test - cover "Authentication*" - - def test_client_id_should_get_set - account_id = SecureRandom.uuid - client_id = SecureRandom.uuid - - act(RegisterAccount.new(account_id: account_id)) - - account_connected_to_client = AccountConnectedToClient.new(data: { account_id: account_id, client_id: client_id }) - - assert_events("Authentication::Account$#{account_id}", account_connected_to_client) do - run_command(ConnectAccountToClient.new(account_id: account_id, client_id: client_id)) - end - end - end -end diff --git a/ecommerce/authentication/test/register_account_test.rb b/ecommerce/authentication/test/register_account_test.rb deleted file mode 100644 index 612985fee..000000000 --- a/ecommerce/authentication/test/register_account_test.rb +++ /dev/null @@ -1,32 +0,0 @@ -require_relative "test_helper" - -module Authentication - class RegisterAccountTest < Test - cover "Authentication*" - - def setup - @uid = SecureRandom.uuid - @data = { account_id: @uid } - end - - def test_account_should_get_registered - account_registered = AccountRegistered.new(data: @data) - assert_events("Authentication::Account$#{@uid}", account_registered) do - register_account(@uid) - end - end - - def test_should_not_allow_for_double_registration - assert_raises(Account::AlreadyRegistered) do - register_account(@uid) - register_account(@uid) - end - end - - private - - def register_account(account_id) - run_command(RegisterAccount.new(account_id: account_id)) - end - end -end diff --git a/ecommerce/authentication/test/set_login_test.rb b/ecommerce/authentication/test/set_login_test.rb deleted file mode 100644 index b47c32d53..000000000 --- a/ecommerce/authentication/test/set_login_test.rb +++ /dev/null @@ -1,19 +0,0 @@ -require_relative "test_helper" - -module Authentication - class SetLoginTest < Test - cover "Authentication*" - - def test_login_should_get_set - account_id = SecureRandom.uuid - - act(RegisterAccount.new(account_id: account_id)) - - login_set = LoginSet.new(data: { account_id: account_id, login: fake_login }) - - assert_events("Authentication::Account$#{account_id}", login_set) do - run_command(SetLogin.new(account_id: account_id, login: fake_login)) - end - end - end -end diff --git a/ecommerce/authentication/test/set_password_hash_test.rb b/ecommerce/authentication/test/set_password_hash_test.rb deleted file mode 100644 index 88e8e414e..000000000 --- a/ecommerce/authentication/test/set_password_hash_test.rb +++ /dev/null @@ -1,20 +0,0 @@ -require_relative "test_helper" - -module Authentication - class SetPasswordHashTest < Test - cover "Authentication*" - - def test_password_hash_should_get_set - account_id = SecureRandom.uuid - password_hash = SecureRandom.hex(10) - - act(RegisterAccount.new(account_id: account_id)) - - password_hash_set = PasswordHashSet.new(data: { account_id: account_id, password_hash: password_hash }) - - assert_events("Authentication::Account$#{account_id}", password_hash_set) do - run_command(SetPasswordHash.new(account_id: account_id, password_hash: password_hash)) - end - end - end -end diff --git a/ecommerce/authentication/test/test_helper.rb b/ecommerce/authentication/test/test_helper.rb deleted file mode 100644 index bc727dbb5..000000000 --- a/ecommerce/authentication/test/test_helper.rb +++ /dev/null @@ -1,19 +0,0 @@ -require "minitest/autorun" -require "mutant/minitest/coverage" - -require_relative "../lib/authentication" - -module Authentication - class Test < Infra::InMemoryTest - def before_setup - super() - Configuration.new.call(event_store, command_bus) - end - - private - - def fake_login - "fake_login" - end - end -end diff --git a/ecommerce/configuration.rb b/ecommerce/configuration.rb deleted file mode 100644 index 2af4d70bf..000000000 --- a/ecommerce/configuration.rb +++ /dev/null @@ -1,50 +0,0 @@ -require_relative "authentication/lib/authentication" -require_relative "ordering/lib/ordering" -require_relative "pricing/lib/pricing" -require_relative "product_catalog/lib/product_catalog" -require_relative "crm/lib/crm" -require_relative "payments/lib/payments" -require_relative "inventory/lib/inventory" -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 - class Configuration - def initialize(number_generator: nil, payment_gateway: nil, available_vat_rates: []) - @number_generator = number_generator - @payment_gateway = payment_gateway - @available_vat_rates = available_vat_rates - end - - def call(event_store, command_bus) - configure_bounded_contexts(event_store, command_bus) - configure_processes(event_store, command_bus) - end - - def configure_bounded_contexts(event_store, command_bus) - raise ArgumentError.new( - "Neither number_generator nor payment_gateway can be null" - ) if @number_generator.nil? || @payment_gateway.nil? - [ - Authentication::Configuration.new, - Ordering::Configuration.new(@number_generator), - Crm::Configuration.new, - Inventory::Configuration.new, - Invoicing::Configuration.new, - Payments::Configuration.new(@payment_gateway), - Shipping::Configuration.new, - Pricing::Configuration.new, - Taxes::Configuration.new(@available_vat_rates), - ProductCatalog::Configuration.new, - Fulfillment::Configuration.new - ].each { |c| c.call(event_store, command_bus) } - end - - def configure_processes(event_store, command_bus) - Processes::Configuration.new.call(event_store, command_bus) - end - end -end diff --git a/ecommerce/crm/.mutant.yml b/ecommerce/crm/.mutant.yml deleted file mode 100644 index 952b042b0..000000000 --- a/ecommerce/crm/.mutant.yml +++ /dev/null @@ -1,11 +0,0 @@ -requires: - - ./test/test_helper -integration: minitest -coverage_criteria: - process_abort: true -matcher: - subjects: - - Crm* - ignore: - - Crm::Configuration#call - diff --git a/ecommerce/crm/Gemfile b/ecommerce/crm/Gemfile deleted file mode 100644 index 8fd887144..000000000 --- a/ecommerce/crm/Gemfile +++ /dev/null @@ -1,4 +0,0 @@ -source "https://rubygems.org" - -eval_gemfile "../../infra/Gemfile.test" -gem "infra", path: "../../infra" \ No newline at end of file diff --git a/ecommerce/crm/Gemfile.lock b/ecommerce/crm/Gemfile.lock deleted file mode 100644 index 4a73abff2..000000000 --- a/ecommerce/crm/Gemfile.lock +++ /dev/null @@ -1,119 +0,0 @@ -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.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.13.0) - ruby_event_store (= 2.13.0) - arkency-command_bus (0.4.1) - concurrent-ruby - ast (2.4.2) - base64 (0.2.0) - bigdecimal (3.1.4) - concurrent-ruby (1.2.2) - connection_pool (2.4.1) - diff-lcs (1.5.0) - drb (2.2.0) - ruby2_keywords - 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.1) - concurrent-ruby (~> 1.0) - dry-core (~> 1.0) - dry-inflector (~> 1.0) - dry-logic (~> 1.4) - zeitwerk (~> 2.6) - i18n (1.14.1) - 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.8) - rake (13.1.0) - redis-client (0.19.0) - connection_pool - regexp_parser (2.8.3) - ruby2_keywords (0.0.5) - ruby_event_store (2.13.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.0) - concurrent-ruby (< 2) - connection_pool (>= 2.3.0) - rack (>= 2.2.4) - redis-client (>= 0.14.0) - sorbet-runtime (0.5.11190) - tzinfo (2.0.6) - concurrent-ruby (~> 1.0) - unparser (0.6.12) - diff-lcs (~> 1.3) - parser (>= 3.2.2.4) - zeitwerk (2.6.12) - -PLATFORMS - arm64-darwin-20 - arm64-darwin-21 - ruby - x86_64-darwin-20 - x86_64-linux - -DEPENDENCIES - infra! - minitest (= 5.15.0)! - mutant-license! - mutant-minitest (= 0.11.26)! - -BUNDLED WITH - 2.5.9 diff --git a/ecommerce/crm/Makefile b/ecommerce/crm/Makefile deleted file mode 100644 index 23850fab1..000000000 --- a/ecommerce/crm/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -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/crm/README.md b/ecommerce/crm/README.md deleted file mode 100644 index 0fe6e4a09..000000000 --- a/ecommerce/crm/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# CRM - -[![Build Status](https://github.com/RailsEventStore/cqrs-es-sample-with-res/workflows/crm/badge.svg)](https://github.com/RailsEventStore/cqrs-es-sample-with-res/actions/workflows/crm.yml) - -#### Up and running - -``` -make install test mutate -``` diff --git a/ecommerce/crm/lib/crm.rb b/ecommerce/crm/lib/crm.rb deleted file mode 100644 index 1876d7a00..000000000 --- a/ecommerce/crm/lib/crm.rb +++ /dev/null @@ -1,22 +0,0 @@ -require "infra" -require_relative "crm/commands/promote_customer_to_vip" -require_relative "crm/commands/register_customer" -require_relative "crm/commands/assign_customer_to_order" -require_relative "crm/events/customer_promoted_to_vip" -require_relative "crm/events/customer_registered" -require_relative "crm/events/customer_assigned_to_order.rb" -require_relative "crm/customer_service" -require_relative "crm/customer" -require_relative "crm/order_service" -require_relative "crm/order" - -module Crm - class Configuration - - def call(event_store, command_bus) - command_bus.register(RegisterCustomer, OnRegistration.new(event_store)) - command_bus.register(PromoteCustomerToVip, OnPromoteCustomerToVip.new(event_store)) - command_bus.register(AssignCustomerToOrder, OnSetCustomer.new(event_store)) - end - end -end diff --git a/ecommerce/crm/lib/crm/commands/assign_customer_to_order.rb b/ecommerce/crm/lib/crm/commands/assign_customer_to_order.rb deleted file mode 100644 index 727b9386e..000000000 --- a/ecommerce/crm/lib/crm/commands/assign_customer_to_order.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Crm - class AssignCustomerToOrder < Infra::Command - attribute :customer_id, Infra::Types::UUID - attribute :order_id, Infra::Types::UUID - alias aggregate_id order_id - end -end diff --git a/ecommerce/crm/lib/crm/commands/promote_customer_to_vip.rb b/ecommerce/crm/lib/crm/commands/promote_customer_to_vip.rb deleted file mode 100644 index a2bcae947..000000000 --- a/ecommerce/crm/lib/crm/commands/promote_customer_to_vip.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Crm - class PromoteCustomerToVip < Infra::Command - attribute :customer_id, Infra::Types::UUID - alias aggregate_id customer_id - end -end diff --git a/ecommerce/crm/lib/crm/commands/register_customer.rb b/ecommerce/crm/lib/crm/commands/register_customer.rb deleted file mode 100644 index c5693bd43..000000000 --- a/ecommerce/crm/lib/crm/commands/register_customer.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Crm - class RegisterCustomer < Infra::Command - attribute :customer_id, Infra::Types::UUID - attribute :name, Infra::Types::String - alias aggregate_id customer_id - end -end diff --git a/ecommerce/crm/lib/crm/customer.rb b/ecommerce/crm/lib/crm/customer.rb deleted file mode 100644 index 31c697d6b..000000000 --- a/ecommerce/crm/lib/crm/customer.rb +++ /dev/null @@ -1,40 +0,0 @@ -module Crm - class Customer - include AggregateRoot - - AlreadyVip = Class.new(StandardError) - AlreadyRegistered = Class.new(StandardError) - NotExists = Class.new(StandardError) - - def initialize(id) - @id = id - end - - def register(name) - raise AlreadyRegistered if @registered - apply CustomerRegistered.new( - data: { - customer_id: @id, - name: name - } - ) - end - - def promote_to_vip - raise AlreadyVip if @vip - apply CustomerPromotedToVip.new( - data: { - customer_id: @id - } - ) - end - - on CustomerRegistered do |event| - @registered = true - end - - on CustomerPromotedToVip do |event| - @vip = true - end - end -end diff --git a/ecommerce/crm/lib/crm/customer_service.rb b/ecommerce/crm/lib/crm/customer_service.rb deleted file mode 100644 index a89cbd750..000000000 --- a/ecommerce/crm/lib/crm/customer_service.rb +++ /dev/null @@ -1,27 +0,0 @@ -module Crm - - class OnRegistration - def initialize(event_store) - @repository = Infra::AggregateRootRepository.new(event_store) - end - - def call(command) - @repository.with_aggregate(Customer, command.aggregate_id) do |customer| - customer.register(command.name) - end - end - end - - class OnPromoteCustomerToVip - def initialize(event_store) - @repository = Infra::AggregateRootRepository.new(event_store) - end - - def call(command) - @repository.with_aggregate(Customer, command.aggregate_id) do |customer| - customer.promote_to_vip - end - end - end - -end \ No newline at end of file diff --git a/ecommerce/crm/lib/crm/events/customer_assigned_to_order.rb b/ecommerce/crm/lib/crm/events/customer_assigned_to_order.rb deleted file mode 100644 index dcbc9eda2..000000000 --- a/ecommerce/crm/lib/crm/events/customer_assigned_to_order.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Crm - class CustomerAssignedToOrder < Infra::Event - attribute :customer_id, Infra::Types::UUID - attribute :order_id, Infra::Types::UUID - end -end diff --git a/ecommerce/crm/lib/crm/events/customer_promoted_to_vip.rb b/ecommerce/crm/lib/crm/events/customer_promoted_to_vip.rb deleted file mode 100644 index b73906d2a..000000000 --- a/ecommerce/crm/lib/crm/events/customer_promoted_to_vip.rb +++ /dev/null @@ -1,5 +0,0 @@ -module Crm - class CustomerPromotedToVip < Infra::Event - attribute :customer_id, Infra::Types::UUID - end -end diff --git a/ecommerce/crm/lib/crm/events/customer_registered.rb b/ecommerce/crm/lib/crm/events/customer_registered.rb deleted file mode 100644 index 8e34598d1..000000000 --- a/ecommerce/crm/lib/crm/events/customer_registered.rb +++ /dev/null @@ -1,8 +0,0 @@ -module Crm - class CustomerRegistered < Infra::Event - attribute :customer_id, Infra::Types::UUID - attribute :name, Infra::Types::String - end -end - - diff --git a/ecommerce/crm/lib/crm/order.rb b/ecommerce/crm/lib/crm/order.rb deleted file mode 100644 index be6bc955d..000000000 --- a/ecommerce/crm/lib/crm/order.rb +++ /dev/null @@ -1,21 +0,0 @@ -module Crm - class Order - include AggregateRoot - CustomerAlreadyAssigned = Class.new(StandardError) - - def initialize(id) - @id = id - end - - def set_customer(customer_id) - raise CustomerAlreadyAssigned if @customer_id - apply CustomerAssignedToOrder.new(data: { order_id: @id, customer_id: customer_id }) - end - - private - - on CustomerAssignedToOrder do |event| - @customer_id = event.data[:customer_id] - end - end -end \ No newline at end of file diff --git a/ecommerce/crm/lib/crm/order_service.rb b/ecommerce/crm/lib/crm/order_service.rb deleted file mode 100644 index edf7d62df..000000000 --- a/ecommerce/crm/lib/crm/order_service.rb +++ /dev/null @@ -1,22 +0,0 @@ -module Crm - class OnSetCustomer - def initialize(event_store) - @repository = Infra::AggregateRootRepository.new(event_store) - @event_store = event_store - end - - def call(command) - raise Customer::NotExists unless customer_exists?(command.customer_id) - @repository.with_aggregate(Order, command.aggregate_id) do |order| - order.set_customer(command.customer_id) - end - end - - private - - def customer_exists?(customer_id) - customer_stream = @repository.stream_name(Customer, customer_id) - !@event_store.read.stream(customer_stream).count.eql?(0) - end - end -end \ No newline at end of file diff --git a/ecommerce/crm/test/assign_customer_to_order_test.rb b/ecommerce/crm/test/assign_customer_to_order_test.rb deleted file mode 100644 index cbddf33ed..000000000 --- a/ecommerce/crm/test/assign_customer_to_order_test.rb +++ /dev/null @@ -1,43 +0,0 @@ -require_relative "test_helper" - -module Crm - class AssignCustomerToOrderTest < Test - cover "Crm*" - - def test_customer_should_get_assigned - customer_id = SecureRandom.uuid - order_id = SecureRandom.uuid - register_customer(customer_id, fake_name) - expected_event = CustomerAssignedToOrder.new(data: {customer_id: customer_id, order_id: order_id}) - assert_events("Crm::Order$#{order_id}", expected_event) do - assign_customer_to_order(order_id, customer_id) - end - end - - def test_customer_should_not_get_assigned_twice - customer_id = SecureRandom.uuid - order_id = SecureRandom.uuid - register_customer(customer_id, fake_name) - assign_customer_to_order(order_id, customer_id) - assert_raises(Order::CustomerAlreadyAssigned) do - assign_customer_to_order(order_id, customer_id) - end - end - - def test_customer_should_not_get_assigned_if_does_not_exist - customer_id = SecureRandom.uuid - another_customer_id = SecureRandom.uuid - order_id = SecureRandom.uuid - register_customer(another_customer_id, fake_name) - assert_raises(Customer::NotExists) do - assign_customer_to_order(order_id, customer_id) - end - end - - private - - def assign_customer_to_order(order_id, customer_id) - run_command(AssignCustomerToOrder.new(order_id: order_id, customer_id: customer_id)) - end - end -end \ No newline at end of file diff --git a/ecommerce/crm/test/promote_client_to_vip_test.rb b/ecommerce/crm/test/promote_client_to_vip_test.rb deleted file mode 100644 index d82209d0b..000000000 --- a/ecommerce/crm/test/promote_client_to_vip_test.rb +++ /dev/null @@ -1,45 +0,0 @@ -require_relative "test_helper" - -module Crm - class PromoteCustomerToVipTest < Test - cover "Crm*" - - def test_should_not_allow_for_marking_vip_as_vip_again - customer_id = SecureRandom.uuid - - arrange( - RegisterCustomer.new( - customer_id: customer_id, - name: fake_name - ) - ) - - assert_raises(Customer::AlreadyVip) do - promote_to_vip(customer_id) - promote_to_vip(customer_id) - end - end - - def test_should_publish_event - customer_id = SecureRandom.uuid - - arrange( - RegisterCustomer.new( - customer_id: customer_id, - name: fake_name - ) - ) - - customer_promoted_to_vip = CustomerPromotedToVip.new(data: {customer_id: customer_id}) - assert_events("Crm::Customer$#{customer_id}", customer_promoted_to_vip) do - promote_to_vip(customer_id) - end - end - - private - - def promote_to_vip(uid) - run_command(PromoteCustomerToVip.new(customer_id: uid)) - end - end -end diff --git a/ecommerce/crm/test/registration_test.rb b/ecommerce/crm/test/registration_test.rb deleted file mode 100644 index db312ab1d..000000000 --- a/ecommerce/crm/test/registration_test.rb +++ /dev/null @@ -1,28 +0,0 @@ -require_relative "test_helper" - -module Crm - class RegistrationTest < Test - cover "Crm*" - - def test_customer_should_get_registered - uid = SecureRandom.uuid - register_customer(uid, fake_name) - end - - def test_should_not_allow_for_double_registration - uid = SecureRandom.uuid - assert_raises(Customer::AlreadyRegistered) do - register_customer(uid, fake_name) - register_customer(uid, fake_name) - end - end - - def test_should_publish_event - uid = SecureRandom.uuid - customer_registered = CustomerRegistered.new(data: {customer_id: uid, name: fake_name}) - assert_events("Crm::Customer$#{uid}", customer_registered) do - register_customer(uid, fake_name) - end - end - end -end diff --git a/ecommerce/crm/test/test_helper.rb b/ecommerce/crm/test/test_helper.rb deleted file mode 100644 index feec8f051..000000000 --- a/ecommerce/crm/test/test_helper.rb +++ /dev/null @@ -1,23 +0,0 @@ -require "minitest/autorun" -require "mutant/minitest/coverage" - -require_relative "../lib/crm" - -module Crm - class Test < Infra::InMemoryTest - def before_setup - super() - Configuration.new.call(event_store, command_bus) - end - - private - - def register_customer(uid, name) - run_command(RegisterCustomer.new(customer_id: uid, name: name)) - end - - def fake_name - "Fake name" - end - end -end diff --git a/ecommerce/fulfillment/.mutant.yml b/ecommerce/fulfillment/.mutant.yml deleted file mode 100644 index 6d1df49be..000000000 --- a/ecommerce/fulfillment/.mutant.yml +++ /dev/null @@ -1,12 +0,0 @@ -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 deleted file mode 100644 index 8fd887144..000000000 --- a/ecommerce/fulfillment/Gemfile +++ /dev/null @@ -1,4 +0,0 @@ -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 deleted file mode 100644 index 87553b254..000000000 --- a/ecommerce/fulfillment/Gemfile.lock +++ /dev/null @@ -1,116 +0,0 @@ -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 deleted file mode 100644 index 23850fab1..000000000 --- a/ecommerce/fulfillment/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -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 deleted file mode 100644 index 66ea3b558..000000000 --- a/ecommerce/fulfillment/lib/fulfillment.rb +++ /dev/null @@ -1,21 +0,0 @@ -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/fulfillment/lib/fulfillment/commands/cancel_order.rb b/ecommerce/fulfillment/lib/fulfillment/commands/cancel_order.rb deleted file mode 100644 index 0d1dd8b70..000000000 --- a/ecommerce/fulfillment/lib/fulfillment/commands/cancel_order.rb +++ /dev/null @@ -1,9 +0,0 @@ -# frozen_string_literal: true - -module Fulfillment - class CancelOrder < Infra::Command - attribute :order_id, Infra::Types::UUID - - alias aggregate_id order_id - end -end diff --git a/ecommerce/fulfillment/lib/fulfillment/commands/confirm_order.rb b/ecommerce/fulfillment/lib/fulfillment/commands/confirm_order.rb deleted file mode 100644 index 729debae4..000000000 --- a/ecommerce/fulfillment/lib/fulfillment/commands/confirm_order.rb +++ /dev/null @@ -1,9 +0,0 @@ -# frozen_string_literal: true - -module Fulfillment - class ConfirmOrder < Infra::Command - attribute :order_id, Infra::Types::UUID - - alias aggregate_id order_id - end -end diff --git a/ecommerce/fulfillment/lib/fulfillment/commands/register_order.rb b/ecommerce/fulfillment/lib/fulfillment/commands/register_order.rb deleted file mode 100644 index 18bb18370..000000000 --- a/ecommerce/fulfillment/lib/fulfillment/commands/register_order.rb +++ /dev/null @@ -1,9 +0,0 @@ -# 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/fulfillment/lib/fulfillment/events/order_cancelled.rb b/ecommerce/fulfillment/lib/fulfillment/events/order_cancelled.rb deleted file mode 100644 index 9a937e3f9..000000000 --- a/ecommerce/fulfillment/lib/fulfillment/events/order_cancelled.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -module Fulfillment - class OrderCancelled < Infra::Event - attribute :order_id, Infra::Types::UUID - end -end diff --git a/ecommerce/fulfillment/lib/fulfillment/events/order_confirmed.rb b/ecommerce/fulfillment/lib/fulfillment/events/order_confirmed.rb deleted file mode 100644 index 1342816a5..000000000 --- a/ecommerce/fulfillment/lib/fulfillment/events/order_confirmed.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -module Fulfillment - class OrderConfirmed < Infra::Event - attribute :order_id, Infra::Types::UUID - end -end diff --git a/ecommerce/fulfillment/lib/fulfillment/events/order_registered.rb b/ecommerce/fulfillment/lib/fulfillment/events/order_registered.rb deleted file mode 100644 index 1fce5c007..000000000 --- a/ecommerce/fulfillment/lib/fulfillment/events/order_registered.rb +++ /dev/null @@ -1,7 +0,0 @@ -# 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 deleted file mode 100644 index 91490dcab..000000000 --- a/ecommerce/fulfillment/lib/fulfillment/on_cancel_order.rb +++ /dev/null @@ -1,15 +0,0 @@ -# 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 deleted file mode 100644 index 87b82a377..000000000 --- a/ecommerce/fulfillment/lib/fulfillment/on_confirm_order.rb +++ /dev/null @@ -1,15 +0,0 @@ -# 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 deleted file mode 100644 index b9fa5acb7..000000000 --- a/ecommerce/fulfillment/lib/fulfillment/on_register_order.rb +++ /dev/null @@ -1,15 +0,0 @@ -# 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 deleted file mode 100644 index 688ab8f4c..000000000 --- a/ecommerce/fulfillment/lib/fulfillment/order.rb +++ /dev/null @@ -1,40 +0,0 @@ -# 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 deleted file mode 100644 index 55369ac92..000000000 --- a/ecommerce/fulfillment/test/cancel_order_test.rb +++ /dev/null @@ -1,41 +0,0 @@ -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 deleted file mode 100644 index ec67b49a6..000000000 --- a/ecommerce/fulfillment/test/confirm_order_test.rb +++ /dev/null @@ -1,41 +0,0 @@ -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 deleted file mode 100644 index c82a1b3f5..000000000 --- a/ecommerce/fulfillment/test/register_order_test.rb +++ /dev/null @@ -1,29 +0,0 @@ -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 deleted file mode 100644 index 374827131..000000000 --- a/ecommerce/fulfillment/test/test_helper.rb +++ /dev/null @@ -1,13 +0,0 @@ -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/inventory/.mutant.yml b/ecommerce/inventory/.mutant.yml deleted file mode 100644 index 075692f1f..000000000 --- a/ecommerce/inventory/.mutant.yml +++ /dev/null @@ -1,12 +0,0 @@ -requires: - - ./test/test_helper -integration: minitest -coverage_criteria: - process_abort: true -matcher: - subjects: - - Inventory* - ignore: - - Inventory::Test* - - Inventory::Configuration#initialize - - Inventory::Configuration#call \ No newline at end of file diff --git a/ecommerce/inventory/Gemfile b/ecommerce/inventory/Gemfile deleted file mode 100644 index 8fd887144..000000000 --- a/ecommerce/inventory/Gemfile +++ /dev/null @@ -1,4 +0,0 @@ -source "https://rubygems.org" - -eval_gemfile "../../infra/Gemfile.test" -gem "infra", path: "../../infra" \ No newline at end of file diff --git a/ecommerce/inventory/Gemfile.lock b/ecommerce/inventory/Gemfile.lock deleted file mode 100644 index 4a73abff2..000000000 --- a/ecommerce/inventory/Gemfile.lock +++ /dev/null @@ -1,119 +0,0 @@ -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.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.13.0) - ruby_event_store (= 2.13.0) - arkency-command_bus (0.4.1) - concurrent-ruby - ast (2.4.2) - base64 (0.2.0) - bigdecimal (3.1.4) - concurrent-ruby (1.2.2) - connection_pool (2.4.1) - diff-lcs (1.5.0) - drb (2.2.0) - ruby2_keywords - 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.1) - concurrent-ruby (~> 1.0) - dry-core (~> 1.0) - dry-inflector (~> 1.0) - dry-logic (~> 1.4) - zeitwerk (~> 2.6) - i18n (1.14.1) - 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.8) - rake (13.1.0) - redis-client (0.19.0) - connection_pool - regexp_parser (2.8.3) - ruby2_keywords (0.0.5) - ruby_event_store (2.13.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.0) - concurrent-ruby (< 2) - connection_pool (>= 2.3.0) - rack (>= 2.2.4) - redis-client (>= 0.14.0) - sorbet-runtime (0.5.11190) - tzinfo (2.0.6) - concurrent-ruby (~> 1.0) - unparser (0.6.12) - diff-lcs (~> 1.3) - parser (>= 3.2.2.4) - zeitwerk (2.6.12) - -PLATFORMS - arm64-darwin-20 - arm64-darwin-21 - ruby - x86_64-darwin-20 - x86_64-linux - -DEPENDENCIES - infra! - minitest (= 5.15.0)! - mutant-license! - mutant-minitest (= 0.11.26)! - -BUNDLED WITH - 2.5.9 diff --git a/ecommerce/inventory/Makefile b/ecommerce/inventory/Makefile deleted file mode 100644 index 23850fab1..000000000 --- a/ecommerce/inventory/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -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/inventory/README.md b/ecommerce/inventory/README.md deleted file mode 100644 index a05e5cffb..000000000 --- a/ecommerce/inventory/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# Inventory - -[![Build Status](https://github.com/RailsEventStore/cqrs-es-sample-with-res/workflows/inventory/badge.svg)](https://github.com/RailsEventStore/cqrs-es-sample-with-res/actions/workflows/inventory.yml) - -#### Up and running - -``` -make install test mutate -``` diff --git a/ecommerce/inventory/lib/inventory.rb b/ecommerce/inventory/lib/inventory.rb deleted file mode 100644 index fe432c851..000000000 --- a/ecommerce/inventory/lib/inventory.rb +++ /dev/null @@ -1,36 +0,0 @@ -require "infra" -require_relative "inventory/commands/release" -require_relative "inventory/commands/supply" -require_relative "inventory/commands/reserve" -require_relative "inventory/commands/dispatch" -require_relative "inventory/events/stock_level_changed" -require_relative "inventory/events/stock_released" -require_relative "inventory/events/stock_reserved" -require_relative "inventory/events/availability_changed" -require_relative "inventory/inventory_entry_service" -require_relative "inventory/inventory_entry" - -module Inventory - class Configuration - def call(event_store, command_bus) - inventory = InventoryEntryService.new(event_store) - - command_bus.register( - Reserve, - inventory.method(:reserve) - ) - command_bus.register( - Release, - inventory.method(:release) - ) - command_bus.register( - Supply, - inventory.public_method(:supply) - ) - command_bus.register( - Dispatch, - inventory.public_method(:dispatch) - ) - end - end -end diff --git a/ecommerce/inventory/lib/inventory/commands/dispatch.rb b/ecommerce/inventory/lib/inventory/commands/dispatch.rb deleted file mode 100644 index 1db4643b8..000000000 --- a/ecommerce/inventory/lib/inventory/commands/dispatch.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Inventory - class Dispatch < Infra::Command - attribute :product_id, Infra::Types::UUID - attribute :quantity, Infra::Types::Coercible::Integer.constrained(gteq: 1) - end -end diff --git a/ecommerce/inventory/lib/inventory/commands/release.rb b/ecommerce/inventory/lib/inventory/commands/release.rb deleted file mode 100644 index d105f6ad2..000000000 --- a/ecommerce/inventory/lib/inventory/commands/release.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Inventory - class Release < Infra::Command - attribute :product_id, Infra::Types::UUID - attribute :quantity, Infra::Types::Coercible::Integer.constrained(gteq: 1) - end -end diff --git a/ecommerce/inventory/lib/inventory/commands/reserve.rb b/ecommerce/inventory/lib/inventory/commands/reserve.rb deleted file mode 100644 index 04f57849d..000000000 --- a/ecommerce/inventory/lib/inventory/commands/reserve.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Inventory - class Reserve < Infra::Command - attribute :product_id, Infra::Types::UUID - attribute :quantity, Infra::Types::Coercible::Integer.constrained(gteq: 1) - end -end diff --git a/ecommerce/inventory/lib/inventory/commands/supply.rb b/ecommerce/inventory/lib/inventory/commands/supply.rb deleted file mode 100644 index ecb5c1165..000000000 --- a/ecommerce/inventory/lib/inventory/commands/supply.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Inventory - class Supply < Infra::Command - attribute :product_id, Infra::Types::UUID - attribute :quantity, Infra::Types::Coercible::Integer.constrained(gteq: 1) - end -end diff --git a/ecommerce/inventory/lib/inventory/events/availability_changed.rb b/ecommerce/inventory/lib/inventory/events/availability_changed.rb deleted file mode 100644 index 00bc02de7..000000000 --- a/ecommerce/inventory/lib/inventory/events/availability_changed.rb +++ /dev/null @@ -1,4 +0,0 @@ -module Inventory - class AvailabilityChanged < Infra::Event - end -end diff --git a/ecommerce/inventory/lib/inventory/events/stock_level_changed.rb b/ecommerce/inventory/lib/inventory/events/stock_level_changed.rb deleted file mode 100644 index b5623110e..000000000 --- a/ecommerce/inventory/lib/inventory/events/stock_level_changed.rb +++ /dev/null @@ -1,4 +0,0 @@ -module Inventory - class StockLevelChanged < Infra::Event - end -end diff --git a/ecommerce/inventory/lib/inventory/events/stock_released.rb b/ecommerce/inventory/lib/inventory/events/stock_released.rb deleted file mode 100644 index 8d62e01df..000000000 --- a/ecommerce/inventory/lib/inventory/events/stock_released.rb +++ /dev/null @@ -1,4 +0,0 @@ -module Inventory - class StockReleased < Infra::Event - end -end diff --git a/ecommerce/inventory/lib/inventory/events/stock_reserved.rb b/ecommerce/inventory/lib/inventory/events/stock_reserved.rb deleted file mode 100644 index 72ea5bf66..000000000 --- a/ecommerce/inventory/lib/inventory/events/stock_reserved.rb +++ /dev/null @@ -1,4 +0,0 @@ -module Inventory - class StockReserved < Infra::Event - end -end diff --git a/ecommerce/inventory/lib/inventory/inventory_entry.rb b/ecommerce/inventory/lib/inventory/inventory_entry.rb deleted file mode 100644 index d1d11f08d..000000000 --- a/ecommerce/inventory/lib/inventory/inventory_entry.rb +++ /dev/null @@ -1,91 +0,0 @@ -module Inventory - class InventoryEntry - include AggregateRoot - - InventoryNotAvailable = Class.new(StandardError) - InventoryNotEvenReserved = Class.new(StandardError) - - def initialize(product_id) - @product_id = product_id - @reserved = 0 - end - - def supply(quantity) - apply StockLevelChanged.new( - data: { - product_id: @product_id, - quantity: quantity, - stock_level: (@in_stock || 0) + quantity - } - ) - apply_availability_changed - end - - def dispatch(quantity) - apply StockLevelChanged.new( - data: { - product_id: @product_id, - quantity: -quantity, - stock_level: @in_stock - quantity - } - ) if stock_level_defined? - apply_availability_changed - end - - def reserve(quantity) - raise InventoryNotAvailable if stock_level_defined? && quantity > availability - apply StockReserved.new( - data: { - product_id: @product_id, - quantity: quantity - } - ) - apply_availability_changed - end - - def release(quantity) - raise InventoryNotEvenReserved if quantity > @reserved - apply StockReleased.new( - data: { - product_id: @product_id, - quantity: quantity - } - ) - apply_availability_changed - end - - private - - def apply_availability_changed - apply AvailabilityChanged.new( - data: { - product_id: @product_id, - available: availability - } - ) if stock_level_defined? - end - - on StockLevelChanged do |event| - @in_stock = event.data.fetch(:stock_level) - end - - on StockReserved do |event| - @reserved += event.data.fetch(:quantity) - end - - on StockReleased do |event| - @reserved -= event.data.fetch(:quantity) - end - - on AvailabilityChanged do |_| - end - - def availability - @in_stock - @reserved - end - - def stock_level_defined? - !@in_stock.nil? - end - end -end diff --git a/ecommerce/inventory/lib/inventory/inventory_entry_service.rb b/ecommerce/inventory/lib/inventory/inventory_entry_service.rb deleted file mode 100644 index 5d5147601..000000000 --- a/ecommerce/inventory/lib/inventory/inventory_entry_service.rb +++ /dev/null @@ -1,39 +0,0 @@ -module Inventory - class InventoryEntryService - def initialize(event_store) - @repository = Infra::AggregateRootRepository.new(event_store) - end - - def supply(command) - with_inventory_entry(command.product_id) do |entry| - entry.supply(command.quantity) - end - end - - def dispatch(command) - with_inventory_entry(command.product_id) do |entry| - entry.dispatch(command.quantity) - end - end - - def reserve(command) - with_inventory_entry(command.product_id) do |entry| - entry.reserve(command.quantity) - end - end - - def release(command) - with_inventory_entry(command.product_id) do |entry| - entry.release(command.quantity) - end - end - - private - - def with_inventory_entry(product_id) - @repository.with_aggregate(InventoryEntry, product_id) do |entry| - yield(entry) - end - end - end -end diff --git a/ecommerce/inventory/test/dispatch_test.rb b/ecommerce/inventory/test/dispatch_test.rb deleted file mode 100644 index 5483d7673..000000000 --- a/ecommerce/inventory/test/dispatch_test.rb +++ /dev/null @@ -1,30 +0,0 @@ -require_relative "test_helper" - -module Inventory - class DispatchTest < Test - def test_nothing_changes_when_stock_level_is_undefined - product_id = SecureRandom.uuid - assert_events(inventory_entry_stream(product_id)) do - act(dispatch(product_id, 1)) - end - end - - def test_stock_level_changes_with_dispatch_command - product_id = SecureRandom.uuid - arrange(supply(product_id, 1)) - assert_events( - inventory_entry_stream(product_id), - StockLevelChanged.new( - data: { - product_id: product_id, - quantity: -1, - stock_level: 0 - } - ), - AvailabilityChanged.new(data: { product_id: product_id, available: 0 }) - ) do - act(dispatch(product_id, 1)) - end - end - end -end diff --git a/ecommerce/inventory/test/release_test.rb b/ecommerce/inventory/test/release_test.rb deleted file mode 100644 index 8d35021cc..000000000 --- a/ecommerce/inventory/test/release_test.rb +++ /dev/null @@ -1,40 +0,0 @@ -require_relative "test_helper" - -module Inventory - class ReleaseTest < Test - def test_stock_gets_released_when_reserved_and_stock_level_undefined - product_id = SecureRandom.uuid - - arrange(reserve(product_id, 1)) - assert_events( - inventory_entry_stream(product_id), - StockReleased.new(data: { product_id: product_id, quantity: 1 }) - ) do - act(Release.new(product_id: product_id, quantity: 1)) - end - end - - def test_stock_gets_released_when_reserved_and_stock_level_defined - product_id = SecureRandom.uuid - - arrange(supply(product_id, 1), reserve(product_id, 1)) - assert_events( - inventory_entry_stream(product_id), - StockReleased.new(data: { product_id: product_id, quantity: 1 }), - AvailabilityChanged.new(data: { product_id: product_id, available: 1 }) - ) do - act(Release.new(product_id: product_id, quantity: 1)) - end - end - - def test_stock_does_not_get_released_when_not_reserved - product_id = SecureRandom.uuid - - assert_raises( - InventoryEntry::InventoryNotEvenReserved - ) do - act(Release.new(product_id: product_id, quantity: 1)) - end - end - end -end diff --git a/ecommerce/inventory/test/reserve_test.rb b/ecommerce/inventory/test/reserve_test.rb deleted file mode 100644 index 89a900c55..000000000 --- a/ecommerce/inventory/test/reserve_test.rb +++ /dev/null @@ -1,38 +0,0 @@ -require_relative "test_helper" - -module Inventory - class ReserveTest < Test - def test_stock_gets_reserved_when_available - product_id = SecureRandom.uuid - arrange(supply(product_id, 1)) - - assert_events( - inventory_entry_stream(product_id), - StockReserved.new(data: { product_id: product_id, quantity: 1 }), - AvailabilityChanged.new(data: { product_id: product_id, available: 0 }) - ) do - act(reserve(product_id, 1)) - end - end - - def test_stock_gets_reserved_when_stock_level_undefined - product_id = SecureRandom.uuid - - assert_events( - inventory_entry_stream(product_id), - StockReserved.new(data: { product_id: product_id, quantity: 1 }) - ) do - act(reserve(product_id, 1)) - end - end - - def test_raises_when_stock_unavailable - product_id = SecureRandom.uuid - arrange(supply(product_id, 1)) - - assert_raises(InventoryEntry::InventoryNotAvailable) do - act(reserve(product_id, 2)) - end - end - end -end diff --git a/ecommerce/inventory/test/supply_test.rb b/ecommerce/inventory/test/supply_test.rb deleted file mode 100644 index 7815e544f..000000000 --- a/ecommerce/inventory/test/supply_test.rb +++ /dev/null @@ -1,33 +0,0 @@ -require_relative "test_helper" - -module Inventory - class SupplyTest < Test - def test_stock_level_changes_with_supply_command - product_id = SecureRandom.uuid - assert_events( - inventory_entry_stream(product_id), - StockLevelChanged.new( - data: { - product_id: product_id, - quantity: 1, - stock_level: 1 - } - ), - AvailabilityChanged.new( - data: { product_id: product_id, available: 1 } - ) - ) { act(supply(product_id, 1)) } - assert_events( - inventory_entry_stream(product_id), - StockLevelChanged.new( - data: { - product_id: product_id, - quantity: 1, - stock_level: 2 - } - ), - AvailabilityChanged.new(data: { product_id: product_id, available: 2 }) - ) { act(supply(product_id, 1)) } - end - end -end diff --git a/ecommerce/inventory/test/test_helper.rb b/ecommerce/inventory/test/test_helper.rb deleted file mode 100644 index 3b3901c49..000000000 --- a/ecommerce/inventory/test/test_helper.rb +++ /dev/null @@ -1,39 +0,0 @@ -require "minitest/autorun" -require "mutant/minitest/coverage" - -require_relative "../lib/inventory" - -module Inventory - class Test < Infra::InMemoryTest - cover "Inventory*" - - def before_setup - super - Configuration.new.call(event_store, command_bus) - end - - def inventory_entry_stream(product_id) - "Inventory::InventoryEntry$#{product_id}" - end - - def reserve(product_id, quantity) - Reserve.new(product_id: product_id, quantity: quantity) - end - - def release(product_id, quantity) - Release.new(product_id: product_id, quantity: quantity) - end - - def dispatch(product_id, quantity) - Dispatch.new(product_id: product_id, quantity: quantity) - end - - def supply(product_id, quantity) - Supply.new(product_id: product_id, quantity: quantity) - end - - def cancel_reservation(order_id) - Release.new(order_id: order_id) - end - end -end diff --git a/ecommerce/invoicing/.mutant.yml b/ecommerce/invoicing/.mutant.yml deleted file mode 100644 index 751c1e676..000000000 --- a/ecommerce/invoicing/.mutant.yml +++ /dev/null @@ -1,14 +0,0 @@ -requires: - - ./test/test_helper -integration: minitest -coverage_criteria: - process_abort: true -matcher: - subjects: - - Invoicing* - ignore: - - Invoicing::Configuration* - - Invoicing::Test* - - Invoicing::InvoiceItemTitleCatalog* - - Invoicing::InvoiceService#initialize - - Invoicing::FakeConcurrentInvoiceNumberGenerator#next_number \ No newline at end of file diff --git a/ecommerce/invoicing/Gemfile b/ecommerce/invoicing/Gemfile deleted file mode 100644 index 8fd887144..000000000 --- a/ecommerce/invoicing/Gemfile +++ /dev/null @@ -1,4 +0,0 @@ -source "https://rubygems.org" - -eval_gemfile "../../infra/Gemfile.test" -gem "infra", path: "../../infra" \ No newline at end of file diff --git a/ecommerce/invoicing/Gemfile.lock b/ecommerce/invoicing/Gemfile.lock deleted file mode 100644 index 4a73abff2..000000000 --- a/ecommerce/invoicing/Gemfile.lock +++ /dev/null @@ -1,119 +0,0 @@ -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.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.13.0) - ruby_event_store (= 2.13.0) - arkency-command_bus (0.4.1) - concurrent-ruby - ast (2.4.2) - base64 (0.2.0) - bigdecimal (3.1.4) - concurrent-ruby (1.2.2) - connection_pool (2.4.1) - diff-lcs (1.5.0) - drb (2.2.0) - ruby2_keywords - 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.1) - concurrent-ruby (~> 1.0) - dry-core (~> 1.0) - dry-inflector (~> 1.0) - dry-logic (~> 1.4) - zeitwerk (~> 2.6) - i18n (1.14.1) - 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.8) - rake (13.1.0) - redis-client (0.19.0) - connection_pool - regexp_parser (2.8.3) - ruby2_keywords (0.0.5) - ruby_event_store (2.13.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.0) - concurrent-ruby (< 2) - connection_pool (>= 2.3.0) - rack (>= 2.2.4) - redis-client (>= 0.14.0) - sorbet-runtime (0.5.11190) - tzinfo (2.0.6) - concurrent-ruby (~> 1.0) - unparser (0.6.12) - diff-lcs (~> 1.3) - parser (>= 3.2.2.4) - zeitwerk (2.6.12) - -PLATFORMS - arm64-darwin-20 - arm64-darwin-21 - ruby - x86_64-darwin-20 - x86_64-linux - -DEPENDENCIES - infra! - minitest (= 5.15.0)! - mutant-license! - mutant-minitest (= 0.11.26)! - -BUNDLED WITH - 2.5.9 diff --git a/ecommerce/invoicing/Makefile b/ecommerce/invoicing/Makefile deleted file mode 100644 index 23850fab1..000000000 --- a/ecommerce/invoicing/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -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/invoicing/README.md b/ecommerce/invoicing/README.md deleted file mode 100644 index ff873a58c..000000000 --- a/ecommerce/invoicing/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# Invoicing - -[![Build Status](https://github.com/RailsEventStore/cqrs-es-sample-with-res/workflows/invoicing/badge.svg)](https://github.com/RailsEventStore/cqrs-es-sample-with-res/actions/workflows/invoicing.yml) - - -#### Up and running - -``` -make install test mutate -``` - - -### Domain knowledge - -[Steps for successful invoicing](https://www.xero.com/guides/invoicing/) \ No newline at end of file diff --git a/ecommerce/invoicing/lib/invoicing.rb b/ecommerce/invoicing/lib/invoicing.rb deleted file mode 100644 index dc3c3ce19..000000000 --- a/ecommerce/invoicing/lib/invoicing.rb +++ /dev/null @@ -1,49 +0,0 @@ -require 'infra' -require_relative 'invoicing/commands' -require_relative 'invoicing/events' -require_relative 'invoicing/services' -require_relative 'invoicing/invoice' -require_relative 'invoicing/invoice_item_title_catalog' -require_relative 'invoicing/product' -require_relative 'invoicing/invoice_number_generator' - -module Invoicing - class Configuration - def call(event_store, command_bus) - command_bus.register( - SetProductNameDisplayedOnInvoice, - SetProductNameDisplayedOnInvoiceHandler.new(event_store) - ) - command_bus.register( - AddInvoiceItem, - InvoiceService.new(event_store).public_method(:add_item) - ) - command_bus.register( - SetPaymentDate, - InvoiceService.new(event_store).public_method(:set_payment_date) - ) - command_bus.register( - IssueInvoice, - InvoiceService.new(event_store).public_method(:issue) - ) - command_bus.register( - SetBillingAddress, - InvoiceService.new(event_store).public_method(:set_billing_address) - ) - event_store.subscribe( - ->(event) do - stream_name = "InvoiceIssued$#{event.data.fetch(:issue_date).strftime("%Y-%m")}" - ordinal_number = event.data.fetch(:invoice_number).split('/').first.to_i - event_store.link( - event.event_id, - stream_name: stream_name, - expected_version: ordinal_number - 2 - ) - rescue RubyEventStore::WrongExpectedEventVersion - raise Invoice::InvoiceNumberInUse - end, - to: [Invoicing::InvoiceIssued] - ) - end - end -end \ No newline at end of file diff --git a/ecommerce/invoicing/lib/invoicing/commands.rb b/ecommerce/invoicing/lib/invoicing/commands.rb deleted file mode 100644 index b49a47a93..000000000 --- a/ecommerce/invoicing/lib/invoicing/commands.rb +++ /dev/null @@ -1,30 +0,0 @@ -module Invoicing - class AddInvoiceItem < Infra::Command - attribute :invoice_id, Infra::Types::UUID - attribute :product_id, Infra::Types::UUID - attribute :quantity, Infra::Types::Quantity - attribute :unit_price, Infra::Types::Price - attribute :vat_rate, Infra::Types::VatRate - end - - class IssueInvoice < Infra::Command - attribute :invoice_id, Infra::Types::UUID - attribute :issue_date, Infra::Types::Date - end - - class SetPaymentDate < Infra::Command - attribute :invoice_id, Infra::Types::UUID - attribute :payment_date, Infra::Types::Date - end - - class SetBillingAddress < Infra::Command - attribute :invoice_id, Infra::Types::UUID - attribute :tax_id_number, Infra::Types::String.optional - attribute :postal_address, Infra::Types::PostalAddress - end - - class SetProductNameDisplayedOnInvoice < Infra::Command - attribute :product_id, Infra::Types::UUID - attribute :name_displayed, Infra::Types::String - end -end \ No newline at end of file diff --git a/ecommerce/invoicing/lib/invoicing/events.rb b/ecommerce/invoicing/lib/invoicing/events.rb deleted file mode 100644 index 30c4bdd67..000000000 --- a/ecommerce/invoicing/lib/invoicing/events.rb +++ /dev/null @@ -1,33 +0,0 @@ -module Invoicing - class InvoiceItemAdded < Infra::Event - attribute :invoice_id, Infra::Types::UUID - attribute :product_id, Infra::Types::UUID - attribute :title, Infra::Types::String - attribute :quantity, Infra::Types::Quantity - attribute :unit_price, Infra::Types::Price - attribute :vat_rate, Infra::Types::VatRate - end - - class InvoicePaymentDateSet < Infra::Event - attribute :invoice_id, Infra::Types::UUID - attribute :payment_date, Infra::Types::Params::Date - end - - class InvoiceIssued < Infra::Event - attribute :invoice_id, Infra::Types::UUID - attribute :issue_date, Infra::Types::Params::Date - attribute :disposal_date, Infra::Types::Params::Date - attribute :invoice_number, Infra::Types::String - end - - class BillingAddressSet < Infra::Event - attribute :invoice_id, Infra::Types::UUID - attribute :tax_id_number, Infra::Types::String.optional - attribute :postal_address, Infra::Types::PostalAddress - end - - class ProductNameDisplayedSet < Infra::Event - attribute :product_id, Infra::Types::UUID - attribute :name_displayed, Infra::Types::String - end -end \ No newline at end of file diff --git a/ecommerce/invoicing/lib/invoicing/fake_concurrent_invoice_number_generator.rb b/ecommerce/invoicing/lib/invoicing/fake_concurrent_invoice_number_generator.rb deleted file mode 100644 index 7328ece12..000000000 --- a/ecommerce/invoicing/lib/invoicing/fake_concurrent_invoice_number_generator.rb +++ /dev/null @@ -1,19 +0,0 @@ -module Invoicing - class FakeConcurrentInvoiceNumberGenerator - def initialize - @counter = 0 - end - - def call(issue_date) - issue_date.strftime("#{next_number}/%m/%Y") - end - - private - - def next_number - @counter += 1 - return 1 if @counter < 2 - @counter - 1 - end - end -end \ No newline at end of file diff --git a/ecommerce/invoicing/lib/invoicing/invoice.rb b/ecommerce/invoicing/lib/invoicing/invoice.rb deleted file mode 100644 index 9d759e807..000000000 --- a/ecommerce/invoicing/lib/invoicing/invoice.rb +++ /dev/null @@ -1,110 +0,0 @@ -module Invoicing - class Invoice - InvoiceAlreadyIssued = Class.new(StandardError) - InvoiceNumberInUse = Class.new(StandardError) - BillingAddressNotSpecified = Class.new(StandardError) - include AggregateRoot - - def initialize(invoice_id) - @invoice_id = invoice_id - @invoice_items = [] - end - - def issue(issue_date, invoice_number) - raise BillingAddressNotSpecified unless @postal_address - raise InvoiceAlreadyIssued unless draft? - disposal_date = [@payment_date, issue_date].compact.min - apply( - InvoiceIssued.new( - data: { - invoice_id: @invoice_id, - issue_date: issue_date, - disposal_date: disposal_date, - invoice_number: invoice_number - } - ) - ) - end - - def set_payment_date(payment_date) - apply( - InvoicePaymentDateSet.new( - data: { - invoice_id: @invoice_id, - payment_date: payment_date - } - ) - ) - end - - def add_item(product_id, title, unit_price, vat_rate, quantity) - raise InvoiceAlreadyIssued unless draft? - apply( - InvoiceItemAdded.new( - data: { - invoice_id: @invoice_id, - product_id: product_id, - title: title, - quantity: quantity, - unit_price: unit_price, - vat_rate: vat_rate - } - ) - ) - end - - def set_billing_address(tax_id_number, postal_address) - raise InvoiceAlreadyIssued unless draft? - apply BillingAddressSet.new( - data: { - invoice_id: @invoice_id, - postal_address: postal_address, - tax_id_number: tax_id_number - } - ) - end - - private - - def draft? - @issue_date.nil? - end - - on InvoiceItemAdded do |event| - @invoice_items << InvoiceItem.new( - event.data[:product_id], - event.data[:title], - event.data[:unit_price], - event.data[:vat_rate], - event.data[:quantity] - ) - end - - on InvoicePaymentDateSet do |event| - @payment_date = event.data[:payment_date] - end - - on InvoiceIssued do |event| - @state = :issued - @issue_date = event.data[:issue_date] - @disposal_date = event.data[:disposal_date] - end - - on BillingAddressSet do |event| - @tax_id_number = event.data.fetch(:tax_id_number) - @postal_address = event.data.fetch(:postal_address) - end - end - - class InvoiceItem - attr_reader :product_id, :quantity, :unit_price, :vat_rate, :title - - def initialize(product_id, title, unit_price, vat_rate, quantity) - @product_id = product_id - @title = title - @unit_price = unit_price - @vat_rate = vat_rate - @quantity = quantity - end - end -end \ No newline at end of file diff --git a/ecommerce/invoicing/lib/invoicing/invoice_item_title_catalog.rb b/ecommerce/invoicing/lib/invoicing/invoice_item_title_catalog.rb deleted file mode 100644 index bcabc61d5..000000000 --- a/ecommerce/invoicing/lib/invoicing/invoice_item_title_catalog.rb +++ /dev/null @@ -1,18 +0,0 @@ -module Invoicing - class InvoiceItemTitleCatalog - def initialize(event_store) - @event_store = event_store - end - - def invoice_item_title_for_product(product_id) - @event_store - .read - .of_type(ProductNameDisplayedSet) - .to_a - .filter { |e| e.data.fetch(:product_id).eql?(product_id) } - .last - .data - .fetch(:name_displayed) - end - end -end \ No newline at end of file diff --git a/ecommerce/invoicing/lib/invoicing/invoice_number_generator.rb b/ecommerce/invoicing/lib/invoicing/invoice_number_generator.rb deleted file mode 100644 index 0caaa15e1..000000000 --- a/ecommerce/invoicing/lib/invoicing/invoice_number_generator.rb +++ /dev/null @@ -1,18 +0,0 @@ -module Invoicing - class InvoiceNumberGenerator - def initialize(event_store) - @event_store = event_store - end - - def call(issue_date) - issue_date.strftime("#{next_number(issue_date)}/%m/%Y") - end - - private - - def next_number(issue_date) - stream_name = "InvoiceIssued$#{issue_date.strftime("%Y-%m")}" - @event_store.read.stream(stream_name).count + 1 - end - end -end \ No newline at end of file diff --git a/ecommerce/invoicing/lib/invoicing/product.rb b/ecommerce/invoicing/lib/invoicing/product.rb deleted file mode 100644 index 01624ff3c..000000000 --- a/ecommerce/invoicing/lib/invoicing/product.rb +++ /dev/null @@ -1,26 +0,0 @@ -module Invoicing - class Product - include AggregateRoot - - def initialize(product_id) - @product_id = product_id - end - - def set_name_displayed(name) - apply( - ProductNameDisplayedSet.new( - data: { - product_id: @product_id, - name_displayed: name - } - ) - ) - end - - private - - on ProductNameDisplayedSet do |event| - @name_displayed = event.data[:name_displayed] - end - end -end \ No newline at end of file diff --git a/ecommerce/invoicing/lib/invoicing/services.rb b/ecommerce/invoicing/lib/invoicing/services.rb deleted file mode 100644 index b547ae0ab..000000000 --- a/ecommerce/invoicing/lib/invoicing/services.rb +++ /dev/null @@ -1,55 +0,0 @@ -module Invoicing - class InvoiceService - def initialize(event_store, number_generator = InvoiceNumberGenerator.new(event_store)) - @repository = Infra::AggregateRootRepository.new(event_store) - @titles_catalog = InvoiceItemTitleCatalog.new(event_store) - @number_generator = number_generator - end - - def add_item(command) - with_invoice(command.invoice_id) do |invoice| - title = @titles_catalog.invoice_item_title_for_product(command.product_id) - invoice.add_item(command.product_id, title, command.unit_price, command.vat_rate, command.quantity) - end - end - - def set_payment_date(command) - with_invoice(command.invoice_id) do |invoice| - invoice.set_payment_date(command.payment_date) - end - end - - def set_billing_address(command) - with_invoice(command.invoice_id) do |invoice| - invoice.set_billing_address(command.tax_id_number, command.postal_address) - end - end - - def issue(command) - with_invoice(command.invoice_id) do |invoice| - invoice_number = @number_generator.call(command.issue_date) - invoice.issue(command.issue_date, invoice_number) - end - end - - private - - def with_invoice(invoice_id) - @repository.with_aggregate(Invoice, invoice_id) do |invoice| - yield(invoice) - end - end - end - - class SetProductNameDisplayedOnInvoiceHandler - def initialize(event_store) - @repository = Infra::AggregateRootRepository.new(event_store) - end - - def call(command) - @repository.with_aggregate(Product, command.product_id) do |product| - product.set_name_displayed(command.name_displayed) - end - end - end -end \ No newline at end of file diff --git a/ecommerce/invoicing/test/fake_concurrent_invoice_number_generator_test.rb b/ecommerce/invoicing/test/fake_concurrent_invoice_number_generator_test.rb deleted file mode 100644 index 645b150c6..000000000 --- a/ecommerce/invoicing/test/fake_concurrent_invoice_number_generator_test.rb +++ /dev/null @@ -1,15 +0,0 @@ -require_relative "test_helper" - -module Invoicing - class FakeConcurrentInvoiceNumberGeneratorTest < Test - cover "Invoicing::FakeInvoiceNumberGenerator" - - def test_fetching_next_number - issue_date = Date.new(2022, 1, 5) - number_generator = FakeConcurrentInvoiceNumberGenerator.new - assert_equal("1/01/2022", number_generator.call(issue_date)) - assert_equal("1/01/2022", number_generator.call(issue_date)) - assert_equal("2/01/2022", number_generator.call(issue_date)) - end - end -end \ No newline at end of file diff --git a/ecommerce/invoicing/test/invoice_item_test.rb b/ecommerce/invoicing/test/invoice_item_test.rb deleted file mode 100644 index 3d65d1ec1..000000000 --- a/ecommerce/invoicing/test/invoice_item_test.rb +++ /dev/null @@ -1,22 +0,0 @@ -require_relative "test_helper" - -module Invoicing - class InvoiceItemTest < Test - cover "Invoicing::Invoice" - - def test_initializer - product_id = SecureRandom.uuid - vat_rate = Infra::Types::VatRate.new(rate: 20, code: "20") - unit_price = 100.to_d - quantity = 20 - title = 'test' - item = InvoiceItem.new(product_id, title, unit_price, vat_rate, quantity) - - assert_equal product_id, item.product_id - assert_equal title, item.title - assert_equal vat_rate, item.vat_rate - assert_equal unit_price, item.unit_price - assert_equal quantity, item.quantity - end - end -end \ No newline at end of file diff --git a/ecommerce/invoicing/test/invoice_number_generator_test.rb b/ecommerce/invoicing/test/invoice_number_generator_test.rb deleted file mode 100644 index b847f7b8b..000000000 --- a/ecommerce/invoicing/test/invoice_number_generator_test.rb +++ /dev/null @@ -1,27 +0,0 @@ -require_relative "test_helper" - -module Invoicing - class InvoiceNumberGeneratorTest < Test - cover "Invoicing::InvoiceNumberGenerator" - - def test_fetching_next_number - issue_date = Date.new(2022, 1, 5) - number_generator = InvoiceNumberGenerator.new(event_store) - assert_equal("1/01/2022", number_generator.call(issue_date)) - issue_random_invoice(issue_date) - assert_equal("2/01/2022", number_generator.call(issue_date)) - next_month_issue_date = Date.new(2022, 2, 5) - assert_equal("1/02/2022", number_generator.call(next_month_issue_date)) - next_year_issue_date = Date.new(2023, 1, 5) - assert_equal("1/01/2023", number_generator.call(next_year_issue_date)) - end - - private - - def issue_random_invoice(issue_date) - invoice_id = SecureRandom.uuid - set_billing_address(invoice_id) - run_command(IssueInvoice.new(invoice_id: invoice_id, issue_date: issue_date)) - end - end -end \ No newline at end of file diff --git a/ecommerce/invoicing/test/invoice_service_test.rb b/ecommerce/invoicing/test/invoice_service_test.rb deleted file mode 100644 index 11412c942..000000000 --- a/ecommerce/invoicing/test/invoice_service_test.rb +++ /dev/null @@ -1,177 +0,0 @@ -require_relative "test_helper" - -module Invoicing - class InvoiceServiceTest < Test - cover "Invoicing::InvoiceService" - - def test_adding_to_invoice - invoice_id = SecureRandom.uuid - product_id = SecureRandom.uuid - unit_price = 10.0.to_d - vat_rate = Infra::Types::VatRate.new(code: "20", rate: 20) - title = 'test' - - stream = "Invoicing::Invoice$#{invoice_id}" - assert_events( - stream, - InvoiceItemAdded.new( - data: { - invoice_id: invoice_id, - product_id: product_id, - title: title, - vat_rate: vat_rate, - unit_price: unit_price, - quantity: 1, - } - ) - ) { add_item(invoice_id, product_id, vat_rate, unit_price, title) } - end - - def test_setting_billing_address - invoice_id = SecureRandom.uuid - billing_address = fake_address - tax_id_number = "PL1111111111" - stream = "Invoicing::Invoice$#{invoice_id}" - assert_events( - stream, - BillingAddressSet.new( - data: { - invoice_id: invoice_id, - postal_address: fake_address, - tax_id_number: tax_id_number - } - ) - ) { set_billing_address(invoice_id, billing_address, tax_id_number) } - end - - def test_setting_payment_date - invoice_id = SecureRandom.uuid - payment_date = Date.new(2021, 1, 5) - - stream = "Invoicing::Invoice$#{invoice_id}" - assert_events( - stream, - InvoicePaymentDateSet.new( - data: { - invoice_id: invoice_id, - payment_date: payment_date, - } - ) - ) { set_payment_date(invoice_id, payment_date) } - end - - def test_issuing_invoice - invoice_id = SecureRandom.uuid - issue_date = Date.new(2021, 1, 5) - set_billing_address(invoice_id) - - stream = "Invoicing::Invoice$#{invoice_id}" - assert_events( - stream, - InvoiceIssued.new( - data: { - invoice_id: invoice_id, - issue_date: issue_date, - disposal_date: issue_date, - invoice_number: '1/01/2021' - } - ) - ) { issue_invoice(invoice_id, issue_date) } - end - - def test_issuing_invoice_after_setting_payment_date - invoice_id = SecureRandom.uuid - issue_date = Date.new(2021, 1, 5) - payment_date = Date.new(2021, 1, 1) - set_payment_date(invoice_id, payment_date) - set_billing_address(invoice_id) - - stream = "Invoicing::Invoice$#{invoice_id}" - assert_events( - stream, - InvoiceIssued.new( - data: { - invoice_id: invoice_id, - issue_date: issue_date, - disposal_date: payment_date, - invoice_number: '1/01/2021' - } - ) - ) { issue_invoice(invoice_id, issue_date) } - end - - def test_issuing_invoice_with_faked_race_condition - invoice_id = SecureRandom.uuid - another_invoice_id = SecureRandom.uuid - issue_date = Date.new(2021, 1, 5) - set_billing_address(invoice_id) - set_billing_address(another_invoice_id) - - mocked_service = InvoiceService.new( - event_store, - FakeConcurrentInvoiceNumberGenerator.new - ).public_method(:issue) - - stream = "Invoicing::Invoice$#{invoice_id}" - assert_events( - stream, - InvoiceIssued.new( - data: { - invoice_id: invoice_id, - issue_date: issue_date, - disposal_date: issue_date, - invoice_number: '1/01/2021' - } - ) - ) { mocked_service.(issue_invoice_command(invoice_id, issue_date)) } - assert_raises(Invoice::InvoiceNumberInUse) do - mocked_service.(issue_invoice_command(another_invoice_id, issue_date)) - end - end - - def test_issued_invoice_is_a_final_state - invoice_id = SecureRandom.uuid - set_billing_address(invoice_id) - issue_invoice(invoice_id) - assert_raises(Invoice::InvoiceAlreadyIssued) { issue_invoice(invoice_id) } - assert_raises(Invoice::InvoiceAlreadyIssued) { add_item(invoice_id) } - assert_raises(Invoice::InvoiceAlreadyIssued) { set_billing_address(invoice_id) } - end - - def test_invoice_can_not_be_issued_without_billing_address - invoice_id = SecureRandom.uuid - assert_raises(Invoice::BillingAddressNotSpecified) { issue_invoice(invoice_id) } - end - - private - - def add_item ( - invoice_id, - product_id = SecureRandom.uuid, - vat_rate = Infra::Types::VatRate.new(code: "20", rate: 20), - unit_price = 10.0.to_d, - title = 'test' - ) - set_product_name_displayed(product_id, title) - run_command(AddInvoiceItem.new( - invoice_id: invoice_id, - product_id: product_id, - vat_rate: vat_rate, - unit_price: unit_price, - quantity: 1 - )) - end - - def issue_invoice(invoice_id, issue_date = Date.new(2021, 1, 5)) - run_command(issue_invoice_command(invoice_id, issue_date)) - end - - def issue_invoice_command(invoice_id, issue_date) - IssueInvoice.new(invoice_id: invoice_id, issue_date: issue_date) - end - - def set_payment_date(invoice_id, payment_date = Date.new(2021, 1, 5)) - run_command(SetPaymentDate.new(invoice_id: invoice_id, payment_date: payment_date)) - end - end -end \ No newline at end of file diff --git a/ecommerce/invoicing/test/setting_product_displayed_name_test.rb b/ecommerce/invoicing/test/setting_product_displayed_name_test.rb deleted file mode 100644 index 3c26305c4..000000000 --- a/ecommerce/invoicing/test/setting_product_displayed_name_test.rb +++ /dev/null @@ -1,23 +0,0 @@ -require_relative "test_helper" - -module Invoicing - class SettingProductDisplayedNameTest < Test - cover "Invoicing::SetProductNameDisplayedOnInvoiceHandler" - - def test_adding_to_invoice - product_id = SecureRandom.uuid - name_displayed = 'test' - stream = "Invoicing::Product$#{product_id}" - - assert_events( - stream, - ProductNameDisplayedSet.new( - data: { - product_id: product_id, - name_displayed: name_displayed, - } - ) - ) { set_product_name_displayed(product_id, name_displayed) } - end - end -end \ No newline at end of file diff --git a/ecommerce/invoicing/test/test_helper.rb b/ecommerce/invoicing/test/test_helper.rb deleted file mode 100644 index f44c21892..000000000 --- a/ecommerce/invoicing/test/test_helper.rb +++ /dev/null @@ -1,37 +0,0 @@ -require "minitest/autorun" -require "mutant/minitest/coverage" - -require_relative "../lib/invoicing" -require_relative '../lib/invoicing/fake_concurrent_invoice_number_generator' - -module Invoicing - class Test < Infra::InMemoryTest - def before_setup - super - Configuration.new.call(event_store, command_bus) - end - - private - - def set_product_name_displayed(product_id, name_displayed) - run_command(SetProductNameDisplayedOnInvoice.new(product_id: product_id, name_displayed: name_displayed)) - end - - def set_billing_address(invoice_id, postal_address = fake_address, tax_id_number = nil) - run_command(SetBillingAddress.new( - invoice_id: invoice_id, - postal_address: postal_address, - tax_id_number: tax_id_number - )) - end - - def fake_address - Infra::Types::PostalAddress.new( - line_1: "Anna Kowalska", - line_2: "Ul. Bosmanska 1", - line_3: "81-116 GDYNIA", - line_4: "POLAND" - ) - end - end -end diff --git a/ecommerce/ordering/.mutant.yml b/ecommerce/ordering/.mutant.yml deleted file mode 100644 index 6f7998002..000000000 --- a/ecommerce/ordering/.mutant.yml +++ /dev/null @@ -1,13 +0,0 @@ -requires: - - ./test/test_helper -integration: minitest -coverage_criteria: - process_abort: true -matcher: - subjects: - - Ordering* - ignore: - - Ordering::NumberGenerator* - - Ordering::Test* - - Ordering::Configuration#call - - Ordering::Configuration#initialize \ No newline at end of file diff --git a/ecommerce/ordering/Gemfile b/ecommerce/ordering/Gemfile deleted file mode 100644 index 8fd887144..000000000 --- a/ecommerce/ordering/Gemfile +++ /dev/null @@ -1,4 +0,0 @@ -source "https://rubygems.org" - -eval_gemfile "../../infra/Gemfile.test" -gem "infra", path: "../../infra" \ No newline at end of file diff --git a/ecommerce/ordering/Gemfile.lock b/ecommerce/ordering/Gemfile.lock deleted file mode 100644 index 4a73abff2..000000000 --- a/ecommerce/ordering/Gemfile.lock +++ /dev/null @@ -1,119 +0,0 @@ -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.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.13.0) - ruby_event_store (= 2.13.0) - arkency-command_bus (0.4.1) - concurrent-ruby - ast (2.4.2) - base64 (0.2.0) - bigdecimal (3.1.4) - concurrent-ruby (1.2.2) - connection_pool (2.4.1) - diff-lcs (1.5.0) - drb (2.2.0) - ruby2_keywords - 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.1) - concurrent-ruby (~> 1.0) - dry-core (~> 1.0) - dry-inflector (~> 1.0) - dry-logic (~> 1.4) - zeitwerk (~> 2.6) - i18n (1.14.1) - 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.8) - rake (13.1.0) - redis-client (0.19.0) - connection_pool - regexp_parser (2.8.3) - ruby2_keywords (0.0.5) - ruby_event_store (2.13.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.0) - concurrent-ruby (< 2) - connection_pool (>= 2.3.0) - rack (>= 2.2.4) - redis-client (>= 0.14.0) - sorbet-runtime (0.5.11190) - tzinfo (2.0.6) - concurrent-ruby (~> 1.0) - unparser (0.6.12) - diff-lcs (~> 1.3) - parser (>= 3.2.2.4) - zeitwerk (2.6.12) - -PLATFORMS - arm64-darwin-20 - arm64-darwin-21 - ruby - x86_64-darwin-20 - x86_64-linux - -DEPENDENCIES - infra! - minitest (= 5.15.0)! - mutant-license! - mutant-minitest (= 0.11.26)! - -BUNDLED WITH - 2.5.9 diff --git a/ecommerce/ordering/Makefile b/ecommerce/ordering/Makefile deleted file mode 100644 index 23850fab1..000000000 --- a/ecommerce/ordering/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -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/ordering/README.md b/ecommerce/ordering/README.md deleted file mode 100644 index 26708b6b8..000000000 --- a/ecommerce/ordering/README.md +++ /dev/null @@ -1,61 +0,0 @@ -# Ordering - -[![Build Status](https://github.com/RailsEventStore/cqrs-es-sample-with-res/workflows/ordering/badge.svg)](https://github.com/RailsEventStore/cqrs-es-sample-with-res/actions/workflows/ordering.yml) - -The `Ordering::Order` aggregate manages the state machine of an order: - -- draft -- submitted -- accepted -- expired - -After each successful change an appropriate event is published in the Order stream. -This object is fully event sourced. - -| Order | draft | expired | submitted | accepted | -|-----------|:-----:|:-------:|:---------:|:--------:| -| draft | | ✅ | ✅ | | -| expired | | | | | -| submitted | ✅ | | | ✅ | -| accepted | | | | | - -### Design dilemmas - -#### God Domain - -The state machine mentioned above became a very central place to the whole application. -Almost every other domain either reacts to this domain or triggers Ordering. - -This might be an issue, as we might end up with a God Domain. - -#### Duplication of states - -Some of the states here are actually duplicates of the states of the Order in other domains. - -#### Multiplication and naming of states - -We clearly have a naming issue here. -What is the actual difference between submit/confirm/accept? -Not all the names match between method names and event names. - -#### Order items - -We track order items here, but we actually don't really use it much. -It doesn't have any impact on the state machine. -It's only needed to some read models, which can retrieve it from elsewhere - most notably the `Pricing` -The implementation of `Basket`, because of this, seems duplicated to Pricing or Inventory. - -#### Mapping of events between domains - -UI -> Ordering::SubmitOrder -> Ordering::Submitted -> Reservation(process) -> Ordering::AcceptOrder - -Ordering::AcceptOrder -> Ordering::OrderPlaced -> - --> Shipment::SubmitShipment --> Pricing::CalculateTotalValue - -### Up and running - -``` -make install test mutate -``` diff --git a/ecommerce/ordering/lib/ordering.rb b/ecommerce/ordering/lib/ordering.rb deleted file mode 100644 index ca4ad0c1c..000000000 --- a/ecommerce/ordering/lib/ordering.rb +++ /dev/null @@ -1,37 +0,0 @@ -require "infra" -require_relative "ordering/events/item_added_to_basket" -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_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/accept_order" -require_relative "ordering/commands/reject_order" -require_relative "ordering/fake_number_generator" -require_relative "ordering/number_generator" -require_relative "ordering/service" -require_relative "ordering/order" - -module Ordering - class Configuration - def initialize(number_generator) - @number_generator = number_generator - end - - def call(event_store, command_bus) - command_bus.register( - SubmitOrder, - OnSubmitOrder.new(event_store, @number_generator.call) - ) - 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(AcceptOrder, OnAcceptOrder.new(event_store)) - command_bus.register(RejectOrder, OnRejectOrder.new(event_store)) - end - end -end diff --git a/ecommerce/ordering/lib/ordering/commands/accept_order.rb b/ecommerce/ordering/lib/ordering/commands/accept_order.rb deleted file mode 100644 index 4ca46dee2..000000000 --- a/ecommerce/ordering/lib/ordering/commands/accept_order.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Ordering - class AcceptOrder < Infra::Command - attribute :order_id, Infra::Types::UUID - - alias aggregate_id order_id - end -end diff --git a/ecommerce/ordering/lib/ordering/commands/add_item_to_basket.rb b/ecommerce/ordering/lib/ordering/commands/add_item_to_basket.rb deleted file mode 100644 index bad32f450..000000000 --- a/ecommerce/ordering/lib/ordering/commands/add_item_to_basket.rb +++ /dev/null @@ -1,8 +0,0 @@ -module Ordering - class AddItemToBasket < Infra::Command - attribute :order_id, Infra::Types::UUID - attribute :product_id, Infra::Types::UUID - - alias aggregate_id order_id - end -end \ No newline at end of file diff --git a/ecommerce/ordering/lib/ordering/commands/reject_order.rb b/ecommerce/ordering/lib/ordering/commands/reject_order.rb deleted file mode 100644 index 39a6d522c..000000000 --- a/ecommerce/ordering/lib/ordering/commands/reject_order.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Ordering - class RejectOrder < Infra::Command - attribute :order_id, Infra::Types::UUID - - alias aggregate_id order_id - end -end diff --git a/ecommerce/ordering/lib/ordering/commands/remove_item_from_basket.rb b/ecommerce/ordering/lib/ordering/commands/remove_item_from_basket.rb deleted file mode 100644 index dd3e31fe9..000000000 --- a/ecommerce/ordering/lib/ordering/commands/remove_item_from_basket.rb +++ /dev/null @@ -1,8 +0,0 @@ -module Ordering - class RemoveItemFromBasket < Infra::Command - attribute :order_id, Infra::Types::UUID - attribute :product_id, Infra::Types::UUID - - alias aggregate_id order_id - end -end \ No newline at end of file diff --git a/ecommerce/ordering/lib/ordering/commands/set_order_as_expired.rb b/ecommerce/ordering/lib/ordering/commands/set_order_as_expired.rb deleted file mode 100644 index 938f95fdb..000000000 --- a/ecommerce/ordering/lib/ordering/commands/set_order_as_expired.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Ordering - class SetOrderAsExpired < Infra::Command - attribute :order_id, Infra::Types::UUID - - alias aggregate_id order_id - end -end diff --git a/ecommerce/ordering/lib/ordering/commands/submit_order.rb b/ecommerce/ordering/lib/ordering/commands/submit_order.rb deleted file mode 100644 index 6842fe3b5..000000000 --- a/ecommerce/ordering/lib/ordering/commands/submit_order.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Ordering - class SubmitOrder < Infra::Command - attribute :order_id, Infra::Types::UUID - - alias aggregate_id order_id - end -end diff --git a/ecommerce/ordering/lib/ordering/events/item_added_to_basket.rb b/ecommerce/ordering/lib/ordering/events/item_added_to_basket.rb deleted file mode 100644 index d5fe6f697..000000000 --- a/ecommerce/ordering/lib/ordering/events/item_added_to_basket.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Ordering - class ItemAddedToBasket < Infra::Event - attribute :order_id, Infra::Types::UUID - attribute :product_id, Infra::Types::UUID - end -end \ No newline at end of file diff --git a/ecommerce/ordering/lib/ordering/events/item_removed_from_basket.rb b/ecommerce/ordering/lib/ordering/events/item_removed_from_basket.rb deleted file mode 100644 index f68c68ff2..000000000 --- a/ecommerce/ordering/lib/ordering/events/item_removed_from_basket.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Ordering - class ItemRemovedFromBasket < Infra::Event - attribute :order_id, Infra::Types::UUID - attribute :product_id, Infra::Types::UUID - end -end \ No newline at end of file diff --git a/ecommerce/ordering/lib/ordering/events/order_expired.rb b/ecommerce/ordering/lib/ordering/events/order_expired.rb deleted file mode 100644 index 178e1b3c0..000000000 --- a/ecommerce/ordering/lib/ordering/events/order_expired.rb +++ /dev/null @@ -1,5 +0,0 @@ -module Ordering - class OrderExpired < Infra::Event - attribute :order_id, Infra::Types::UUID - end -end diff --git a/ecommerce/ordering/lib/ordering/events/order_placed.rb b/ecommerce/ordering/lib/ordering/events/order_placed.rb deleted file mode 100644 index 14a59b4fb..000000000 --- a/ecommerce/ordering/lib/ordering/events/order_placed.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Ordering - class OrderPlaced < Infra::Event - attribute :order_id, Infra::Types::UUID - attribute :order_number, Infra::Types::OrderNumber - end -end diff --git a/ecommerce/ordering/lib/ordering/events/order_rejected.rb b/ecommerce/ordering/lib/ordering/events/order_rejected.rb deleted file mode 100644 index 02cd44b60..000000000 --- a/ecommerce/ordering/lib/ordering/events/order_rejected.rb +++ /dev/null @@ -1,5 +0,0 @@ -module Ordering - class OrderRejected < Infra::Event - attribute :order_id, Infra::Types::UUID - end -end diff --git a/ecommerce/ordering/lib/ordering/events/order_submitted.rb b/ecommerce/ordering/lib/ordering/events/order_submitted.rb deleted file mode 100644 index 5ebd08e5c..000000000 --- a/ecommerce/ordering/lib/ordering/events/order_submitted.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Ordering - class OrderSubmitted < Infra::Event - attribute :order_id, Infra::Types::UUID - attribute :order_number, Infra::Types::OrderNumber - end -end diff --git a/ecommerce/ordering/lib/ordering/fake_number_generator.rb b/ecommerce/ordering/lib/ordering/fake_number_generator.rb deleted file mode 100644 index a25911d20..000000000 --- a/ecommerce/ordering/lib/ordering/fake_number_generator.rb +++ /dev/null @@ -1,8 +0,0 @@ -module Ordering - class FakeNumberGenerator - FAKE_NUMBER = "2019/01/60".freeze - def call - FAKE_NUMBER - end - end -end diff --git a/ecommerce/ordering/lib/ordering/number_generator.rb b/ecommerce/ordering/lib/ordering/number_generator.rb deleted file mode 100644 index 48fd930c1..000000000 --- a/ecommerce/ordering/lib/ordering/number_generator.rb +++ /dev/null @@ -1,13 +0,0 @@ -module Ordering - class NumberGenerator - def call - Time.now.strftime("%Y/%m/#{random_number}") - end - - private - - def random_number - SecureRandom.random_number(100) - end - end -end diff --git a/ecommerce/ordering/lib/ordering/order.rb b/ecommerce/ordering/lib/ordering/order.rb deleted file mode 100644 index b6ccdd0e9..000000000 --- a/ecommerce/ordering/lib/ordering/order.rb +++ /dev/null @@ -1,146 +0,0 @@ -module Ordering - class Order - include AggregateRoot - - InvalidState = Class.new(StandardError) - AlreadySubmitted = Class.new(InvalidState) - NotPlaced = Class.new(InvalidState) - OrderHasExpired = Class.new(InvalidState) - - def initialize(id) - @id = id - @state = State.draft - @basket = Basket.new - end - - def submit(order_number) - raise OrderHasExpired if @state.expired? - raise AlreadySubmitted unless @state.draft? - apply OrderSubmitted.new( - data: { - order_id: @id, - order_number: order_number, - order_lines: @basket.order_lines - } - ) - end - - def accept - raise InvalidState unless @state.submitted? - apply OrderPlaced.new( - data: { - order_id: @id, - order_number: @order_number, - order_lines: @basket.order_lines - } - ) - end - - def reject - raise InvalidState unless @state.submitted? - apply OrderRejected.new( - data: { - order_id: @id - } - ) - end - - def expire - raise AlreadySubmitted unless @state.draft? - apply OrderExpired.new(data: { order_id: @id }) - end - - def add_item(product_id) - raise AlreadySubmitted unless @state.draft? - apply ItemAddedToBasket.new( - data: { - order_id: @id, - product_id: product_id, - } - ) - end - - def remove_item(product_id) - raise AlreadySubmitted unless @state.draft? - apply ItemRemovedFromBasket.new(data: { order_id: @id, product_id: product_id }) - end - - on OrderPlaced do |_| - @state = State.new(:accepted) - end - - on OrderExpired do |_| - @state = State.expired - end - - on ItemAddedToBasket do |event| - @basket.increase_quantity(event.data[:product_id]) - end - - on ItemRemovedFromBasket do |event| - @basket.decrease_quantity(event.data[:product_id]) - end - - on OrderSubmitted do |event| - @order_number = event.data[:order_number] - @state = State.submitted - end - - on OrderRejected do |_| - @state = State.draft - end - - class Basket - def initialize - @order_lines = Hash.new(0) - end - - def increase_quantity(product_id) - order_lines[product_id] = quantity(product_id) + 1 - end - - def decrease_quantity(product_id) - order_lines[product_id] -= 1 - order_lines.delete(product_id) if order_lines.fetch(product_id).equal?(0) - end - - def order_lines - @order_lines - end - - def quantity(product_id) - order_lines[product_id] - end - end - - class State - def self.draft - new(:draft) - end - - def self.submitted - new(:submitted) - end - - def self.expired - new(:expired) - end - - def initialize(state) - @state = state - end - - def draft? - @state.equal?(:draft) - end - - def submitted? - @state.equal?(:submitted) - end - - def expired? - @state.equal?(:expired) - end - end - end -end diff --git a/ecommerce/ordering/lib/ordering/service.rb b/ecommerce/ordering/lib/ordering/service.rb deleted file mode 100644 index 4ab6dde83..000000000 --- a/ecommerce/ordering/lib/ordering/service.rb +++ /dev/null @@ -1,75 +0,0 @@ -module Ordering - class OnAddItemToBasket - def initialize(event_store) - @repository = Infra::AggregateRootRepository.new(event_store) - end - - def call(command) - @repository.with_aggregate(Order, command.aggregate_id) do |order| - order.add_item(command.product_id) - end - end - end - - class OnRemoveItemFromBasket - def initialize(event_store) - @repository = Infra::AggregateRootRepository.new(event_store) - end - - def call(command) - @repository.with_aggregate(Order, command.aggregate_id) do |order| - order.remove_item(command.product_id) - end - end - end - - class OnSetOrderAsExpired - def initialize(event_store) - @repository = Infra::AggregateRootRepository.new(event_store) - end - - def call(command) - @repository.with_aggregate(Order, command.aggregate_id) do |order| - order.expire - end - end - end - - class OnSubmitOrder - def initialize(event_store, number_generator) - @repository = Infra::AggregateRootRepository.new(event_store) - @number_generator = number_generator - end - - def call(command) - @repository.with_aggregate(Order, command.aggregate_id) do |order| - order_number = @number_generator.call - order.submit(order_number) - end - end - end - - class OnAcceptOrder - def initialize(event_store) - @repository = Infra::AggregateRootRepository.new(event_store) - end - - def call(command) - @repository.with_aggregate(Order, command.aggregate_id) do |order| - order.accept - end - end - end - - class OnRejectOrder - def initialize(event_store) - @repository = Infra::AggregateRootRepository.new(event_store) - end - - def call(command) - @repository.with_aggregate(Order, command.aggregate_id) do |order| - order.reject - end - end - end -end diff --git a/ecommerce/ordering/test/accept_order_test.rb b/ecommerce/ordering/test/accept_order_test.rb deleted file mode 100644 index 331343ee9..000000000 --- a/ecommerce/ordering/test/accept_order_test.rb +++ /dev/null @@ -1,54 +0,0 @@ -require_relative "test_helper" - -module Ordering - class AcceptOrderTest < Test - cover "Ordering::OnAcceptOrder*" - - def test_order_gets_accepted - aggregate_id = SecureRandom.uuid - stream = "Ordering::Order$#{aggregate_id}" - customer_id = SecureRandom.uuid - product_id = SecureRandom.uuid - order_number = FakeNumberGenerator::FAKE_NUMBER - arrange( - AddItemToBasket.new( - order_id: aggregate_id, - product_id: product_id - ), - SubmitOrder.new( - order_id: aggregate_id, - customer_id: customer_id - ) - ) - - assert_events( - stream, - OrderPlaced.new( - data: { - order_id: aggregate_id, - order_number: order_number, - order_lines: { product_id => 1 } - } - ) - ) do - act(AcceptOrder.new(order_id: aggregate_id)) - end - end - - def test_order_must_be_submitted_to_get_accepted - aggregate_id = SecureRandom.uuid - product_id = SecureRandom.uuid - - arrange( - AddItemToBasket.new( - order_id: aggregate_id, - product_id: product_id - ) - ) - - assert_raises(Order::InvalidState) do - act(AcceptOrder.new(order_id: aggregate_id)) - end - end - end -end diff --git a/ecommerce/ordering/test/add_item_to_basket_test.rb b/ecommerce/ordering/test/add_item_to_basket_test.rb deleted file mode 100644 index d33ae672c..000000000 --- a/ecommerce/ordering/test/add_item_to_basket_test.rb +++ /dev/null @@ -1,49 +0,0 @@ -require_relative "test_helper" - -module Ordering - class AddItemToBasketTest < Test - cover "Ordering::OnAddItemToBasket*" - - def test_item_is_added_to_draft_order - aggregate_id = SecureRandom.uuid - stream = "Ordering::Order$#{aggregate_id}" - product_id = SecureRandom.uuid - - expected_events = [ - ItemAddedToBasket.new( - data: { - order_id: aggregate_id, - product_id: product_id, - } - ) - ] - assert_events(stream, *expected_events) do - act( - AddItemToBasket.new( - order_id: aggregate_id, - product_id: product_id - ) - ) - end - end - - def test_no_add_allowed_to_submitted_order - aggregate_id = SecureRandom.uuid - customer_id = SecureRandom.uuid - product_id = SecureRandom.uuid - order_number = FakeNumberGenerator::FAKE_NUMBER - - arrange( - AddItemToBasket.new(order_id: aggregate_id, product_id: product_id), - SubmitOrder.new( - order_id: aggregate_id, - order_number: order_number, - customer_id: customer_id - ) - ) - assert_raises(Order::AlreadySubmitted) do - act(AddItemToBasket.new(order_id: aggregate_id, product_id: product_id)) - end - end - end -end diff --git a/ecommerce/ordering/test/number_generator_test.rb b/ecommerce/ordering/test/number_generator_test.rb deleted file mode 100644 index 3d9c49de8..000000000 --- a/ecommerce/ordering/test/number_generator_test.rb +++ /dev/null @@ -1,13 +0,0 @@ -require_relative "test_helper" - -module Ordering - class NumberGeneratorTest < Test - def test_includes_year - assert_includes(NumberGenerator.new.call, "#{Time.now.year}") - end - - def test_includes_month - assert_includes(NumberGenerator.new.call, "#{Time.now.month}") - end - end -end diff --git a/ecommerce/ordering/test/order_test.rb b/ecommerce/ordering/test/order_test.rb deleted file mode 100644 index b398e0ae7..000000000 --- a/ecommerce/ordering/test/order_test.rb +++ /dev/null @@ -1,39 +0,0 @@ -require_relative "test_helper" - -module Ordering - class OrderTest < Test - cover "Ordering::Order" - - def setup - super - @order_id = SecureRandom.uuid - @product_id = SecureRandom.uuid - @customer_id = SecureRandom.uuid - end - - def test_order_lines_are_empty_after_adding_and_removing - order = Order.new(@order_id) - order.add_item(@product_id) - order.remove_item(@product_id) - order.submit(NumberGenerator.new.call) - assert_equal({}, order.unpublished_events.to_a.last.data[:order_lines]) - end - - def test_order_lines_with_the_same_product_twice - order = Order.new(@order_id) - order.add_item(@product_id) - order.add_item(@product_id) - order.submit(NumberGenerator.new.call) - assert_equal({ @product_id => 2 }, order.unpublished_events.to_a.last.data[:order_lines]) - end - - def test_order_lines_after_adding_twice_and_remove_once - order = Order.new(@order_id) - order.add_item(@product_id) - order.add_item(@product_id) - order.remove_item(@product_id) - order.submit(NumberGenerator.new.call) - assert_equal({ @product_id => 1 }, order.unpublished_events.to_a.last.data[:order_lines]) - end - end -end diff --git a/ecommerce/ordering/test/reject_order_test.rb b/ecommerce/ordering/test/reject_order_test.rb deleted file mode 100644 index bc813772d..000000000 --- a/ecommerce/ordering/test/reject_order_test.rb +++ /dev/null @@ -1,52 +0,0 @@ -require_relative "test_helper" - -module Ordering - class RejectOrderTest < Test - cover "Ordering::OnRejectOrder*" - - def test_order_gets_rejected - aggregate_id = SecureRandom.uuid - stream = "Ordering::Order$#{aggregate_id}" - customer_id = SecureRandom.uuid - product_id = SecureRandom.uuid - - arrange( - AddItemToBasket.new( - order_id: aggregate_id, - product_id: product_id - ), - SubmitOrder.new( - order_id: aggregate_id, - customer_id: customer_id - ) - ) - - assert_events( - stream, - OrderRejected.new( - data: { - order_id: aggregate_id - } - ) - ) do - act(RejectOrder.new(order_id: aggregate_id)) - end - end - - def test_order_must_be_submitted_to_get_rejected - aggregate_id = SecureRandom.uuid - product_id = SecureRandom.uuid - - arrange( - AddItemToBasket.new( - order_id: aggregate_id, - product_id: product_id - ) - ) - - assert_raises(Order::InvalidState) do - act(RejectOrder.new(order_id: aggregate_id)) - end - end - end -end diff --git a/ecommerce/ordering/test/remove_item_from_basket_test.rb b/ecommerce/ordering/test/remove_item_from_basket_test.rb deleted file mode 100644 index 2605eec69..000000000 --- a/ecommerce/ordering/test/remove_item_from_basket_test.rb +++ /dev/null @@ -1,53 +0,0 @@ -require_relative "test_helper" - -module Ordering - class RemoveItemFromBasketTest < Test - cover "Ordering::OnRemoveItemFromBasket*" - - def test_item_is_removed_from_draft_order - aggregate_id = SecureRandom.uuid - stream = "Ordering::Order$#{aggregate_id}" - - product_id = SecureRandom.uuid - - arrange( - AddItemToBasket.new( - order_id: aggregate_id, - product_id: product_id - ) - ) - expected_events = [ - ItemRemovedFromBasket.new( - data: { - order_id: aggregate_id, - product_id: product_id - } - ) - ] - assert_events(stream, *expected_events) do - act( - RemoveItemFromBasket.new( - order_id: aggregate_id, - product_id: product_id - ) - ) - end - end - - def test_no_remove_allowed_to_created_order - aggregate_id = SecureRandom.uuid - customer_id = SecureRandom.uuid - product_id = SecureRandom.uuid - order_number = FakeNumberGenerator::FAKE_NUMBER - - arrange( - AddItemToBasket.new(order_id: aggregate_id, product_id: product_id), - SubmitOrder.new(order_id: aggregate_id, order_number: order_number, customer_id: customer_id) - ) - - assert_raises(Order::AlreadySubmitted) do - act(RemoveItemFromBasket.new(order_id: aggregate_id, product_id: product_id)) - end - end - end -end diff --git a/ecommerce/ordering/test/set_order_as_expired_test.rb b/ecommerce/ordering/test/set_order_as_expired_test.rb deleted file mode 100644 index 33d6cb410..000000000 --- a/ecommerce/ordering/test/set_order_as_expired_test.rb +++ /dev/null @@ -1,46 +0,0 @@ -require_relative "test_helper" - -module Ordering - class SetOrderAsExpiredTest < Test - cover "Ordering::OnSetOrderAsExpired*" - - def test_draft_order_will_expire - aggregate_id = SecureRandom.uuid - stream = "Ordering::Order$#{aggregate_id}" - product_id = SecureRandom.uuid - - arrange( - AddItemToBasket.new( - order_id: aggregate_id, - product_id: product_id - ) - ) - - assert_events( - stream, - OrderExpired.new(data: { order_id: aggregate_id }) - ) { act(SetOrderAsExpired.new(order_id: aggregate_id)) } - end - - def test_submitted_order_will_not_expire - 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 - ) - ) - - assert_raises(Order::AlreadySubmitted) { act(SetOrderAsExpired.new(order_id: aggregate_id)) } - end - end -end diff --git a/ecommerce/ordering/test/submit_order_test.rb b/ecommerce/ordering/test/submit_order_test.rb deleted file mode 100644 index a9a579596..000000000 --- a/ecommerce/ordering/test/submit_order_test.rb +++ /dev/null @@ -1,75 +0,0 @@ -require_relative "test_helper" - -module Ordering - class SubmitOrderTest < Test - cover "Ordering::OnSubmitOrder*" - - def test_order_is_submitted - aggregate_id = SecureRandom.uuid - stream = "Ordering::Order$#{aggregate_id}" - product_id = SecureRandom.uuid - order_number = FakeNumberGenerator::FAKE_NUMBER - arrange( - AddItemToBasket.new( - order_id: aggregate_id, - product_id: product_id - ) - ) - - assert_events( - stream, - OrderSubmitted.new( - data: { - order_id: aggregate_id, - order_number: order_number, - order_lines: { product_id => 1 } - } - ) - ) do - act(SubmitOrder.new(order_id: aggregate_id)) - end - end - - def test_already_created_order_could_not_be_created_again - aggregate_id = SecureRandom.uuid - product_id = SecureRandom.uuid - order_number = FakeNumberGenerator::FAKE_NUMBER - - arrange( - AddItemToBasket.new( - order_id: aggregate_id, - product_id: product_id - ), - SubmitOrder.new( - order_id: aggregate_id, - order_number: order_number, - ) - ) - - assert_raises(Order::AlreadySubmitted) do - act( - SubmitOrder.new( - order_id: aggregate_id - ) - ) - end - end - - def test_expired_order_could_not_be_created - aggregate_id = SecureRandom.uuid - product_id = SecureRandom.uuid - - arrange( - AddItemToBasket.new( - order_id: aggregate_id, - product_id: product_id - ), - SetOrderAsExpired.new(order_id: aggregate_id) - ) - - assert_raises(Order::OrderHasExpired) do - act(SubmitOrder.new(order_id: aggregate_id)) - end - end - end -end diff --git a/ecommerce/ordering/test/test_helper.rb b/ecommerce/ordering/test/test_helper.rb deleted file mode 100644 index 9097c977d..000000000 --- a/ecommerce/ordering/test/test_helper.rb +++ /dev/null @@ -1,14 +0,0 @@ -require "minitest/autorun" -require "mutant/minitest/coverage" - -require_relative "../lib/ordering" - -module Ordering - class Test < Infra::InMemoryTest - def before_setup - super - number_generator = FakeNumberGenerator.new - Configuration.new(-> { number_generator }).call(event_store, command_bus) - end - end -end diff --git a/ecommerce/payments/.mutant.yml b/ecommerce/payments/.mutant.yml deleted file mode 100644 index 68e0d18f9..000000000 --- a/ecommerce/payments/.mutant.yml +++ /dev/null @@ -1,12 +0,0 @@ -requires: - - ./test/test_helper -integration: minitest -coverage_criteria: - process_abort: true -matcher: - subjects: - - Payments* - ignore: - - Payments::Payment#authorized? - - Payments::Test* - - Payments::Configuration#call diff --git a/ecommerce/payments/Gemfile b/ecommerce/payments/Gemfile deleted file mode 100644 index 00fef6d3c..000000000 --- a/ecommerce/payments/Gemfile +++ /dev/null @@ -1,4 +0,0 @@ -source "https://rubygems.org" - -eval_gemfile "../../infra/Gemfile.test" -gem "infra", path: "../../infra" diff --git a/ecommerce/payments/Gemfile.lock b/ecommerce/payments/Gemfile.lock deleted file mode 100644 index 4a73abff2..000000000 --- a/ecommerce/payments/Gemfile.lock +++ /dev/null @@ -1,119 +0,0 @@ -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.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.13.0) - ruby_event_store (= 2.13.0) - arkency-command_bus (0.4.1) - concurrent-ruby - ast (2.4.2) - base64 (0.2.0) - bigdecimal (3.1.4) - concurrent-ruby (1.2.2) - connection_pool (2.4.1) - diff-lcs (1.5.0) - drb (2.2.0) - ruby2_keywords - 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.1) - concurrent-ruby (~> 1.0) - dry-core (~> 1.0) - dry-inflector (~> 1.0) - dry-logic (~> 1.4) - zeitwerk (~> 2.6) - i18n (1.14.1) - 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.8) - rake (13.1.0) - redis-client (0.19.0) - connection_pool - regexp_parser (2.8.3) - ruby2_keywords (0.0.5) - ruby_event_store (2.13.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.0) - concurrent-ruby (< 2) - connection_pool (>= 2.3.0) - rack (>= 2.2.4) - redis-client (>= 0.14.0) - sorbet-runtime (0.5.11190) - tzinfo (2.0.6) - concurrent-ruby (~> 1.0) - unparser (0.6.12) - diff-lcs (~> 1.3) - parser (>= 3.2.2.4) - zeitwerk (2.6.12) - -PLATFORMS - arm64-darwin-20 - arm64-darwin-21 - ruby - x86_64-darwin-20 - x86_64-linux - -DEPENDENCIES - infra! - minitest (= 5.15.0)! - mutant-license! - mutant-minitest (= 0.11.26)! - -BUNDLED WITH - 2.5.9 diff --git a/ecommerce/payments/Makefile b/ecommerce/payments/Makefile deleted file mode 100644 index 23850fab1..000000000 --- a/ecommerce/payments/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -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/payments/README.md b/ecommerce/payments/README.md deleted file mode 100644 index 4dfa6901f..000000000 --- a/ecommerce/payments/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# Payments - -[![Build Status](https://github.com/RailsEventStore/cqrs-es-sample-with-res/workflows/payments/badge.svg)](https://github.com/RailsEventStore/cqrs-es-sample-with-res/actions/workflows/payments.yml) - -The `Payments::Payment` aggregate manages the following states: - -- authorized -- captured -- released - -This Payment object is fully event sourced. - -#### Up and running - -``` -make install test mutate -``` diff --git a/ecommerce/payments/lib/payments.rb b/ecommerce/payments/lib/payments.rb deleted file mode 100644 index bd6eb54de..000000000 --- a/ecommerce/payments/lib/payments.rb +++ /dev/null @@ -1,27 +0,0 @@ -require "infra" -require_relative "payments/commands" -require_relative "payments/events" -require_relative "payments/on_set_payment_amount" -require_relative "payments/on_authorize_payment" -require_relative "payments/on_capture_payment" -require_relative "payments/on_release_payment" -require_relative "payments/fake_gateway" -require_relative "payments/payment" - -module Payments - class Configuration - def initialize(gateway) - @gateway = gateway - end - - def call(event_store, command_bus) - command_bus.register( - AuthorizePayment, - OnAuthorizePayment.new(event_store, @gateway) - ) - command_bus.register(CapturePayment, OnCapturePayment.new(event_store)) - command_bus.register(ReleasePayment, OnReleasePayment.new(event_store)) - command_bus.register(SetPaymentAmount, OnSetPaymentAmount.new(event_store)) - end - end -end diff --git a/ecommerce/payments/lib/payments/commands.rb b/ecommerce/payments/lib/payments/commands.rb deleted file mode 100644 index e6c1e086d..000000000 --- a/ecommerce/payments/lib/payments/commands.rb +++ /dev/null @@ -1,18 +0,0 @@ -module Payments - class SetPaymentAmount < Infra::Command - attribute :order_id, Infra::Types::UUID - attribute :amount, Infra::Types::Nominal::Decimal - end - - class AuthorizePayment < Infra::Command - attribute :order_id, Infra::Types::UUID - end - - class CapturePayment < Infra::Command - attribute :order_id, Infra::Types::UUID - end - - class ReleasePayment < Infra::Command - attribute :order_id, Infra::Types::UUID - end -end diff --git a/ecommerce/payments/lib/payments/events.rb b/ecommerce/payments/lib/payments/events.rb deleted file mode 100644 index 322474e7d..000000000 --- a/ecommerce/payments/lib/payments/events.rb +++ /dev/null @@ -1,18 +0,0 @@ -module Payments - class PaymentAmountSet < Infra::Event - attribute :order_id, Infra::Types::UUID - attribute :amount, Infra::Types::Nominal::Decimal - end - - class PaymentAuthorized < Infra::Event - attribute :order_id, Infra::Types::UUID - end - - class PaymentCaptured < Infra::Event - attribute :order_id, Infra::Types::UUID - end - - class PaymentReleased < Infra::Event - attribute :order_id, Infra::Types::UUID - end -end diff --git a/ecommerce/payments/lib/payments/fake_gateway.rb b/ecommerce/payments/lib/payments/fake_gateway.rb deleted file mode 100644 index ba71d6b7e..000000000 --- a/ecommerce/payments/lib/payments/fake_gateway.rb +++ /dev/null @@ -1,19 +0,0 @@ -module Payments - class FakeGateway - def initialize - @authorized_transactions = [] - end - - def reset - @authorized_transactions = [] - end - - def authorize_transaction(transaction_id, amount) - authorized_transactions << [transaction_id, amount] - end - - def authorized_transactions - @authorized_transactions - end - end -end diff --git a/ecommerce/payments/lib/payments/on_authorize_payment.rb b/ecommerce/payments/lib/payments/on_authorize_payment.rb deleted file mode 100644 index 182112e68..000000000 --- a/ecommerce/payments/lib/payments/on_authorize_payment.rb +++ /dev/null @@ -1,15 +0,0 @@ -module Payments - class OnAuthorizePayment - def initialize(event_store, gateway) - @repository = AggregateRoot::Repository.new(event_store) - @gateway = gateway - end - - def call(command) - @repository.with_aggregate( - Payment.new, - "Payments::Payment$#{command.order_id}" - ) { |payment| payment.authorize(command.order_id, @gateway.call) } - end - end -end diff --git a/ecommerce/payments/lib/payments/on_capture_payment.rb b/ecommerce/payments/lib/payments/on_capture_payment.rb deleted file mode 100644 index 4fbe70cbf..000000000 --- a/ecommerce/payments/lib/payments/on_capture_payment.rb +++ /dev/null @@ -1,14 +0,0 @@ -module Payments - class OnCapturePayment - def initialize(event_store) - @repository = AggregateRoot::Repository.new(event_store) - end - - def call(command) - @repository.with_aggregate( - Payment.new, - "Payments::Payment$#{command.order_id}" - ) { |payment| payment.capture } - end - end -end diff --git a/ecommerce/payments/lib/payments/on_release_payment.rb b/ecommerce/payments/lib/payments/on_release_payment.rb deleted file mode 100644 index 15a3999c6..000000000 --- a/ecommerce/payments/lib/payments/on_release_payment.rb +++ /dev/null @@ -1,14 +0,0 @@ -module Payments - class OnReleasePayment - def initialize(event_store) - @repository = AggregateRoot::Repository.new(event_store) - end - - def call(command) - @repository.with_aggregate( - Payment.new, - "Payments::Payment$#{command.order_id}" - ) { |payment| payment.release } - end - end -end diff --git a/ecommerce/payments/lib/payments/on_set_payment_amount.rb b/ecommerce/payments/lib/payments/on_set_payment_amount.rb deleted file mode 100644 index 25f528c59..000000000 --- a/ecommerce/payments/lib/payments/on_set_payment_amount.rb +++ /dev/null @@ -1,14 +0,0 @@ -module Payments - class OnSetPaymentAmount - def initialize(event_store) - @repository = AggregateRoot::Repository.new(event_store) - end - - def call(command) - @repository.with_aggregate( - Payment.new, - "Payments::Payment$#{command.order_id}" - ) { |payment| payment.set_amount(command.order_id, command.amount) } - end - end -end diff --git a/ecommerce/payments/lib/payments/payment.rb b/ecommerce/payments/lib/payments/payment.rb deleted file mode 100644 index 2c43716ef..000000000 --- a/ecommerce/payments/lib/payments/payment.rb +++ /dev/null @@ -1,64 +0,0 @@ -module Payments - class Payment - include AggregateRoot - - AlreadyAuthorized = Class.new(StandardError) - NotAuthorized = Class.new(StandardError) - AlreadyCaptured = Class.new(StandardError) - AlreadyReleased = Class.new(StandardError) - - def set_amount(order_id, amount) - apply(PaymentAmountSet.new(data: { order_id: order_id, amount: amount })) - end - - def authorize(order_id, gateway) - raise AlreadyAuthorized if authorized? - gateway.authorize_transaction(order_id, @amount) - apply(PaymentAuthorized.new(data: { order_id: order_id })) - end - - def capture - raise AlreadyCaptured if captured? - raise NotAuthorized unless authorized? - apply(PaymentCaptured.new(data: { order_id: @order_id })) - end - - def release - raise AlreadyReleased if released? - raise AlreadyCaptured if captured? - raise NotAuthorized unless authorized? - apply(PaymentReleased.new(data: { order_id: @order_id })) - end - - private - - on PaymentAmountSet do |event| - @amount = event.data.fetch(:amount) - end - - on PaymentAuthorized do |event| - @state = :authorized - @order_id = event.data.fetch(:order_id) - end - - on PaymentCaptured do |event| - @state = :captured - end - - on PaymentReleased do |event| - @state = :released - end - - def authorized? - @state.equal?(:authorized) - end - - def captured? - @state.equal?(:captured) - end - - def released? - @state.equal?(:released) - end - end -end diff --git a/ecommerce/payments/test/fake_gateway_test.rb b/ecommerce/payments/test/fake_gateway_test.rb deleted file mode 100644 index 4010c5bd9..000000000 --- a/ecommerce/payments/test/fake_gateway_test.rb +++ /dev/null @@ -1,15 +0,0 @@ -require_relative "test_helper" - -module Payments - class FakeGatewayTest < Test - cover "Payments::FakeGateway*" - - def test_happy_path - gateway = FakeGateway.new - gateway.authorize_transaction("12", 20) - assert_equal([["12", 20]], gateway.authorized_transactions) - gateway.reset - assert_equal([], gateway.authorized_transactions) - end - end -end diff --git a/ecommerce/payments/test/on_capture_payment_test.rb b/ecommerce/payments/test/on_capture_payment_test.rb deleted file mode 100644 index 9ebca5ea0..000000000 --- a/ecommerce/payments/test/on_capture_payment_test.rb +++ /dev/null @@ -1,24 +0,0 @@ -require_relative "test_helper" - -module Payments - class OnCapturePaymentTest < Test - cover "Payments::OnCapturePayment*" - - def test_capture_payment - order_id = SecureRandom.uuid - stream = "Payments::Payment$#{order_id}" - - arrange( - SetPaymentAmount.new(order_id: order_id, amount: 20), - AuthorizePayment.new(order_id: order_id) - ) - - assert_equal(20, payment_gateway.authorized_transactions[0][1]) - - assert_events( - stream, - PaymentCaptured.new(data: { order_id: order_id }) - ) { act(CapturePayment.new(order_id: order_id)) } - end - end -end diff --git a/ecommerce/payments/test/on_release_payment_test.rb b/ecommerce/payments/test/on_release_payment_test.rb deleted file mode 100644 index 5f5bf3f89..000000000 --- a/ecommerce/payments/test/on_release_payment_test.rb +++ /dev/null @@ -1,21 +0,0 @@ -require_relative "test_helper" - -module Payments - class OnReleasePaymentTest < Test - cover "Payments::OnReleasePayment*" - - def test_capture_payment - order_id = SecureRandom.uuid - stream = "Payments::Payment$#{order_id}" - - arrange( - AuthorizePayment.new(order_id: order_id) - ) - - assert_events( - stream, - PaymentReleased.new(data: { order_id: order_id }) - ) { act(ReleasePayment.new(order_id: order_id)) } - end - end -end diff --git a/ecommerce/payments/test/payment_test.rb b/ecommerce/payments/test/payment_test.rb deleted file mode 100644 index 3dfd77f6b..000000000 --- a/ecommerce/payments/test/payment_test.rb +++ /dev/null @@ -1,103 +0,0 @@ -require_relative "test_helper" - -module Payments - class PaymentTest < Test - cover "Payments::Payment*" - - def test_authorize_publishes_event - payment = Payment.new - gateway = FakeGateway.new - payment.set_amount(order_id, 20) - payment.authorize(order_id, gateway) - assert_changes( - payment.unpublished_events, - [ - PaymentAmountSet.new(data: { order_id: order_id, amount: 20 }), - PaymentAuthorized.new(data: { order_id: order_id }) - ] - ) - end - - def test_authorize_contacts_gateway - payment = Payment.new - gateway = FakeGateway.new - payment.set_amount(order_id, 20) - payment.authorize(order_id, gateway) - assert(gateway.authorized_transactions.include?([order_id, 20])) - end - - def test_should_not_allow_for_double_authorization - assert_raises(Payment::AlreadyAuthorized) do - authorized_payment.authorize(order_id, nil) - end - end - - def test_should_capture_authorized_payment - payment = authorized_payment - before = payment.unpublished_events.to_a - - payment.capture - actual = payment.unpublished_events.to_a - before - assert_changes( - actual, - [PaymentCaptured.new(data: { order_id: order_id })] - ) - end - - def test_must_not_capture_not_authorized_payment - assert_raises(Payment::NotAuthorized) { Payment.new.capture } - end - - def test_should_not_allow_for_double_capture - assert_raises(Payment::AlreadyCaptured) { captured_payment.capture } - end - - def test_authorization_could_be_released - payment = authorized_payment - before = payment.unpublished_events.to_a - - payment.release - actual = payment.unpublished_events.to_a - before - assert_changes( - actual, - [PaymentReleased.new(data: { order_id: order_id })] - ) - end - - def test_must_not_release_not_captured_payment - assert_raises(Payment::AlreadyCaptured) { captured_payment.release } - end - - def test_must_not_release_not_authorized_payment - assert_raises(Payment::NotAuthorized) { Payment.new.release } - end - - def test_should_not_allow_for_double_release - assert_raises(Payment::AlreadyReleased) { released_payment.release } - end - - private - - def order_id - @order_id ||= SecureRandom.uuid - end - - def authorized_payment - Payment.new.tap do |payment| - payment.apply(PaymentAuthorized.new(data: { order_id: order_id })) - end - end - - def captured_payment - authorized_payment.tap do |payment| - payment.apply(PaymentCaptured.new(data: { order_id: order_id })) - end - end - - def released_payment - captured_payment.tap do |payment| - payment.apply(PaymentReleased.new(data: { order_id: order_id })) - end - end - end -end diff --git a/ecommerce/payments/test/test_helper.rb b/ecommerce/payments/test/test_helper.rb deleted file mode 100644 index 5e21bf0ce..000000000 --- a/ecommerce/payments/test/test_helper.rb +++ /dev/null @@ -1,16 +0,0 @@ -require "minitest/autorun" -require "mutant/minitest/coverage" - -require_relative "../lib/payments" - -module Payments - class Test < Infra::InMemoryTest - attr_reader :payment_gateway - - def before_setup - super - @payment_gateway = FakeGateway.new - Configuration.new(-> { @payment_gateway }).call(event_store, command_bus) - end - end -end diff --git a/ecommerce/pricing/.mutant.yml b/ecommerce/pricing/.mutant.yml deleted file mode 100644 index 26bd2ad34..000000000 --- a/ecommerce/pricing/.mutant.yml +++ /dev/null @@ -1,13 +0,0 @@ -requires: - - ./test/test_helper -integration: minitest -coverage_criteria: - process_abort: true -matcher: - subjects: - - Pricing* - ignore: - - Pricing::Configuration* - - Pricing::Test* - - Pricing::OnCalculateTotalValue#call - - Pricing::OnCalculateTotalValue#calculate_sub_amounts \ No newline at end of file diff --git a/ecommerce/pricing/Gemfile b/ecommerce/pricing/Gemfile deleted file mode 100644 index acd69f632..000000000 --- a/ecommerce/pricing/Gemfile +++ /dev/null @@ -1,8 +0,0 @@ -source "https://rubygems.org" - -eval_gemfile "../../infra/Gemfile.test" -gem "infra", path: "../../infra" - -group :test do - gem "timecop" -end diff --git a/ecommerce/pricing/Gemfile.lock b/ecommerce/pricing/Gemfile.lock deleted file mode 100644 index d7e4ebf47..000000000 --- a/ecommerce/pricing/Gemfile.lock +++ /dev/null @@ -1,121 +0,0 @@ -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.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.13.0) - ruby_event_store (= 2.13.0) - arkency-command_bus (0.4.1) - concurrent-ruby - ast (2.4.2) - base64 (0.2.0) - bigdecimal (3.1.4) - concurrent-ruby (1.2.2) - connection_pool (2.4.1) - diff-lcs (1.5.0) - drb (2.2.0) - ruby2_keywords - 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.1) - concurrent-ruby (~> 1.0) - dry-core (~> 1.0) - dry-inflector (~> 1.0) - dry-logic (~> 1.4) - zeitwerk (~> 2.6) - i18n (1.14.1) - 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.8) - rake (13.1.0) - redis-client (0.19.0) - connection_pool - regexp_parser (2.8.3) - ruby2_keywords (0.0.5) - ruby_event_store (2.13.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.0) - concurrent-ruby (< 2) - connection_pool (>= 2.3.0) - rack (>= 2.2.4) - redis-client (>= 0.14.0) - sorbet-runtime (0.5.11190) - timecop (0.9.8) - tzinfo (2.0.6) - concurrent-ruby (~> 1.0) - unparser (0.6.12) - diff-lcs (~> 1.3) - parser (>= 3.2.2.4) - zeitwerk (2.6.12) - -PLATFORMS - arm64-darwin-20 - arm64-darwin-21 - ruby - x86_64-darwin-20 - x86_64-linux - -DEPENDENCIES - infra! - minitest (= 5.15.0)! - mutant-license! - mutant-minitest (= 0.11.26)! - timecop - -BUNDLED WITH - 2.5.9 diff --git a/ecommerce/pricing/Makefile b/ecommerce/pricing/Makefile deleted file mode 100644 index 23850fab1..000000000 --- a/ecommerce/pricing/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -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/pricing/README.md b/ecommerce/pricing/README.md deleted file mode 100644 index f323e315c..000000000 --- a/ecommerce/pricing/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# Pricing - -[![Build Status](https://github.com/RailsEventStore/cqrs-es-sample-with-res/workflows/pricing/badge.svg)](https://github.com/RailsEventStore/cqrs-es-sample-with-res/actions/workflows/pricing.yml) - -The `Pricing::Coupon` aggregate manages the creation and usage of a coupon. This includes as of now: - -- registration - -After each successful action an appropriate event is published in the Coupon stream. - -| Command | Event | Service used to apply | -|:---------------:|:-----:|:----------------------| -| RegisterCoupon | CouponRegistered | OnCouponRegister | - -#### Up and running - -``` -make install test mutate -``` diff --git a/ecommerce/pricing/lib/pricing.rb b/ecommerce/pricing/lib/pricing.rb deleted file mode 100644 index 789b5e0f6..000000000 --- a/ecommerce/pricing/lib/pricing.rb +++ /dev/null @@ -1,109 +0,0 @@ -require "infra" -require_relative "pricing/discounts" -require_relative "pricing/coupon" -require_relative "pricing/commands" -require_relative "pricing/events" -require_relative "pricing/services" -require_relative "pricing/offer" -require_relative "pricing/price_change" -require_relative "pricing/pricing_catalog" -require_relative "pricing/time_promotion" -require_relative "pricing/promotions_calendar" -require_relative "pricing/calculate_order_sub_amounts_value" -require_relative "pricing/calculate_order_total_value" - -module Pricing - def self.command_bus=(value) - @command_bus = value - end - - def self.command_bus - @command_bus - end - - def self.event_store=(value) - @event_store = value - end - - def self.event_store - @event_store - end - - class Configuration - def call(event_store, command_bus) - Pricing.event_store = event_store - Pricing.command_bus = command_bus - - command_bus.register( - AddPriceItem, - OnAddItemToBasket.new(event_store) - ) - command_bus.register( - RemovePriceItem, - OnRemoveItemFromBasket.new(event_store) - ) - command_bus.register( - SetPrice, - SetPriceHandler.new(event_store) - ) - command_bus.register( - SetFuturePrice, - SetFuturePriceHandler.new(event_store) - ) - command_bus.register( - CalculateTotalValue, - OnCalculateTotalValue.new(event_store) - ) - command_bus.register( - CalculateSubAmounts, - OnCalculateTotalValue.new(event_store).public_method(:calculate_sub_amounts) - ) - command_bus.register( - SetPercentageDiscount, - SetPercentageDiscountHandler.new(event_store) - ) - command_bus.register( - ResetPercentageDiscount, - ResetPercentageDiscountHandler.new(event_store) - ) - command_bus.register( - ChangePercentageDiscount, - ChangePercentageDiscountHandler.new(event_store) - ) - command_bus.register( - RegisterCoupon, - OnCouponRegister.new(event_store) - ) - command_bus.register( - CreateTimePromotion, - CreateTimePromotionHandler.new(event_store) - ) - command_bus.register( - MakeProductFreeForOrder, - MakeProductFreeForOrderHandler.new(event_store) - ) - command_bus.register( - RemoveFreeProductFromOrder, - RemoveFreeProductFromOrderHandler.new(event_store) - ) - event_store.subscribe(CalculateOrderTotalValue, to: [ - PriceItemAdded, - PriceItemRemoved, - PercentageDiscountSet, - PercentageDiscountReset, - PercentageDiscountChanged, - ProductMadeFreeForOrder, - FreeProductRemovedFromOrder - ]) - event_store.subscribe(CalculateOrderTotalSubAmountsValue, to: [ - PriceItemAdded, - PriceItemRemoved, - PercentageDiscountSet, - PercentageDiscountReset, - PercentageDiscountChanged, - ProductMadeFreeForOrder, - FreeProductRemovedFromOrder - ]) - end - end -end diff --git a/ecommerce/pricing/lib/pricing/calculate_order_sub_amounts_value.rb b/ecommerce/pricing/lib/pricing/calculate_order_sub_amounts_value.rb deleted file mode 100644 index aab491c25..000000000 --- a/ecommerce/pricing/lib/pricing/calculate_order_sub_amounts_value.rb +++ /dev/null @@ -1,14 +0,0 @@ -module Pricing - class CalculateOrderTotalSubAmountsValue - def call(event) - command_bus.(CalculateSubAmounts.new(order_id: event.data.fetch(:order_id))) - end - - private - - def command_bus - Pricing.command_bus - end - end -end - diff --git a/ecommerce/pricing/lib/pricing/calculate_order_total_value.rb b/ecommerce/pricing/lib/pricing/calculate_order_total_value.rb deleted file mode 100644 index e09298c0a..000000000 --- a/ecommerce/pricing/lib/pricing/calculate_order_total_value.rb +++ /dev/null @@ -1,14 +0,0 @@ -module Pricing - class CalculateOrderTotalValue - def call(event) - command_bus.(CalculateTotalValue.new(order_id: event.data.fetch(:order_id))) - end - - private - - def command_bus - Pricing.command_bus - end - end -end - diff --git a/ecommerce/pricing/lib/pricing/commands.rb b/ecommerce/pricing/lib/pricing/commands.rb deleted file mode 100644 index 596077c08..000000000 --- a/ecommerce/pricing/lib/pricing/commands.rb +++ /dev/null @@ -1,83 +0,0 @@ -module Pricing - class AddPriceItem < Infra::Command - attribute :order_id, Infra::Types::UUID - attribute :product_id, Infra::Types::UUID - - alias aggregate_id order_id - end - - class RemovePriceItem < Infra::Command - attribute :order_id, Infra::Types::UUID - attribute :product_id, Infra::Types::UUID - - alias aggregate_id order_id - end - - class CalculateTotalValue < Infra::Command - attribute :order_id, Infra::Types::UUID - alias aggregate_id order_id - end - - class CalculateSubAmounts < Infra::Command - attribute :order_id, Infra::Types::UUID - alias aggregate_id order_id - end - - class SetPrice < Infra::Command - attribute :product_id, Infra::Types::UUID - attribute :price, Infra::Types::Price - end - - class SetFuturePrice < Infra::Command - attribute :product_id, Infra::Types::UUID - attribute :price, Infra::Types::Price - attribute :valid_since, Infra::Types::Time - end - - class SetPercentageDiscount < Infra::Command - attribute :order_id, Infra::Types::UUID - attribute :amount, Infra::Types::PercentageDiscount - alias aggregate_id order_id - end - - class ResetPercentageDiscount < 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 - attribute :code, Infra::Types::String - attribute :discount, Infra::Types::CouponDiscount - alias aggregate_id coupon_id - end - - class CreateTimePromotion < Infra::Command - attribute :time_promotion_id, Infra::Types::UUID.meta(omittable: true) - attribute :discount, Infra::Types::PercentageDiscount - attribute :start_time, Infra::Types::Time - attribute :end_time, Infra::Types::Time - attribute :label, Infra::Types::String - end - - class ChangePercentageDiscount < Infra::Command - attribute :order_id, Infra::Types::UUID - attribute :amount, Infra::Types::PercentageDiscount - alias aggregate_id order_id - end - - class MakeProductFreeForOrder < Infra::Command - attribute :order_id, Infra::Types::UUID - attribute :product_id, Infra::Types::UUID - - alias aggregate_id order_id - end - - class RemoveFreeProductFromOrder < Infra::Command - attribute :order_id, Infra::Types::UUID - attribute :product_id, Infra::Types::UUID - - alias aggregate_id order_id - end -end diff --git a/ecommerce/pricing/lib/pricing/coupon.rb b/ecommerce/pricing/lib/pricing/coupon.rb deleted file mode 100644 index 22c343f0a..000000000 --- a/ecommerce/pricing/lib/pricing/coupon.rb +++ /dev/null @@ -1,31 +0,0 @@ -require_relative 'events' - -module Pricing - class Coupon - include AggregateRoot - - AlreadyRegistered = Class.new(StandardError) - - def initialize(id) - @id = id - end - - def register(name, code, discount) - raise AlreadyRegistered if @registered - - apply CouponRegistered.new( - data: { - coupon_id: @id, - name: name, - code: code, - discount: discount - } - ) - end - - on CouponRegistered do |event| - @registered = true - end - end -end - diff --git a/ecommerce/pricing/lib/pricing/discounts.rb b/ecommerce/pricing/lib/pricing/discounts.rb deleted file mode 100644 index 8134c7edd..000000000 --- a/ecommerce/pricing/lib/pricing/discounts.rb +++ /dev/null @@ -1,64 +0,0 @@ -module Pricing - module Discounts - class UnacceptableDiscountRange < StandardError - end - - class Discount - def self.build(discount) - if discount.zero? - NoPercentageDiscount.new - else - PercentageDiscount.new(discount) - end - end - end - - class PercentageDiscount - attr_reader :value - - def initialize(value) - raise UnacceptableDiscountRange if value <= 0 - raise UnacceptableDiscountRange if value > 100 - - @value = value - end - - def apply(total) - total - discount(total) - end - - def add(other_discount) - new_value = [value + other_discount.value, 100].min - - PercentageDiscount.new(new_value) - end - - def exists? - true - end - - private - - def discount(total) - total * value / 100 - end - end - - class NoPercentageDiscount - def apply(total) - total - end - - def add(other_discount) - other_discount - end - - def value - 0 - end - - def exists? - end - end - end -end diff --git a/ecommerce/pricing/lib/pricing/events.rb b/ecommerce/pricing/lib/pricing/events.rb deleted file mode 100644 index 37e57a76e..000000000 --- a/ecommerce/pricing/lib/pricing/events.rb +++ /dev/null @@ -1,68 +0,0 @@ -module Pricing - class CouponRegistered < Infra::Event - attribute :coupon_id, Infra::Types::UUID - attribute :name, Infra::Types::String - attribute :code, Infra::Types::String - attribute :discount, Infra::Types::CouponDiscount - end - - class PriceSet < Infra::Event - attribute :product_id, Infra::Types::UUID - attribute :price, Infra::Types::Price - end - - class TimePromotionCreated < Infra::Event - attribute :time_promotion_id, Infra::Types::UUID - attribute? :discount, Infra::Types::PercentageDiscount - attribute? :start_time, Infra::Types::Time - attribute? :end_time, Infra::Types::Time - end - - class OrderTotalValueCalculated < Infra::Event - attribute :order_id, Infra::Types::UUID - attribute :discounted_amount, Infra::Types::Value - attribute :total_amount, Infra::Types::Value - end - - class PriceItemValueCalculated < Infra::Event - attribute :order_id, Infra::Types::UUID - attribute :product_id, Infra::Types::UUID - attribute :quantity, Infra::Types::Quantity - attribute :discounted_amount, Infra::Types::Value - attribute :amount, Infra::Types::Value - end - - class PercentageDiscountSet < Infra::Event - attribute :order_id, Infra::Types::UUID - attribute :amount, Infra::Types::Price - end - - class PriceItemAdded < Infra::Event - attribute :order_id, Infra::Types::UUID - attribute :product_id, Infra::Types::UUID - end - - class PriceItemRemoved < Infra::Event - attribute :order_id, Infra::Types::UUID - attribute :product_id, Infra::Types::UUID - end - - class PercentageDiscountReset < Infra::Event - attribute :order_id, Infra::Types::UUID - end - - class PercentageDiscountChanged < Infra::Event - attribute :order_id, Infra::Types::UUID - attribute :amount, Infra::Types::Price - end - - class ProductMadeFreeForOrder < Infra::Event - attribute :order_id, Infra::Types::UUID - attribute :product_id, Infra::Types::UUID - end - - class FreeProductRemovedFromOrder < Infra::Event - attribute :order_id, Infra::Types::UUID - attribute :product_id, Infra::Types::UUID - end -end diff --git a/ecommerce/pricing/lib/pricing/offer.rb b/ecommerce/pricing/lib/pricing/offer.rb deleted file mode 100644 index 38b221441..000000000 --- a/ecommerce/pricing/lib/pricing/offer.rb +++ /dev/null @@ -1,251 +0,0 @@ -module Pricing - class Offer - include AggregateRoot - - def initialize(id) - @id = id - @list = List.new - @discount = Discounts::NoPercentageDiscount.new - end - - def add_item(product_id) - apply PriceItemAdded.new( - data: { - order_id: @id, - product_id: product_id - } - ) - end - - def remove_item(product_id) - apply PriceItemRemoved.new( - data: { - order_id: @id, - product_id: product_id - } - ) - end - - def apply_discount(discount) - raise NotPossibleToAssignDiscountTwice if @discount.exists? - apply PercentageDiscountSet.new( - data: { - order_id: @id, - amount: discount.value - } - ) - end - - def change_discount(discount) - raise NotPossibleToChangeDiscount unless @discount.exists? - apply PercentageDiscountChanged.new( - data: { - order_id: @id, - amount: discount.value - } - ) - end - - def reset_discount - raise NotPossibleToResetWithoutDiscount unless @discount.exists? - apply PercentageDiscountReset.new( - data: { - order_id: @id - } - ) - end - - def make_product_free(order_id, product_id) - raise FreeProductAlreadyMade if @list.contains_free_products? - apply ProductMadeFreeForOrder.new( - data: { - order_id: order_id, - product_id: product_id - } - ) - end - - def remove_free_product(order_id, product_id) - raise FreeProductNotExists unless @list.contains_free_products? - apply FreeProductRemovedFromOrder.new( - data: { - order_id: order_id, - product_id: product_id - } - ) - end - - def calculate_total_value(pricing_catalog, time_promotion_discount) - total_value = @list.base_sum(pricing_catalog) - - discounted_value = @discount.add(time_promotion_discount).apply(total_value) - apply( - OrderTotalValueCalculated.new( - data: { - order_id: @id, - total_amount: total_value, - discounted_amount: discounted_value - } - ) - ) - end - - def calculate_sub_amounts(pricing_catalog, time_promotions_discount) - sub_amounts_total = @list.sub_amounts_total(pricing_catalog) - sub_discounts = calculate_total_sub_discounts(pricing_catalog, time_promotions_discount) - - products = @list.products - quantities = @list.quantities - products.zip(quantities, sub_amounts_total, sub_discounts) do |product, quantity, sub_amount, sub_discount| - apply( - PriceItemValueCalculated.new( - data: { - order_id: @id, - product_id: product.id, - quantity: quantity, - amount: sub_amount, - discounted_amount: sub_amount - sub_discount - } - ) - ) - end - end - - private - - on PriceItemAdded do |event| - @list.add_item(Product.new(event.data.fetch(:product_id))) - end - - on PriceItemRemoved do |event| - @list.remove_item(event.data.fetch(:product_id)) - end - - on PriceItemValueCalculated do |event| - end - - on OrderTotalValueCalculated do |event| - end - - on PercentageDiscountSet do |event| - @discount = Discounts::PercentageDiscount.new(event.data.fetch(:amount)) - end - - on PercentageDiscountChanged do |event| - @discount = Discounts::PercentageDiscount.new(event.data.fetch(:amount)) - end - - on PercentageDiscountReset do |event| - @discount = Discounts::NoPercentageDiscount.new - end - - on ProductMadeFreeForOrder do |event| - @list.replace(Product, FreeProduct, event.data.fetch(:product_id)) - end - - on FreeProductRemovedFromOrder do |event| - @list.replace(FreeProduct, Product, event.data.fetch(:product_id)) - end - - def calculate_total_sub_discounts(pricing_catalog, time_promotions_discount) - @list.sub_discounts(pricing_catalog, time_promotions_discount, @discount) - end - - class List - - def initialize - @products_quantities = Hash.new(0) - end - - def add_item(product) - @products_quantities[product] += 1 - end - - def remove_item(product_id) - @products_quantities[Product.new(product_id)] -= 1 - clear_empty_products - end - - def clear_empty_products - @products_quantities.delete_if { |_, value| value.zero? } - end - - def replace(from, to, product_id) - @products_quantities[from.new(product_id)] -= 1 - @products_quantities[to.new(product_id)] += 1 - clear_empty_products - end - - def products - @products_quantities.keys - end - - def quantities - @products_quantities.values - end - - def contains_free_products? - @products_quantities.keys.any? {|key| key.free? } - end - - def base_sum(pricing_catalog) - @products_quantities.sum { |product, qty| pricing_catalog.price_for(product) * qty } - end - - def sub_amounts_total(pricing_catalog) - @products_quantities.map { |product, quantity| quantity * pricing_catalog.price_for(product) } - end - - def sub_discounts(pricing_catalog, time_promotions_discount, discount) - @products_quantities.map do |product, quantity| - catalog_price_for_single = pricing_catalog.price_for(product) - with_total_discount_single = discount.add(time_promotions_discount).apply(catalog_price_for_single) - quantity * (catalog_price_for_single - with_total_discount_single) - end - end - end - - class Product - attr_reader :id - - def initialize(id) - @id = id - end - - def free? - end - - def eql?(other) - other.instance_of?(Product) && id.eql?(other.id) - end - - alias == eql? - - def hash - Product.hash ^ id.hash - end - end - - class FreeProduct - attr_reader :id - - def initialize(id) - @id = id - end - - def free? - true - end - - def eql?(other) - other.instance_of?(FreeProduct) && id.eql?(other.id) - end - - alias == eql? - - def hash - FreeProduct.hash ^ id.hash - end - end - end -end diff --git a/ecommerce/pricing/lib/pricing/price_change.rb b/ecommerce/pricing/lib/pricing/price_change.rb deleted file mode 100644 index 5bfa92db1..000000000 --- a/ecommerce/pricing/lib/pricing/price_change.rb +++ /dev/null @@ -1,17 +0,0 @@ -module Pricing - class PriceChange - include AggregateRoot - - def initialize(product_id) - @product_id = product_id - end - - def set_price(price) - apply(PriceSet.new(data: { product_id: @product_id, price: price })) - end - - private - - on(PriceSet) { |_| } - end -end diff --git a/ecommerce/pricing/lib/pricing/pricing_catalog.rb b/ecommerce/pricing/lib/pricing/pricing_catalog.rb deleted file mode 100644 index f2b8f53d5..000000000 --- a/ecommerce/pricing/lib/pricing/pricing_catalog.rb +++ /dev/null @@ -1,59 +0,0 @@ -module Pricing - class PricingCatalog - def initialize(event_store) - @event_store = event_store - end - - def price_for(product) - case product - when Offer::FreeProduct - 0 - else - price_by_product_id(product.id) - end - end - - def price_by_product_id(product_id) - current_price(product_id) - .data - .fetch(:price) - end - - def current_prices_catalog_by_product_id(product_id) - ([current_price(product_id)] + future_prices_catalog_by_product_id(product_id)).map(&method(:to_calendar_entry)) - end - - private - - def future_prices_catalog_by_product_id(product_id) - read_prices_set(product_id) - .select(&method(:future_prices)) - end - - def current_price(product_id) - read_prices_set(product_id) - .reject(&method(:future_prices)) - .last - end - - def read_prices_set(product_id) - @event_store - .read - .of_type(PriceSet) - .as_of - .to_a - .filter { |e| e.data.fetch(:product_id).eql?(product_id) } - end - - def future_prices(e) - e.metadata.fetch(:valid_at) > Time.now - end - - def to_calendar_entry(e) - { - price: e.data.fetch(:price), - valid_since: e.metadata.fetch(:valid_at) - } - end - end -end diff --git a/ecommerce/pricing/lib/pricing/promotions_calendar.rb b/ecommerce/pricing/lib/pricing/promotions_calendar.rb deleted file mode 100644 index 8c82a3f21..000000000 --- a/ecommerce/pricing/lib/pricing/promotions_calendar.rb +++ /dev/null @@ -1,40 +0,0 @@ -module Pricing - class PromotionsCalendar - def initialize(event_store) - @event_store = event_store - end - - def current_time_promotions_discount - Discounts::Discount.build( - get_events(TimePromotionCreated) - .filter { |e| current_promotions.include?(e.data.fetch(:time_promotion_id)) } - .map { |e| e.data.fetch(:discount) }.sum - ) - end - - private - - def current_promotions - get_events(TimePromotionCreated) - .filter { |e| is_promotion_running?(e) } - .map { |e| e.data.fetch(:time_promotion_id) } - end - - def is_promotion_running?(event) - timestamp = Time.current - start_time = event.data.fetch(:start_time) - end_time = event.data.fetch(:end_time) - - timestamp >= start_time && end_time > timestamp - end - - def get_events(event_type) - @event_store - .read - .of_type(event_type) - .to_a - .group_by { |e| e.data.fetch(:time_promotion_id) } - .map { |_, events| events.max_by(&:timestamp) } - end - end -end diff --git a/ecommerce/pricing/lib/pricing/services.rb b/ecommerce/pricing/lib/pricing/services.rb deleted file mode 100644 index 1ac73249f..000000000 --- a/ecommerce/pricing/lib/pricing/services.rb +++ /dev/null @@ -1,183 +0,0 @@ -module Pricing - class NotPossibleToAssignDiscountTwice < StandardError - end - - class NotPossibleToResetWithoutDiscount < StandardError - end - - class NotPossibleToChangeDiscount < StandardError - end - - class FreeProductAlreadyMade < StandardError - end - - class FreeProductNotExists < StandardError - end - - class SetPercentageDiscountHandler - 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_discount(Discounts::PercentageDiscount.new(cmd.amount)) - end - end - end - - class ResetPercentageDiscountHandler - 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_discount - end - end - end - - class ChangePercentageDiscountHandler - def initialize(event_store) - @repository = Infra::AggregateRootRepository.new(event_store) - end - - def call(cmd) - @repository.with_aggregate(Offer, cmd.aggregate_id) do |order| - order.change_discount(Discounts::PercentageDiscount.new(cmd.amount)) - end - end - end - - class SetPriceHandler - def initialize(event_store) - @repository = Infra::AggregateRootRepository.new(event_store) - end - - def call(cmd) - @repository.with_aggregate(PriceChange, cmd.product_id) do |product| - product.set_price(cmd.price) - end - end - end - - class SetFuturePriceHandler - def initialize(event_store) - @repository = Infra::AggregateRootRepository.new(event_store) - @event_store = event_store - end - - def call(cmd) - @event_store.with_metadata({ valid_at: cmd.valid_since }) do - @repository.with_aggregate(PriceChange, cmd.product_id) do |product| - product.set_price(cmd.price) - end - end - end - end - - class CreateTimePromotionHandler - def initialize(event_store) - @repository = Infra::AggregateRootRepository.new(event_store) - end - - def call(cmd) - @repository.with_aggregate(TimePromotion, cmd.time_promotion_id) do |time_promotion| - time_promotion.create(cmd.discount, cmd.start_time, cmd.end_time, cmd.label) - end - end - end - - class OnAddItemToBasket - def initialize(event_store) - @repository = Infra::AggregateRootRepository.new(event_store) - end - - def call(command) - @repository.with_aggregate(Offer, command.aggregate_id) do |order| - order.add_item(command.product_id) - end - end - end - - class OnRemoveItemFromBasket - def initialize(event_store) - @repository = Infra::AggregateRootRepository.new(event_store) - end - - def call(command) - @repository.with_aggregate(Offer, command.aggregate_id) do |order| - order.remove_item(command.product_id) - end - end - end - - class OnCalculateTotalValue - def initialize(event_store) - @repository = Infra::AggregateRootRepository.new(event_store) - @event_store = event_store - end - - def call(command) - @repository.with_aggregate(Offer, command.aggregate_id) do |order| - order.calculate_total_value(PricingCatalog.new(@event_store), time_promotions_discount) - end - rescue RubyEventStore::WrongExpectedEventVersion - retry - end - - - - def calculate_sub_amounts(command) - @repository.with_aggregate(Offer, command.aggregate_id) do |order| - order.calculate_sub_amounts(PricingCatalog.new(@event_store), time_promotions_discount) - end - rescue RubyEventStore::WrongExpectedEventVersion - retry - end - - private - - def time_promotions_discount - PromotionsCalendar.new(@event_store).current_time_promotions_discount - end - - end - - class OnCouponRegister - def initialize(event_store) - @repository = Infra::AggregateRootRepository.new(event_store) - end - - def call(command) - @repository.with_aggregate(Coupon, command.aggregate_id) do |coupon| - coupon.register(command.name, command.code, command.discount) - end - end - end - - class MakeProductFreeForOrderHandler - def initialize(event_store) - @repository = Infra::AggregateRootRepository.new(event_store) - end - - def call(command) - @repository.with_aggregate(Offer, command.aggregate_id) do |order| - order.make_product_free(command.order_id, command.product_id) - end - end - end - - class RemoveFreeProductFromOrderHandler - def initialize(event_store) - @repository = Infra::AggregateRootRepository.new(event_store) - end - - def call(command) - @repository.with_aggregate(Offer, command.aggregate_id) do |order| - order.remove_free_product(command.order_id, command.product_id) - end - end - end -end diff --git a/ecommerce/pricing/lib/pricing/time_promotion.rb b/ecommerce/pricing/lib/pricing/time_promotion.rb deleted file mode 100644 index 4f1ee9d19..000000000 --- a/ecommerce/pricing/lib/pricing/time_promotion.rb +++ /dev/null @@ -1,27 +0,0 @@ -module Pricing - class TimePromotion - include AggregateRoot - - def initialize(id) - @id = id - end - - def create(discount, start_time, end_time, label) - apply TimePromotionCreated.new( - data: { - time_promotion_id: @id, - discount: discount, - start_time: start_time, - end_time: end_time, - label: label - } - ) - end - - private - - on TimePromotionCreated do |_| - end - - end -end diff --git a/ecommerce/pricing/test/coupons_test.rb b/ecommerce/pricing/test/coupons_test.rb deleted file mode 100644 index b8c7a158e..000000000 --- a/ecommerce/pricing/test/coupons_test.rb +++ /dev/null @@ -1,40 +0,0 @@ -require_relative "test_helper" - -module Pricing - class CouponsTest < Test - cover "Pricing::Coupon*" - - def setup - @uid = SecureRandom.uuid - @code = fake_name.chars.shuffle.join - @discount = 10 - @data = { coupon_id: @uid, name: fake_name, code: @code, discount: @discount } - end - - def test_coupon_should_get_registered - register_coupon(@uid, fake_name, @code, rand(1..20)) - end - - def test_should_not_allow_for_id_based_duplicates - assert_raises(Pricing::Coupon::AlreadyRegistered) do - register_coupon(@uid, fake_name, @code, @discount) - register_coupon(@uid, fake_name, @code, @discount) - end - end - - def test_should_publish_event - coupon_registered = CouponRegistered.new(data: @data) - assert_events("Pricing::Coupon$#{@uid}", coupon_registered) do - register_coupon(@uid, fake_name, @code, @discount) - end - end - - def test_100_is_ok - register_coupon(@uid, fake_name, @code, 100) - end - - def test_0_01_is_ok - register_coupon(@uid, fake_name, @code, 0.01) - end - end -end diff --git a/ecommerce/pricing/test/discounts_test.rb b/ecommerce/pricing/test/discounts_test.rb deleted file mode 100644 index b7387cc70..000000000 --- a/ecommerce/pricing/test/discounts_test.rb +++ /dev/null @@ -1,68 +0,0 @@ -require_relative "test_helper" - -module Pricing - module Discounts - - class PercentageDiscountTest < Test - cover "Pricing::Discounts*" - - def test_is_more_than_zero - assert_raises UnacceptableDiscountRange do - PercentageDiscount.new(0) - end - end - - def test_is_not_lower_than_0 - assert_raises UnacceptableDiscountRange do - PercentageDiscount.new(-0.01) - end - end - - def test_is_not_more_than_100_percent - assert_raises UnacceptableDiscountRange do - PercentageDiscount.new(100.01) - end - end - - def test_100_is_ok - PercentageDiscount.new(100) - end - - def test_0_01_is_ok - PercentageDiscount.new(0.01) - end - - def test_applies_to_value - assert_equal(90, PercentageDiscount.new(10).apply(100)) - end - - def test_calculates_floats_too - assert_equal(90.45, PercentageDiscount.new(10).apply(100.50)) - end - - def test_can_add_another_discount - first_discount = PercentageDiscount.new(20) - second_discount = PercentageDiscount.new(15) - combined = first_discount.add(second_discount) - - assert_equal(65, combined.apply(100)) - end - - def test_cannot_add_to_more_than_100 - first_discount = PercentageDiscount.new(50) - second_discount = PercentageDiscount.new(65) - combined = first_discount.add(second_discount) - - assert_equal(0, combined.apply(100)) - end - end - - class NoPercentageDiscountTest < Test - cover "Pricing::Discounts*" - - def test_doesnt_change_total - assert_equal(100, NoPercentageDiscount.new.apply(100)) - end - end - end -end diff --git a/ecommerce/pricing/test/free_products_test.rb b/ecommerce/pricing/test/free_products_test.rb deleted file mode 100644 index 1982a96d1..000000000 --- a/ecommerce/pricing/test/free_products_test.rb +++ /dev/null @@ -1,217 +0,0 @@ -require_relative "test_helper" - -module Pricing - class FreeProductsTest < Test - cover "Pricing*" - - def test_making_product_free_possible_when_order_is_eligible - product_1_id = SecureRandom.uuid - set_price(product_1_id, 20) - order_id = SecureRandom.uuid - add_item(order_id, product_1_id) - add_item(order_id, product_1_id) - add_item(order_id, product_1_id) - add_item(order_id, product_1_id) - - assert_events_contain( - stream_name(order_id), - ProductMadeFreeForOrder.new( - data: { - order_id: order_id, - product_id: product_1_id - } - ), - OrderTotalValueCalculated.new( - data: { - order_id: order_id, - discounted_amount: 60, - total_amount: 60 - } - ) - ) do - run_command( - Pricing::MakeProductFreeForOrder.new(order_id: order_id, product_id: product_1_id) - ) - end - end - - def test_making_only_the_cheapest_product_free - product_1_id = SecureRandom.uuid - cheaper_product = SecureRandom.uuid - set_price(product_1_id, 20) - set_price(cheaper_product, 10) - order_id = SecureRandom.uuid - add_item(order_id, product_1_id) - add_item(order_id, product_1_id) - add_item(order_id, product_1_id) - add_item(order_id, cheaper_product) - - assert_events_contain( - stream_name(order_id), - ProductMadeFreeForOrder.new( - data: { - order_id: order_id, - product_id: cheaper_product - } - ), - OrderTotalValueCalculated.new( - data: { - order_id: order_id, - discounted_amount: 60, - total_amount: 60 - } - ), - ) do - run_command( - Pricing::MakeProductFreeForOrder.new(order_id: order_id, product_id: cheaper_product) - ) - end - end - - def test_making_product_free_not_possible_if_is_already_set - product_1_id = SecureRandom.uuid - set_price(product_1_id, 20) - order_id = SecureRandom.uuid - add_item(order_id, product_1_id) - add_item(order_id, product_1_id) - add_item(order_id, product_1_id) - add_item(order_id, product_1_id) - - run_command( - Pricing::MakeProductFreeForOrder.new(order_id: order_id, product_id: product_1_id) - ) - - assert_raises FreeProductAlreadyMade do - run_command( - Pricing::MakeProductFreeForOrder.new(order_id: order_id, product_id: product_1_id) - ) - end - end - - def test_making_product_free_possible_after_previous_free_product_was_removed - product_1_id = SecureRandom.uuid - set_price(product_1_id, 20) - order_id = SecureRandom.uuid - add_item(order_id, product_1_id) - add_item(order_id, product_1_id) - add_item(order_id, product_1_id) - add_item(order_id, product_1_id) - - run_command( - Pricing::MakeProductFreeForOrder.new(order_id: order_id, product_id: product_1_id) - ) - - run_command( - Pricing::RemovePriceItem.new(order_id: order_id, product_id: product_1_id) - ) - - run_command( - Pricing::RemoveFreeProductFromOrder.new(order_id: order_id, product_id: product_1_id) - ) - - run_command( - Pricing::AddPriceItem.new(order_id: order_id, product_id: product_1_id) - ) - - assert_events_contain( - stream_name(order_id), - ProductMadeFreeForOrder.new( - data: { - order_id: order_id, - product_id: product_1_id - } - ), - OrderTotalValueCalculated.new( - data: { - order_id: order_id, - discounted_amount: 60, - total_amount: 60 - } - ) - ) do - run_command( - Pricing::MakeProductFreeForOrder.new(order_id: order_id, product_id: product_1_id) - ) - end - end - - def test_removing_free_product_possible_if_it_is_already_set - product_1_id = SecureRandom.uuid - set_price(product_1_id, 20) - order_id = SecureRandom.uuid - add_item(order_id, product_1_id) - add_item(order_id, product_1_id) - add_item(order_id, product_1_id) - add_item(order_id, product_1_id) - - run_command( - Pricing::MakeProductFreeForOrder.new(order_id: order_id, product_id: product_1_id) - ) - - assert_events_contain( - stream_name(order_id), - FreeProductRemovedFromOrder.new( - data: { - order_id: order_id, - product_id: product_1_id - } - ), - OrderTotalValueCalculated.new( - data: { - order_id: order_id, - discounted_amount: 80, - total_amount: 80 - } - ) - ) do - run_command( - Pricing::RemoveFreeProductFromOrder.new(order_id: order_id, product_id: product_1_id) - ) - end - end - - def test_removing_free_product_not_possible_if_is_not_set - product_1_id = SecureRandom.uuid - set_price(product_1_id, 20) - order_id = SecureRandom.uuid - add_item(order_id, product_1_id) - - assert_raises FreeProductNotExists do - run_command( - Pricing::RemoveFreeProductFromOrder.new(order_id: order_id, product_id: product_1_id) - ) - end - end - - def test_removing_free_product_twice_not_possible - product_1_id = SecureRandom.uuid - set_price(product_1_id, 20) - order_id = SecureRandom.uuid - add_item(order_id, product_1_id) - add_item(order_id, product_1_id) - add_item(order_id, product_1_id) - add_item(order_id, product_1_id) - - run_command( - Pricing::MakeProductFreeForOrder.new(order_id: order_id, product_id: product_1_id) - ) - - run_command( - Pricing::RemoveFreeProductFromOrder.new(order_id: order_id, product_id: product_1_id) - ) - - assert_raises FreeProductNotExists do - run_command( - Pricing::RemoveFreeProductFromOrder.new(order_id: order_id, product_id: product_1_id) - ) - end - end - - private - - def stream_name(id) - "Pricing::Offer$#{id}" - end - - end -end diff --git a/ecommerce/pricing/test/future_prices_test.rb b/ecommerce/pricing/test/future_prices_test.rb deleted file mode 100644 index a1e271b17..000000000 --- a/ecommerce/pricing/test/future_prices_test.rb +++ /dev/null @@ -1,125 +0,0 @@ -require_relative "test_helper" - -module Pricing - class FuturePricesTest < Test - cover "Pricing*" - - def test_future_price_is_not_included_when_calculating_total_value - product_1_id = SecureRandom.uuid - set_price(product_1_id, 20) - future_date_timestamp = Time.current + days_number(5) - set_future_price(product_1_id, 30, future_date_timestamp) - 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) } - end - - def test_check_future_price - product_1_id = SecureRandom.uuid - set_price(product_1_id, 20) - future_date_timestamp = Time.current + days_number(5) - set_future_price(product_1_id, 30, future_date_timestamp) - - Timecop.travel(future_date_timestamp + 2137) do - 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: 30, - total_amount: 30 - } - ) - ) { calculate_total_value(order_id) } - end - end - - def test_future_prices_catalog_by_product_id - product_id = SecureRandom.uuid - set_price(product_id, 20) - future_date_timestamp_1 = with_precision(Time.current + days_number(2)) - future_date_timestamp_2 = with_precision(Time.current + days_number(3)) - future_date_timestamp_3 = with_precision(Time.current + days_number(4)) - - set_future_price(product_id, 30, future_date_timestamp_3) - set_future_price(product_id, 40, future_date_timestamp_1) - set_future_price(product_id, 50, future_date_timestamp_2) - - pricing_catalog = PricingCatalog.new(event_store) - - assert_equal 20, pricing_catalog.price_by_product_id(product_id) - - assert_equal [ - BigDecimal(20), - BigDecimal(40), - BigDecimal(50), - BigDecimal(30) - ], pricing_catalog.current_prices_catalog_by_product_id(product_id).map { |entry| entry[:price] } - - Timecop.travel(future_date_timestamp_1 + 1.second) do - assert_equal [ - BigDecimal(40), - BigDecimal(50), - BigDecimal(30) - ], pricing_catalog.current_prices_catalog_by_product_id(product_id).map { |entry| entry[:price] } - assert_equal [ - future_date_timestamp_1, - future_date_timestamp_2, - future_date_timestamp_3, - ], pricing_catalog.current_prices_catalog_by_product_id(product_id).map { |entry| entry[:valid_since] } - assert_equal BigDecimal(40), pricing_catalog.price_by_product_id(product_id) - end - - Timecop.travel(future_date_timestamp_2 + 1.second) do - assert_equal [ - BigDecimal(50), - BigDecimal(30) - ], pricing_catalog.current_prices_catalog_by_product_id(product_id).map { |entry| entry[:price] } - assert_equal [ - future_date_timestamp_2, - future_date_timestamp_3, - ], pricing_catalog.current_prices_catalog_by_product_id(product_id).map { |entry| entry[:valid_since] } - assert_equal BigDecimal(50), pricing_catalog.price_by_product_id(product_id) - end - - - pricing_catalog = PricingCatalog.new(event_store) - Timecop.travel(future_date_timestamp_3 + 1.second) do - assert_equal [BigDecimal(30)], pricing_catalog.current_prices_catalog_by_product_id(product_id).map { |entry| entry[:price] } - assert_equal [ - future_date_timestamp_3 - ], pricing_catalog.current_prices_catalog_by_product_id(product_id).map { |entry| entry[:valid_since] } - assert_equal BigDecimal(30), pricing_catalog.price_by_product_id(product_id) - end - end - - private - - def stream_name(order_id) - "Pricing::Offer$#{order_id}" - end - - def days_number(n) - 3600 * 24 * n - end - - def with_precision(time) - time.round(6) - end - end -end diff --git a/ecommerce/pricing/test/order_product_test.rb b/ecommerce/pricing/test/order_product_test.rb deleted file mode 100644 index 2d9f34d8d..000000000 --- a/ecommerce/pricing/test/order_product_test.rb +++ /dev/null @@ -1,47 +0,0 @@ -require_relative "test_helper" - -module Pricing - class Offer - class ProductTest < Test - cover "Pricing::Offer::Product" - - def setup - super - @id = SecureRandom.uuid - end - - def test_values_equality - refute(Product.new(@id).eql?(FreeProduct.new(@id))) - refute(Product.new(@id).eql?(Product.new(SecureRandom.uuid))) - refute(Product.new(@id).eql?(@id)) - end - - def test_hash_equality - assert(Product.new(@id).hash.eql?(Product.hash ^ @id.hash)) - refute(Product.new(@id).hash.eql?(Product.hash ^ SecureRandom.uuid.hash)) - refute(Product.new(@id).hash == @id.hash) - end - end - - class FreeProductTest < Test - cover "Pricing::Offer::FreeProduct" - - def setup - super - @id = SecureRandom.uuid - end - - def test_values_equality - refute(FreeProduct.new(@id).eql?(Product.new(@id))) - refute(FreeProduct.new(@id).eql?(FreeProduct.new(SecureRandom.uuid))) - refute(FreeProduct.new(@id).eql?(@id)) - end - - def test_hash_equality - assert(FreeProduct.new(@id).hash.eql?(FreeProduct.hash ^ @id.hash)) - refute(FreeProduct.new(@id).hash.eql?(FreeProduct.hash ^ SecureRandom.uuid.hash)) - refute(FreeProduct.new(@id).hash == @id.hash) - end - end - end -end diff --git a/ecommerce/pricing/test/pricing_test.rb b/ecommerce/pricing/test/pricing_test.rb deleted file mode 100644 index 14f2326e3..000000000 --- a/ecommerce/pricing/test/pricing_test.rb +++ /dev/null @@ -1,401 +0,0 @@ -require_relative "test_helper" - -module Pricing - class PricingTest < Test - cover "Pricing*" - - def test_configuration - Pricing.event_store = Infra::EventStore.in_memory - Pricing.event_store = Infra::CommandBus - - assert Pricing.event_store, Infra::EventStore.in_memory - assert Pricing.command_bus, Infra::CommandBus - end - - def test_calculates_total_value - 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 - add_item(order_id, product_1_id) - add_item(order_id, product_2_id) - stream = stream_name(order_id) - assert_events( - stream, - OrderTotalValueCalculated.new( - data: { - order_id: order_id, - discounted_amount: 50, - total_amount: 50 - } - ) - ) { calculate_total_value(order_id) } - end - - def test_calculates_sub_amounts - 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) } - - 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) - ) - assert_events( - stream, - PriceItemValueCalculated.new( - data: { - order_id: order_id, - product_id: product_1_id, - quantity: 1, - amount: 20, - discounted_amount: 18 - } - ), - PriceItemValueCalculated.new( - data: { - order_id: order_id, - product_id: product_2_id, - quantity: 2, - amount: 60, - discounted_amount: 54 - } - ) - ) { calculate_sub_amounts(order_id) } - end - - def test_calculates_total_value_with_discount - 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 - } - ) - ) { run_command(CalculateTotalValue.new(order_id: order_id)) } - assert_events_contain( - stream, - PercentageDiscountSet.new( - data: { - order_id: order_id, - amount: 10 - } - ), - OrderTotalValueCalculated.new( - data: { - order_id: order_id, - discounted_amount: 18, - total_amount: 20 - } - ) - ) do - run_command( - Pricing::SetPercentageDiscount.new(order_id: order_id, amount: 10) - ) - end - assert_events_contain( - stream, - PercentageDiscountChanged.new( - data: { - order_id: order_id, - amount: 50 - } - ), - OrderTotalValueCalculated.new( - data: { - order_id: order_id, - discounted_amount: 10, - total_amount: 20 - } - ) - ) do - run_command( - Pricing::ChangePercentageDiscount.new(order_id: order_id, amount: 50) - ) - end - assert_events_contain( - stream, - PercentageDiscountReset.new( - data: { - order_id: order_id, - } - ), - OrderTotalValueCalculated.new( - data: { - order_id: order_id, - discounted_amount: 20, - total_amount: 20 - } - ) - ) do - run_command( - Pricing::ResetPercentageDiscount.new(order_id: order_id) - ) - end - end - - def test_calculates_total_value_with_100_discount - 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_contain( - stream, - PercentageDiscountSet.new( - data: { - order_id: order_id, - amount: 100 - } - ), - OrderTotalValueCalculated.new( - data: { - order_id: order_id, - discounted_amount: 0, - total_amount: 20 - } - ) - ) do - run_command( - Pricing::SetPercentageDiscount.new(order_id: order_id, amount: 100) - ) - end - end - - def test_setting_discounts_twice_not_possible_because_we_want_explicit_discount_change_command - product_1_id = SecureRandom.uuid - set_price(product_1_id, 20) - order_id = SecureRandom.uuid - add_item(order_id, product_1_id) - run_command( - Pricing::SetPercentageDiscount.new(order_id: order_id, amount: 10) - ) - assert_raises NotPossibleToAssignDiscountTwice do - run_command( - Pricing::SetPercentageDiscount.new(order_id: order_id, amount: 20) - ) - end - end - - def test_setting_discount_not_possible_when_discount_has_been_set_and_then_changed - product_1_id = SecureRandom.uuid - set_price(product_1_id, 20) - order_id = SecureRandom.uuid - add_item(order_id, product_1_id) - run_command( - Pricing::SetPercentageDiscount.new(order_id: order_id, amount: 10) - ) - run_command( - Pricing::ChangePercentageDiscount.new(order_id: order_id, amount: 20) - ) - - assert_raises NotPossibleToAssignDiscountTwice do - run_command( - Pricing::SetPercentageDiscount.new(order_id: order_id, amount: 20) - ) - end - end - - def test_changing_discount_not_possible_when_discount_is_not_set - product_1_id = SecureRandom.uuid - set_price(product_1_id, 20) - order_id = SecureRandom.uuid - add_item(order_id, product_1_id) - - assert_raises NotPossibleToChangeDiscount do - run_command( - Pricing::ChangePercentageDiscount.new(order_id: order_id, amount: 20) - ) - end - end - - def test_changing_discount_not_possible_when_discount_is_reset - product_1_id = SecureRandom.uuid - set_price(product_1_id, 20) - order_id = SecureRandom.uuid - add_item(order_id, product_1_id) - run_command( - Pricing::SetPercentageDiscount.new(order_id: order_id, amount: 10) - ) - run_command( - Pricing::ResetPercentageDiscount.new(order_id: order_id) - ) - - assert_raises NotPossibleToChangeDiscount do - run_command( - Pricing::ChangePercentageDiscount.new(order_id: order_id, amount: 20) - ) - end - end - - def test_changing_discount_possible_when_discount_is_set - 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) - run_command( - Pricing::SetPercentageDiscount.new(order_id: order_id, amount: 10) - ) - - assert_events_contain( - stream, - PercentageDiscountChanged.new( - data: { - order_id: order_id, - amount: 100 - } - ), - OrderTotalValueCalculated.new( - data: { - order_id: order_id, - discounted_amount: 0, - total_amount: 20 - } - ) - ) do - run_command( - Pricing::ChangePercentageDiscount.new(order_id: order_id, amount: 100) - ) - end - end - - def test_changing_discount_possible_more_than_once - 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) - run_command( - Pricing::SetPercentageDiscount.new(order_id: order_id, amount: 10) - ) - run_command( - Pricing::ChangePercentageDiscount.new(order_id: order_id, amount: 20) - ) - - assert_events_contain( - stream, - PercentageDiscountChanged.new( - data: { - order_id: order_id, - amount: 100 - } - ), - OrderTotalValueCalculated.new( - data: { - order_id: order_id, - discounted_amount: 0, - total_amount: 20 - } - ) - ) do - run_command( - Pricing::ChangePercentageDiscount.new(order_id: order_id, amount: 100) - ) - end - end - - def test_resetting_discount_possible_when_discount_has_been_set_and_then_changed - 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) - run_command( - Pricing::SetPercentageDiscount.new(order_id: order_id, amount: 10) - ) - run_command( - Pricing::ChangePercentageDiscount.new(order_id: order_id, amount: 20) - ) - - assert_events_contain( - stream, - PercentageDiscountReset.new( - data: { - order_id: order_id - } - ), - OrderTotalValueCalculated.new( - data: { - order_id: order_id, - discounted_amount: 20, - total_amount: 20 - } - ) - ) do - run_command( - Pricing::ResetPercentageDiscount.new(order_id: order_id) - ) - end - end - - def test_resetting_with_missing_discount_not_possible - product_1_id = SecureRandom.uuid - set_price(product_1_id, 20) - order_id = SecureRandom.uuid - add_item(order_id, product_1_id) - assert_raises NotPossibleToResetWithoutDiscount do - run_command( - Pricing::ResetPercentageDiscount.new(order_id: order_id) - ) - end - run_command( - Pricing::SetPercentageDiscount.new(order_id: order_id, amount: 10) - ) - run_command( - Pricing::ResetPercentageDiscount.new(order_id: order_id) - ) - assert_raises NotPossibleToResetWithoutDiscount do - run_command( - Pricing::ResetPercentageDiscount.new(order_id: order_id) - ) - end - end - - private - - def stream_name(order_id) - "Pricing::Offer$#{order_id}" - end - - def calculate_sub_amounts(order_id) - run_command(CalculateSubAmounts.new(order_id: order_id)) - end - end -end diff --git a/ecommerce/pricing/test/product_test.rb b/ecommerce/pricing/test/product_test.rb deleted file mode 100644 index 3217d590b..000000000 --- a/ecommerce/pricing/test/product_test.rb +++ /dev/null @@ -1,33 +0,0 @@ -require_relative "test_helper" - -module Pricing - class ProductTest < Test - cover "Pricing::Product*" - - def test_product_price_is_set - product_id = SecureRandom.uuid - - set_price(product_id, 20) - end - - def test_set_future_price - product_id = SecureRandom.uuid - valid_since = 2.days.from_now - price = 20 - - future_price_set = [ - PriceSet.new(data: { product_id: product_id, price: price }), - ] - - assert_events("Pricing::PriceChange$#{product_id}", *future_price_set) do - set_future_price(product_id, price, valid_since) - end - end - - private - - def set_price(product_id, amount) - run_command(SetPrice.new(product_id: product_id, price: amount)) - end - end -end diff --git a/ecommerce/pricing/test/simple_offer_test.rb b/ecommerce/pricing/test/simple_offer_test.rb deleted file mode 100644 index a8dd80eb2..000000000 --- a/ecommerce/pricing/test/simple_offer_test.rb +++ /dev/null @@ -1,36 +0,0 @@ -require_relative "test_helper" - -module Pricing - class SimpleOfferTest < Test - cover "Pricing*" - - def test_removing - product_1_id = SecureRandom.uuid - set_price(product_1_id, 20) - order_id = SecureRandom.uuid - add_item(order_id, product_1_id) - stream = "Pricing::Offer$#{order_id}" - assert_events( - stream, - OrderTotalValueCalculated.new( - data: { - order_id: order_id, - discounted_amount: 20, - total_amount: 20 - } - ) - ) { calculate_total_value(order_id) } - remove_item(order_id, product_1_id) - assert_events( - stream, - OrderTotalValueCalculated.new( - data: { - order_id: order_id, - discounted_amount: 0, - total_amount: 0 - } - ) - ) { calculate_total_value(order_id) } - end - end -end diff --git a/ecommerce/pricing/test/subamounts_test.rb b/ecommerce/pricing/test/subamounts_test.rb deleted file mode 100644 index 8328e37df..000000000 --- a/ecommerce/pricing/test/subamounts_test.rb +++ /dev/null @@ -1,41 +0,0 @@ -require_relative "test_helper" - -module Pricing - class SubAmounts < Test - - def test_calculates_sub_amounts - set_price(product_id, 20) - - assert_events_contain(stream, price_item_value_calculated_event(20, 20)) do - add_item(order_id, product_id) - end - end - - private - - def price_item_value_calculated_event(amount, discounted_amount) - PriceItemValueCalculated.new( - data: { - order_id: order_id, - product_id: product_id, - quantity: 1, - discounted_amount: discounted_amount, - amount: amount - } - ) - end - - def stream - "Pricing::Offer$#{order_id}" - end - - def product_id - @product_id ||= SecureRandom.uuid - end - - def order_id - @order_id ||= SecureRandom.uuid - end - - end -end diff --git a/ecommerce/pricing/test/test_helper.rb b/ecommerce/pricing/test/test_helper.rb deleted file mode 100644 index eb9e385f5..000000000 --- a/ecommerce/pricing/test/test_helper.rb +++ /dev/null @@ -1,49 +0,0 @@ -require "minitest/autorun" -require "mutant/minitest/coverage" -require "active_support/all" - -require_relative "../lib/pricing" - -module Pricing - class Test < Infra::InMemoryTest - - def before_setup - super - Configuration.new.call(event_store, command_bus) - end - - private - - def set_price(product_id, amount) - run_command(SetPrice.new(product_id: product_id, price: amount)) - end - - def set_future_price(product_id, amount, valid_since) - run_command(SetFuturePrice.new(product_id: product_id, price: amount, valid_since: valid_since)) - end - - def calculate_total_value(order_id) - run_command(CalculateTotalValue.new(order_id: order_id)) - end - - def add_item(order_id, product_id) - run_command( - AddPriceItem.new(order_id: order_id, product_id: product_id) - ) - end - - def remove_item(order_id, product_id) - run_command( - RemovePriceItem.new(order_id: order_id, product_id: product_id) - ) - end - - def register_coupon(uid, name, code, discount) - run_command(RegisterCoupon.new(coupon_id: uid, name: name, code: code, discount: discount)) - end - - def fake_name - "Fake name" - end - end -end diff --git a/ecommerce/pricing/test/time_promotion_test.rb b/ecommerce/pricing/test/time_promotion_test.rb deleted file mode 100644 index e1de88470..000000000 --- a/ecommerce/pricing/test/time_promotion_test.rb +++ /dev/null @@ -1,222 +0,0 @@ -require_relative "test_helper" - -require "timecop" - -module Pricing - class TimePromotionTest < Test - cover "Pricing::TimePromotion*" - - def test_creates_time_promotion - uid = SecureRandom.uuid - start_time = Time.utc(2022, 7, 1, 12, 15, 0) - end_time = Time.utc(2022, 7, 4, 14, 30, 30) - discount = 25 - label = "Summer Sale" - data = { - time_promotion_id: uid, - discount: discount, - start_time: start_time, - end_time: end_time, - label: label - } - - run_command = -> { create_time_promotion(**data) } - - stream = "Pricing::TimePromotion$#{uid}" - event = TimePromotionCreated.new(data: data) - - assert_events(stream, event) do - run_command.call - end - end - - private - - def create_time_promotion(**kwargs) - run_command(CreateTimePromotion.new(kwargs)) - end - end - - 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, 49) - - time_promotion_id = SecureRandom.uuid - start_time = timestamp - end_time = timestamp + 1 - set_time_promotion_range(time_promotion_id, start_time, end_time, 1) - - # Not applicable promotions - time_promotion_id = SecureRandom.uuid - start_time = timestamp - 2 - end_time = timestamp - 1 - set_time_promotion_range(time_promotion_id, start_time, end_time, 10) - - time_promotion_id = SecureRandom.uuid - start_time = timestamp + 1 - end_time = timestamp + 2 - set_time_promotion_range(time_promotion_id, start_time, end_time, 15) - - time_promotion_id = SecureRandom.uuid - start_time = timestamp - 1 - end_time = timestamp - set_time_promotion_range(time_promotion_id, start_time, end_time, 15) - - assert_events( - stream, - OrderTotalValueCalculated.new( - data: { - order_id: order_id, - total_amount: 20, - discounted_amount: 10, - } - ) - ) { calculate_total_value(order_id) } - end - 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) - - assert_events(stream) { calculate_sub_amounts(order_id) } - - 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) - ) - - 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) - - 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 - end - - def test_takes_last_values_for_time_promotion - timestamp = Time.new(2022, 5, 30, 15, 33) - time_promotion_id = SecureRandom.uuid - start_time = timestamp - 5 - end_time = timestamp - 2 - set_time_promotion_range(time_promotion_id, start_time, end_time, 30) - - start_time = timestamp - 1 - end_time = timestamp + 1 - set_time_promotion_range(time_promotion_id, start_time, end_time, 50) - set_time_promotion_range(time_promotion_id, start_time, end_time, 40) - - 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: 12, - total_amount: 20 - } - ) - ) { calculate_total_value(order_id) } - end - end - - private - - def stream_name(order_id) - "Pricing::Offer$#{order_id}" - end - - def set_time_promotion_range(time_promotion_id, start_time, end_time, discount) - run_command( - CreateTimePromotion.new(time_promotion_id: time_promotion_id, start_time: start_time, end_time: end_time, discount: discount, label: "test") - ) - end - - def calculate_sub_amounts(order_id) - run_command(CalculateSubAmounts.new(order_id: order_id)) - end - end -end diff --git a/ecommerce/processes/.mutant.yml b/ecommerce/processes/.mutant.yml deleted file mode 100644 index e352e65d4..000000000 --- a/ecommerce/processes/.mutant.yml +++ /dev/null @@ -1,21 +0,0 @@ -requires: - - ./test/test_helper -integration: minitest -coverage_criteria: - process_abort: true -matcher: - subjects: - - Processes* - ignore: - - Processes::Configuration* - - Processes::OrderConfirmation#stream_name - - Processes::Test* - - Processes::ShipmentProcess* - - Processes::ReleasePaymentProcess* - - Processes::OrderItemInvoicingProcess* - - Processes::SyncShipmentFromOrdering* - - Processes::SyncInventoryFromOrdering* - - Processes::NotifyPaymentsAboutOrderValue* - - Processes::ThreePlusOneFree* - - Processes::ReservationProcess#build_state - - Processes::ReservationProcess::ProcessState#call \ No newline at end of file diff --git a/ecommerce/processes/Gemfile b/ecommerce/processes/Gemfile deleted file mode 100644 index 8fd887144..000000000 --- a/ecommerce/processes/Gemfile +++ /dev/null @@ -1,4 +0,0 @@ -source "https://rubygems.org" - -eval_gemfile "../../infra/Gemfile.test" -gem "infra", path: "../../infra" \ No newline at end of file diff --git a/ecommerce/processes/Gemfile.lock b/ecommerce/processes/Gemfile.lock deleted file mode 100644 index 4a73abff2..000000000 --- a/ecommerce/processes/Gemfile.lock +++ /dev/null @@ -1,119 +0,0 @@ -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.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.13.0) - ruby_event_store (= 2.13.0) - arkency-command_bus (0.4.1) - concurrent-ruby - ast (2.4.2) - base64 (0.2.0) - bigdecimal (3.1.4) - concurrent-ruby (1.2.2) - connection_pool (2.4.1) - diff-lcs (1.5.0) - drb (2.2.0) - ruby2_keywords - 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.1) - concurrent-ruby (~> 1.0) - dry-core (~> 1.0) - dry-inflector (~> 1.0) - dry-logic (~> 1.4) - zeitwerk (~> 2.6) - i18n (1.14.1) - 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.8) - rake (13.1.0) - redis-client (0.19.0) - connection_pool - regexp_parser (2.8.3) - ruby2_keywords (0.0.5) - ruby_event_store (2.13.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.0) - concurrent-ruby (< 2) - connection_pool (>= 2.3.0) - rack (>= 2.2.4) - redis-client (>= 0.14.0) - sorbet-runtime (0.5.11190) - tzinfo (2.0.6) - concurrent-ruby (~> 1.0) - unparser (0.6.12) - diff-lcs (~> 1.3) - parser (>= 3.2.2.4) - zeitwerk (2.6.12) - -PLATFORMS - arm64-darwin-20 - arm64-darwin-21 - ruby - x86_64-darwin-20 - x86_64-linux - -DEPENDENCIES - infra! - minitest (= 5.15.0)! - mutant-license! - mutant-minitest (= 0.11.26)! - -BUNDLED WITH - 2.5.9 diff --git a/ecommerce/processes/Makefile b/ecommerce/processes/Makefile deleted file mode 100644 index 23850fab1..000000000 --- a/ecommerce/processes/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -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/processes/lib/processes.rb b/ecommerce/processes/lib/processes.rb deleted file mode 100644 index 153c90df6..000000000 --- a/ecommerce/processes/lib/processes.rb +++ /dev/null @@ -1,153 +0,0 @@ -require_relative "../../ordering/lib/ordering" -require_relative "../../pricing/lib/pricing" -require_relative "../../product_catalog/lib/product_catalog" -require_relative "../../crm/lib/crm" -require_relative "../../payments/lib/payments" -require_relative "../../inventory/lib/inventory" -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' -require_relative 'processes/determine_vat_rates_on_order_placed' -require_relative 'processes/order_item_invoicing_process' -require_relative 'processes/notify_payments_about_order_value' -require_relative 'processes/sync_shipment_from_ordering' -require_relative 'processes/three_plus_one_free' -require_relative 'processes/reservation_process' - -module Processes - class Configuration - class << self - attr_accessor :event_store, :command_bus - end - - def call(event_store, command_bus) - self.class.event_store = event_store - self.class.command_bus = command_bus - notify_payments_about_order_total_value(event_store, command_bus) - enable_shipment_sync(event_store, command_bus) - determine_vat_rates_on_order_placed(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) - enable_order_item_invoicing_process(event_store, command_bus) - enable_reservation_process(event_store, command_bus) - build_pricing_offer_from_ordering_items(event_store, command_bus) - end - - private - - def enable_shipment_process(event_store, command_bus) - ShipmentProcess.new(event_store, command_bus) - end - - def build_pricing_offer_from_ordering_items(event_store, command_bus) - Infra::Process.new(event_store, command_bus) - .call(Ordering::ItemAddedToBasket, [:order_id, :product_id], - Pricing::AddPriceItem, [:order_id, :product_id]) - Infra::Process.new(event_store, command_bus) - .call(Ordering::ItemRemovedFromBasket, [:order_id, :product_id], - Pricing::RemovePriceItem, [:order_id, :product_id]) - end - - def enable_shipment_sync(event_store, command_bus) - SyncShipmentFromOrdering.new(event_store, command_bus) - end - - def notify_payments_about_order_total_value(event_store, command_bus) - NotifyPaymentsAboutOrderValue.new(event_store, command_bus) - end - - def confirm_order_on_payment_captured(event_store, command_bus) - event_store.subscribe( - ConfirmOrderOnPaymentCaptured.new(command_bus), - to: [Payments::PaymentCaptured] - ) - end - - def enable_release_payment_process(event_store, command_bus) - event_store.subscribe( - ReleasePaymentProcess.new(event_store, command_bus), - to: [ - Ordering::OrderPlaced, - Ordering::OrderExpired, - Fulfillment::OrderConfirmed, - Payments::PaymentAuthorized, - Payments::PaymentReleased - ] - ) - end - - def enable_order_item_invoicing_process(event_store, command_bus) - event_store.subscribe( - OrderItemInvoicingProcess.new(event_store, command_bus), - to: [ - Pricing::PriceItemValueCalculated, - Taxes::VatRateDetermined - ] - ) - end - - def determine_vat_rates_on_order_placed(event_store, command_bus) - event_store.subscribe( - DetermineVatRatesOnOrderPlaced.new(command_bus), - to: [Ordering::OrderPlaced] - ) - end - - def enable_product_name_sync(event_store, command_bus) - Infra::Process.new(event_store, command_bus) - .call(ProductCatalog::ProductNamed, [:product_id, :name], - Invoicing::SetProductNameDisplayedOnInvoice, [:product_id, :name_displayed]) - end - - def set_invoice_payment_date_when_order_confirmed(event_store, command_bus) - event_store.subscribe( - ->(event) do - command_bus.call( - Invoicing::SetPaymentDate.new( - invoice_id: event.data.fetch(:order_id), - payment_date: Time.zone.at(event.metadata.fetch(:timestamp)).to_date - ) - ) - end, - to: [Fulfillment::OrderConfirmed] - ) - end - - def enable_three_plus_one_free_process(event_store, command_bus) - ThreePlusOneFree.new(event_store, command_bus) - end - - def enable_reservation_process(event_store, command_bus) - event_store.subscribe( - ReservationProcess.new, - to: [ - Ordering::OrderSubmitted, - 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 deleted file mode 100644 index e1d671dac..000000000 --- a/ecommerce/processes/lib/processes/confirm_order_on_payment_captured.rb +++ /dev/null @@ -1,16 +0,0 @@ -module Processes - class ConfirmOrderOnPaymentCaptured - - def initialize(command_bus) - @command_bus = command_bus - end - - def call(event) - order_id = event.data.fetch(:order_id) - command_bus.call(Fulfillment::ConfirmOrder.new(order_id: order_id)) - end - - private - attr_reader :command_bus - end -end diff --git a/ecommerce/processes/lib/processes/determine_vat_rates_on_order_placed.rb b/ecommerce/processes/lib/processes/determine_vat_rates_on_order_placed.rb deleted file mode 100644 index 71b55983f..000000000 --- a/ecommerce/processes/lib/processes/determine_vat_rates_on_order_placed.rb +++ /dev/null @@ -1,20 +0,0 @@ -module Processes - class DetermineVatRatesOnOrderPlaced - def initialize(command_bus) - @command_bus = command_bus - end - - def call(event) - order_id = event.data.fetch(:order_id) - event.data.fetch(:order_lines).each do |product_quantity_hash| - product_id = product_quantity_hash.first - command = Taxes::DetermineVatRate.new(order_id: order_id, product_id: product_id) - command_bus.call(command) - end - end - - private - - attr_reader :command_bus - end -end \ No newline at end of file diff --git a/ecommerce/processes/lib/processes/notify_payments_about_order_value.rb b/ecommerce/processes/lib/processes/notify_payments_about_order_value.rb deleted file mode 100644 index 46fd6c246..000000000 --- a/ecommerce/processes/lib/processes/notify_payments_about_order_value.rb +++ /dev/null @@ -1,17 +0,0 @@ -module Processes - class NotifyPaymentsAboutOrderValue - def initialize(event_store, command_bus) - event_store.subscribe( - ->(event) do - command_bus.call( - Payments::SetPaymentAmount.new( - order_id: event.data.fetch(:order_id), - amount: event.data.fetch(:discounted_amount).to_f - ) - ) - end, - to: [Pricing::OrderTotalValueCalculated] - ) - end - end -end \ No newline at end of file diff --git a/ecommerce/processes/lib/processes/order_item_invoicing_process.rb b/ecommerce/processes/lib/processes/order_item_invoicing_process.rb deleted file mode 100644 index d03b1a0a1..000000000 --- a/ecommerce/processes/lib/processes/order_item_invoicing_process.rb +++ /dev/null @@ -1,87 +0,0 @@ -module Processes - class OrderItemInvoicingProcess - def initialize(event_store, command_bus) - @event_store = event_store - @command_bus = command_bus - end - - def call(event) - state = build_state(event) - return unless state.create_invoice_item? - - unit_prices = MoneySplitter.new(state.discounted_amount, Array.new(state.quantity, 1)).call - unit_prices.tally.each do |unit_price, quantity| - command_bus.call(Invoicing::AddInvoiceItem.new( - invoice_id: state.order_id, - product_id: state.product_id, - vat_rate: state.vat_rate, - quantity: quantity, - unit_price: unit_price - )) - end - end - - private - - attr_reader :event_store, :command_bus - - def build_state(event) - stream_name = "OrderInvoicingProcess$#{event.data.fetch(:order_id)}$#{event.data.fetch(:product_id)}" - past = event_store.read.stream(stream_name).to_a - last_stored = past.size - 1 - event_store.link(event.event_id, stream_name: stream_name, expected_version: last_stored) - ProcessState.new.tap do |state| - past.each { |ev| state.call(ev) } - state.call(event) - end - rescue RubyEventStore::WrongExpectedEventVersion - retry - end - - class ProcessState - attr_reader :order_id, :product_id, :quantity, :vat_rate, :discounted_amount - - def call(event) - @order_id ||= event.data.fetch(:order_id) - @product_id ||= event.data.fetch(:product_id) - case event - when Pricing::PriceItemValueCalculated - @quantity = event.data.fetch(:quantity) - @discounted_amount = event.data.fetch(:discounted_amount) - when Taxes::VatRateDetermined - @vat_rate = event.data.fetch(:vat_rate).symbolize_keys - end - end - - def create_invoice_item? - [order_id, product_id, quantity, vat_rate, discounted_amount].all? - end - end - end - - class MoneySplitter - def initialize(amount, weights) - raise ArgumentError unless weights.instance_of? Array - raise ArgumentError if weights.empty? - @amount = amount - @weights = weights - end - - def call - distributed_amounts = [] - total_weight = @weights.sum.to_d - @weights.each do |weight| - if total_weight.eql?(0) - distributed_amounts << 0 - next - end - p = weight / total_weight - distributed_amount = (p * @amount).round(2) - distributed_amounts << distributed_amount - total_weight -= weight - @amount -= distributed_amount - end - distributed_amounts - end - end -end \ No newline at end of file diff --git a/ecommerce/processes/lib/processes/registration_process.rb b/ecommerce/processes/lib/processes/registration_process.rb deleted file mode 100644 index e69b542b0..000000000 --- a/ecommerce/processes/lib/processes/registration_process.rb +++ /dev/null @@ -1,4 +0,0 @@ -# frozen_string_literal: true - -class RegistrationProcess -end diff --git a/ecommerce/processes/lib/processes/release_payment_process.rb b/ecommerce/processes/lib/processes/release_payment_process.rb deleted file mode 100644 index e85a338b5..000000000 --- a/ecommerce/processes/lib/processes/release_payment_process.rb +++ /dev/null @@ -1,63 +0,0 @@ -module Processes - class ReleasePaymentProcess - def initialize(event_store, command_bus) - @event_store = event_store - @command_bus = command_bus - end - - def call(event) - state = build_state(event) - release_payment(state) if state.release? - end - - private - - def release_payment(state) - command_bus.call(Payments::ReleasePayment.new(order_id: state.order_id)) - end - - attr_reader :command_bus, :event_store - - def build_state(event) - stream_name = "PaymentProcess$#{event.data.fetch(:order_id)}" - past_events = event_store.read.stream(stream_name).to_a - last_stored = past_events.size - 1 - event_store.link(event.event_id, stream_name: stream_name, expected_version: last_stored) - ProcessState.new.tap do |state| - past_events.each { |ev| state.call(ev) } - state.call(event) - end - rescue RubyEventStore::WrongExpectedEventVersion - retry - end - - class ProcessState - def initialize - @order = :draft - @payment = :none - end - - attr_reader :order_id - - def call(event) - case event - when Payments::PaymentAuthorized - @payment = :authorized - when Payments::PaymentReleased - @payment = :released - when Ordering::OrderPlaced - @order = :placed - @order_id = event.data.fetch(:order_id) - when Ordering::OrderExpired - @order = :expired - when Fulfillment::OrderConfirmed - @order = :confirmed - end - end - - def release? - @payment.eql?(:authorized) && @order.eql?(:expired) - end - end - end -end \ No newline at end of file diff --git a/ecommerce/processes/lib/processes/reservation_process.rb b/ecommerce/processes/lib/processes/reservation_process.rb deleted file mode 100644 index fa920cea2..000000000 --- a/ecommerce/processes/lib/processes/reservation_process.rb +++ /dev/null @@ -1,96 +0,0 @@ -module Processes - class ReservationProcess - def initialize - @event_store = Configuration.event_store - @command_bus = Configuration.command_bus - end - attr_accessor :event_store, :command_bus - - def call(event) - state = build_state(event) - case event.event_type - when 'Ordering::OrderSubmitted' - begin - reserve_stock(state) - rescue Inventory::InventoryEntry::InventoryNotAvailable - release_stock(state) - reject_order(state) - else - accept_order(state) - end - when 'Fulfillment::OrderCancelled' - release_stock(state) - when 'Fulfillment::OrderConfirmed' - dispatch_stock(state) - end - end - - private - - def reserve_stock(state) - state.order_lines.each do |product_id, quantity| - command_bus.(Inventory::Reserve.new(product_id: product_id, quantity: quantity)) - state.product_reserved(product_id) - end - end - - def release_stock(state) - state.order_lines.slice(*state.reserved_product_ids).each do |product_id, quantity| - command_bus.(Inventory::Release.new(product_id: product_id, quantity: quantity)) - end - end - - def dispatch_stock(state) - state.order_lines.each do |product_id, quantity| - command_bus.(Inventory::Dispatch.new(product_id: product_id, quantity: quantity)) - end - end - - def accept_order(state) - command_bus.(Ordering::AcceptOrder.new(order_id: state.order_id)) - end - - def reject_order(state) - command_bus.(Ordering::RejectOrder.new(order_id: state.order_id)) - end - - def build_state(event) - stream_name = "ReservationProcess$#{event.data.fetch(:order_id)}" - begin - past_events = event_store.read.stream(stream_name).to_a - last_stored = past_events.size - 1 - event_store.link(event.event_id, stream_name: stream_name, expected_version: last_stored) - rescue RubyEventStore::WrongExpectedEventVersion - retry - rescue RubyEventStore::EventDuplicatedInStream - return - end - ProcessState.new.tap do |state| - past_events.each { |ev| state.call(ev) } - state.call(event) - end - end - - class ProcessState - def initialize() - @reserved_product_ids = [] - end - - attr_reader :order_id, :order_lines, :reserved_product_ids - - def call(event) - case event - when Ordering::OrderSubmitted - @order_lines = event.data.fetch(:order_lines) - @order_id = event.data.fetch(:order_id) - when Fulfillment::OrderCancelled, Fulfillment::OrderConfirmed - @reserved_product_ids = order_lines.keys - end - end - - def product_reserved(product_id) - reserved_product_ids << product_id - end - end - end -end \ No newline at end of file diff --git a/ecommerce/processes/lib/processes/shipment_process.rb b/ecommerce/processes/lib/processes/shipment_process.rb deleted file mode 100644 index 0a04dae74..000000000 --- a/ecommerce/processes/lib/processes/shipment_process.rb +++ /dev/null @@ -1,81 +0,0 @@ -module Processes - class ShipmentProcess - def initialize(event_store, command_bus) - @event_store = event_store - @command_bus = command_bus - @event_store.subscribe( - self, - to: [ - Shipping::ShippingAddressAddedToShipment, - Shipping::ShipmentSubmitted, - Ordering::OrderPlaced, - Fulfillment::OrderConfirmed - ] - ) - end - - def call(event) - state = build_state(event) - submit_shipment(state) if state.submit? - authorize_shipment(state) if state.authorize? - end - - private - - def submit_shipment(state) - command_bus.call(Shipping::SubmitShipment.new(order_id: state.order_id)) - end - - def authorize_shipment(state) - command_bus.call(Shipping::AuthorizeShipment.new(order_id: state.order_id)) - end - - attr_reader :command_bus, :event_store - - def build_state(event) - stream_name = "ShipmentProcess$#{event.data.fetch(:order_id)}" - past_events = event_store.read.stream(stream_name).to_a - last_stored = past_events.size - 1 - event_store.link(event.event_id, stream_name: stream_name, expected_version: last_stored) - ProcessState.new.tap do |state| - past_events.each { |ev| state.call(ev) } - state.call(event) - end - rescue RubyEventStore::WrongExpectedEventVersion - retry - end - - class ProcessState - def initialize - @order = :draft - @shipment = :draft - end - - attr_reader :order_id - - def call(event) - case event - when Shipping::ShippingAddressAddedToShipment - @shipment = :address_set - when Shipping::ShipmentSubmitted - @shipment = :submitted - when Ordering::OrderPlaced - @order = :placed - @order_id = event.data.fetch(:order_id) - when Fulfillment::OrderConfirmed - @order = :confirmed - end - end - - def submit? - return false if @shipment == :submitted - - @shipment == :address_set && @order != :draft - end - - def authorize? - @shipment == :address_set && @order == :confirmed - end - end - end -end \ No newline at end of file diff --git a/ecommerce/processes/lib/processes/sync_shipment_from_ordering.rb b/ecommerce/processes/lib/processes/sync_shipment_from_ordering.rb deleted file mode 100644 index 4cceacd17..000000000 --- a/ecommerce/processes/lib/processes/sync_shipment_from_ordering.rb +++ /dev/null @@ -1,12 +0,0 @@ -module Processes - class SyncShipmentFromOrdering - def initialize(event_store, command_bus) - Infra::Process.new(event_store, command_bus) - .call(Ordering::ItemAddedToBasket, [:order_id, :product_id], - Shipping::AddItemToShipmentPickingList, [:order_id, :product_id]) - Infra::Process.new(event_store, command_bus) - .call(Ordering::ItemRemovedFromBasket, [:order_id, :product_id], - Shipping::RemoveItemFromShipmentPickingList, [:order_id, :product_id]) - end - end -end \ No newline at end of file diff --git a/ecommerce/processes/lib/processes/three_plus_one_free.rb b/ecommerce/processes/lib/processes/three_plus_one_free.rb deleted file mode 100644 index 5e85a0027..000000000 --- a/ecommerce/processes/lib/processes/three_plus_one_free.rb +++ /dev/null @@ -1,119 +0,0 @@ -module Processes - class ThreePlusOneFree - - def initialize(event_store, command_bus) - @event_store = event_store - @command_bus = command_bus - @event_store.subscribe( - self, - to: [ - Pricing::PriceItemAdded, - Pricing::PriceItemRemoved, - Pricing::ProductMadeFreeForOrder, - Pricing::FreeProductRemovedFromOrder - ] - ) - end - - def call(event) - state = build_state(event) - return if event_only_for_state_building?(event) - - make_or_remove_free_product(state) - end - - private - - def build_state(event) - stream_name = "ThreePlusOneFreeProcess$#{event.data.fetch(:order_id)}" - past_events = @event_store.read.stream(stream_name).to_a - last_stored = past_events.size - 1 - @event_store.link(event.event_id, stream_name: stream_name, expected_version: last_stored) - ProcessState.new(event.data.fetch(:order_id)).tap do |state| - past_events.each { |ev| state.call(ev) } - state.call(event) - end - rescue RubyEventStore::WrongExpectedEventVersion - retry - end - - def make_or_remove_free_product(state) - pricing_catalog = Pricing::PricingCatalog.new(@event_store) - free_product_id = FreeProductResolver.new(state, pricing_catalog).call - - return if current_free_product_not_changed?(free_product_id, state) - - remove_old_free_product(state) - make_new_product_for_free(state, free_product_id) - end - - def event_only_for_state_building?(event) - event.instance_of?(Pricing::FreeProductRemovedFromOrder) || event.instance_of?(Pricing::ProductMadeFreeForOrder) - end - - def current_free_product_not_changed?(free_product_id, state) - free_product_id == state.current_free_product_id - end - - def remove_old_free_product(state) - @command_bus.call(Pricing::RemoveFreeProductFromOrder.new(order_id: state.order_id, product_id: state.current_free_product_id)) if state.current_free_product_id - end - - def make_new_product_for_free(state, free_product_id) - @command_bus.call(Pricing::MakeProductFreeForOrder.new(order_id: state.order_id, product_id: free_product_id)) if free_product_id - end - - class ProcessState - attr_reader :order_id, :order_lines, :current_free_product_id - - def initialize(order_id) - @order_id = order_id - @order_lines = Hash.new(0) - end - - def call(event) - product_id = event.data.fetch(:product_id) - case event - when Pricing::PriceItemAdded - order_lines[product_id] += 1 - when Pricing::PriceItemRemoved - order_lines[product_id] -= 1 - order_lines.delete(product_id) if order_lines.fetch(product_id) <= 0 - when Pricing::ProductMadeFreeForOrder - @current_free_product_id = product_id - when Pricing::FreeProductRemovedFromOrder - @current_free_product_id = nil - end - end - - def total_quantity - order_lines.values.sum - end - end - - class FreeProductResolver - MIN_ORDER_LINES_QUANTITY = 4 - - def initialize(state, pricing_catalog) - @state = state - @pricing_catalog = pricing_catalog - end - - def call - cheapest_product if eligible_for_free_product? - end - - private - - attr_reader :state, :pricing_catalog - - def cheapest_product - state.order_lines.keys.sort_by { |product_id| pricing_catalog.price_by_product_id(product_id) }.first - end - - def eligible_for_free_product? - state.total_quantity >= MIN_ORDER_LINES_QUANTITY - end - end - end -end diff --git a/ecommerce/processes/test/determine_vat_rate_test.rb b/ecommerce/processes/test/determine_vat_rate_test.rb deleted file mode 100644 index edbd3e27e..000000000 --- a/ecommerce/processes/test/determine_vat_rate_test.rb +++ /dev/null @@ -1,30 +0,0 @@ -require_relative "test_helper" - -module Processes - class DetermineVatRateTest < Test - cover "Processes::DetermineVatRatesOnOrderPlaced*" - - def test_inventory_available_error_is_raised - product_id = SecureRandom.uuid - order_id = SecureRandom.uuid - process = DetermineVatRatesOnOrderPlaced.new(command_bus) - given([order_placed(order_id, product_id)]).each do |event| - process.call(event) - end - assert_command(Taxes::DetermineVatRate.new(order_id: order_id, product_id: product_id)) - end - - private - - def order_placed order_id, product_id - Ordering::OrderPlaced.new( - data: { - order_id: order_id, - order_number: order_number, - customer_id: customer_id, - order_lines: { product_id => 1 } - } - ) - end - end -end diff --git a/ecommerce/processes/test/money_splitter_test.rb b/ecommerce/processes/test/money_splitter_test.rb deleted file mode 100644 index 379ba9874..000000000 --- a/ecommerce/processes/test/money_splitter_test.rb +++ /dev/null @@ -1,18 +0,0 @@ -require_relative "test_helper" - -module Processes - class MoneySplitterTest < Minitest::Test - cover "Processes::MoneySplitter" - - def test_splitting_money_without_losing_cents - assert_equal([0.01, 0.01, 0.01], MoneySplitter.new(0.03, [1, 1, 1]).call) - assert_equal([0.01, 0.02], MoneySplitter.new(0.03, [1, 1]).call.sort) - assert_equal([0, 0, 0.01, 0.01, 0.01], MoneySplitter.new(0.03, [1, 1, 1, 1, 1]).call.sort) - assert_equal([0, 0, 0.03], MoneySplitter.new(0.03, [1, 0, 0]).call.sort) - - assert_raises(ArgumentError) { MoneySplitter.new(0.03, nil).call } - assert_raises(ArgumentError) { MoneySplitter.new(0.03, 'not nil nor array').call } - assert_raises(ArgumentError) { MoneySplitter.new(0.03, []).call } - end - end -end \ No newline at end of file diff --git a/ecommerce/processes/test/order_confirmation_test.rb b/ecommerce/processes/test/order_confirmation_test.rb deleted file mode 100644 index 3278e67f7..000000000 --- a/ecommerce/processes/test/order_confirmation_test.rb +++ /dev/null @@ -1,15 +0,0 @@ -require_relative "test_helper" - -module Processes - class OrderConfirmationTest < Test - cover "Processes::OrderConfirmation" - - def test_payment_confirms_order - process = ConfirmOrderOnPaymentCaptured.new(command_bus) - given([payment_authorized]).each do |event| - process.call(event) - end - assert_command(Fulfillment::ConfirmOrder.new(order_id: order_id)) - end - end -end diff --git a/ecommerce/processes/test/order_item_invoicing_process_test.rb b/ecommerce/processes/test/order_item_invoicing_process_test.rb deleted file mode 100644 index 97526be44..000000000 --- a/ecommerce/processes/test/order_item_invoicing_process_test.rb +++ /dev/null @@ -1,43 +0,0 @@ -require_relative "test_helper" - -module Processes - class OrderItemInvoicingProcessTest < Test - cover "Processes::OrderItemInvoicingProcess*" - - def test_invoice_item_being_created - product_id = SecureRandom.uuid - amount = 100.to_d - discounted_amount = 90.to_d - quantity = 5 - vat_rate = Infra::Types::VatRate.new(rate: 20, code: "20") - - item_value_calculated = Pricing::PriceItemValueCalculated.new( - data: { - order_id: order_id, - product_id: product_id, - quantity: quantity, - amount: amount, - discounted_amount: discounted_amount - } - ) - vat_rate_determined = Taxes::VatRateDetermined.new( - data: { - order_id: order_id, - product_id: product_id, - vat_rate: vat_rate - } - ) - process = OrderItemInvoicingProcess.new(event_store, command_bus) - given([item_value_calculated, vat_rate_determined]).each do |event| - process.call(event) - end - assert_command(Invoicing::AddInvoiceItem.new( - invoice_id: order_id, - product_id: product_id, - quantity: quantity, - vat_rate: vat_rate, - unit_price: 18.to_d - )) - end - end -end \ No newline at end of file diff --git a/ecommerce/processes/test/release_payment_process_test.rb b/ecommerce/processes/test/release_payment_process_test.rb deleted file mode 100644 index 29f0a551d..000000000 --- a/ecommerce/processes/test/release_payment_process_test.rb +++ /dev/null @@ -1,37 +0,0 @@ -require_relative "test_helper" - -module Processes - class ReleasePaymentProcessTest < Test - cover "Processes::ReleasePaymentProcess*" - - def test_happy_path - process = ReleasePaymentProcess.new(event_store, command_bus) - given([order_placed, payment_authorized, order_confirmed]).each do |event| - process.call(event) - end - assert_no_command - end - - def test_order_expired_without_payment - process = ReleasePaymentProcess.new(event_store, command_bus) - given([order_placed, order_expired]).each { |event| process.call(event) } - assert_no_command - end - - def test_order_expired_after_payment_authorization - process = ReleasePaymentProcess.new(event_store, command_bus) - given([order_placed, payment_authorized, order_expired]).each do |event| - process.call(event) - end - assert_command(Payments::ReleasePayment.new(order_id: order_id),) - end - - def test_order_expired_after_payment_released - process = ReleasePaymentProcess.new(event_store, command_bus) - given([order_placed, payment_authorized, payment_released, order_expired]).each do |event| - process.call(event) - end - assert_no_command - end - end -end \ No newline at end of file diff --git a/ecommerce/processes/test/reservation_process_test.rb b/ecommerce/processes/test/reservation_process_test.rb deleted file mode 100644 index a71aa122c..000000000 --- a/ecommerce/processes/test/reservation_process_test.rb +++ /dev/null @@ -1,108 +0,0 @@ -require_relative "test_helper" - -module Processes - class ReservationProcessTest < Test - cover "Processes::ReservationProcess*" - - def test_happy_path - process = ReservationProcess.new - given([order_submitted]).each { |event| process.call(event) } - assert_all_commands( - Inventory::Reserve.new(product_id: product_id, quantity: 1), - Inventory::Reserve.new(product_id: another_product_id, quantity: 2), - Ordering::AcceptOrder.new(order_id: order_id) - ) - end - - class EnhancedFakeCommandBus < SimpleDelegator - def initialize(command_bus, command_error_hash = {}) - super(command_bus) - @command_error_hash = command_error_hash - end - - def call(command) - super(command) - raise @command_error_hash[command] if @command_error_hash[command] - end - end - - def test_reject_order_command_is_dispatched_when_sth_is_unavailable - failing_command = Inventory::Reserve.new(product_id: product_id, quantity: 1) - enhanced_command_bus = EnhancedFakeCommandBus.new(command_bus, failing_command => Inventory::InventoryEntry::InventoryNotAvailable) - process = ReservationProcess.new - process.command_bus = enhanced_command_bus - given([order_submitted]).each { |event| process.call(event) } - assert_all_commands( - failing_command, - Ordering::RejectOrder.new(order_id: order_id) - ) - end - - def test_compensation_when_sth_is_unavailable - failing_command = Inventory::Reserve.new(product_id: another_product_id, quantity: 2) - enhanced_command_bus = EnhancedFakeCommandBus.new(command_bus, failing_command => Inventory::InventoryEntry::InventoryNotAvailable) - process = ReservationProcess.new - process.command_bus = enhanced_command_bus - given([order_submitted]).each { |event| process.call(event) } - assert_all_commands( - Inventory::Reserve.new(product_id: product_id, quantity: 1), - failing_command, - Inventory::Release.new(product_id: product_id, quantity: 1), - Ordering::RejectOrder.new(order_id: order_id) - ) - end - - def test_release_stock_when_order_is_cancelled - process = ReservationProcess.new - given([order_submitted]).each { |event| process.call(event) } - - command_bus.clear_all_received - given([order_cancelled]).each { |event| process.call(event) } - assert_all_commands( - Inventory::Release.new(product_id: product_id, quantity: 1), - Inventory::Release.new(product_id: another_product_id, quantity: 2) - ) - end - - def test_dispatch_stock_when_order_is_confirmed - process = ReservationProcess.new - given([order_submitted]).each { |event| process.call(event) } - - command_bus.clear_all_received - given([order_confirmed]).each { |event| process.call(event) } - assert_all_commands( - Inventory::Dispatch.new(product_id: product_id, quantity: 1), - Inventory::Dispatch.new(product_id: another_product_id, quantity: 2) - ) - end - - private - - def product_id - @product_id ||= SecureRandom.uuid - end - - def another_product_id - @another_product_id ||= SecureRandom.uuid - end - - def order_submitted - Ordering::OrderSubmitted.new( - data: { - order_id: order_id, - order_number: order_number, - customer_id: customer_id, - order_lines: { product_id => 1, another_product_id => 2 } - } - ) - end - - def order_cancelled - Fulfillment::OrderCancelled.new( - data: { - order_id: order_id - } - ) - end - end -end \ No newline at end of file diff --git a/ecommerce/processes/test/test_helper.rb b/ecommerce/processes/test/test_helper.rb deleted file mode 100644 index 2c446bc06..000000000 --- a/ecommerce/processes/test/test_helper.rb +++ /dev/null @@ -1,100 +0,0 @@ -require "minitest/autorun" -require "mutant/minitest/coverage" -require "infra" -require_relative "../lib/processes" - -module Processes - class Test < Minitest::Test - include Infra::TestPlumbing.with( - event_store: -> { Infra::EventStore.in_memory }, - command_bus: -> { FakeCommandBus.new } - ) - - def before_setup - super - Configuration.new.call(event_store, command_bus) - end - - def assert_command(command) - assert_equal(command, @command_bus.received) - end - - def assert_all_commands(*commands) - assert_equal(commands, @command_bus.all_received) - end - - def assert_no_command - assert_nil(@command_bus.received) - end - - private - - class FakeCommandBus - attr_reader :received, :all_received - - def initialize - @all_received = [] - end - - def call(command) - @received = command - @all_received << command - end - - def clear_all_received - @all_received, @received = [], nil - end - end - - def order_id - @order_id ||= SecureRandom.uuid - end - - def order_number - "2018/12/16" - end - - def customer_id - @customer_id ||= SecureRandom.uuid - end - - def given(events, store: event_store) - events.each { |ev| store.append(ev) } - events - end - - def order_placed - Ordering::OrderPlaced.new( - data: { - order_id: order_id, - order_number: order_number, - customer_id: customer_id - } - ) - end - - def order_expired - Ordering::OrderExpired.new(data: { order_id: order_id }) - end - - def order_confirmed - Fulfillment::OrderConfirmed.new(data: { order_id: order_id }) - end - - def order_cancelled - Fulfillment::OrderCancelled.new(data: { order_id: order_id }) - end - - def payment_authorized - Payments::PaymentAuthorized.new(data: { order_id: order_id }) - end - - def payment_captured - Payments::PaymentCaptured.new(data: { order_id: order_id }) - end - - def payment_released - Payments::PaymentReleased.new(data: { order_id: order_id }) - end - end -end diff --git a/ecommerce/processes/test/three_plus_one_free_test.rb b/ecommerce/processes/test/three_plus_one_free_test.rb deleted file mode 100644 index d14141806..000000000 --- a/ecommerce/processes/test/three_plus_one_free_test.rb +++ /dev/null @@ -1,160 +0,0 @@ -require_relative "test_helper" - -module Processes - class ThreePlusOneFreeTest < Test - cover "Processes::ThreePlusOneFree*" - - def test_one_order_line_is_not_eligible_for_free_product - product_id = SecureRandom.uuid - order_id = SecureRandom.uuid - process = ThreePlusOneFree.new(event_store, command_bus) - given(item_added_event(order_id, product_id, 1)).each do |event| - process.call(event) - end - assert_no_command - end - - def test_four_order_lines_are_eligible_for_free_product - product_id = SecureRandom.uuid - order_id = SecureRandom.uuid - process = ThreePlusOneFree.new(event_store, command_bus) - given([set_price(product_id, 20)]) - given(item_added_event(order_id, product_id, 4)).each do |event| - process.call(event) - end - assert_command(Pricing::MakeProductFreeForOrder.new(order_id: order_id, product_id: product_id)) - end - - def test_remove_free_product_when_order_lines_qtn_is_less_than_four - product_id = SecureRandom.uuid - order_id = SecureRandom.uuid - process = ThreePlusOneFree.new(event_store, command_bus) - given([set_price(product_id, 20)]) - given(item_added_event(order_id, product_id, 4) + - product_made_for_free(order_id, product_id) + - item_removed_event(order_id, product_id, 1) + - free_product_removed(order_id, product_id)).each do |event| - process.call(event) - end - - assert_all_commands(Pricing::MakeProductFreeForOrder.new(order_id: order_id, product_id: product_id), - Pricing::RemoveFreeProductFromOrder.new(order_id: order_id, product_id: product_id)) - end - - def test_change_free_product_if_new_order_line_is_the_cheapest - product_id = SecureRandom.uuid - cheapest_product_id = SecureRandom.uuid - order_id = SecureRandom.uuid - process = ThreePlusOneFree.new(event_store, command_bus) - given([set_price(product_id, 20)]) - given([set_price(cheapest_product_id, 1)]) - - given(item_added_event(order_id, product_id, 4) + - product_made_for_free(order_id, product_id) + - item_added_event(order_id, cheapest_product_id, 1) + - free_product_removed(order_id, product_id) + - product_made_for_free(order_id, cheapest_product_id) - ).each do |event| - process.call(event) - end - - assert_all_commands(Pricing::MakeProductFreeForOrder.new(order_id: order_id, product_id: product_id), - Pricing::RemoveFreeProductFromOrder.new(order_id: order_id, product_id: product_id), - Pricing::MakeProductFreeForOrder.new(order_id: order_id, product_id: cheapest_product_id)) - end - - def test_do_not_change_free_product_if_new_order_line_is_more_expensive - product_id = SecureRandom.uuid - more_expensive_product_id = SecureRandom.uuid - order_id = SecureRandom.uuid - process = ThreePlusOneFree.new(event_store, command_bus) - given([set_price(product_id, 20)]) - given([set_price(more_expensive_product_id, 50)]) - - given(item_added_event(order_id, product_id, 4) + - product_made_for_free(order_id, product_id) + - item_added_event(order_id, more_expensive_product_id, 1)).each do |event| - process.call(event) - end - - assert_all_commands(Pricing::MakeProductFreeForOrder.new(order_id: order_id, product_id: product_id)) - end - - def test_change_free_product_if_the_cheapest_order_line_is_removed - product_id = SecureRandom.uuid - cheapest_product_id = SecureRandom.uuid - order_id = SecureRandom.uuid - process = ThreePlusOneFree.new(event_store, command_bus) - given([set_price(product_id, 20)]) - given([set_price(cheapest_product_id, 1)]) - - given(item_added_event(order_id, product_id, 4) + - product_made_for_free(order_id, product_id) + - item_added_event(order_id, cheapest_product_id, 1) + - free_product_removed(order_id, product_id) + - product_made_for_free(order_id, cheapest_product_id) + - item_removed_event(order_id, cheapest_product_id, 1) + - free_product_removed(order_id, cheapest_product_id) + - product_made_for_free(order_id, product_id)).each do |event| - process.call(event) - end - - assert_all_commands(Pricing::MakeProductFreeForOrder.new(order_id: order_id, product_id: product_id), - Pricing::RemoveFreeProductFromOrder.new(order_id: order_id, product_id: product_id), - Pricing::MakeProductFreeForOrder.new(order_id: order_id, product_id: cheapest_product_id), - Pricing::RemoveFreeProductFromOrder.new(order_id: order_id, product_id: cheapest_product_id), - Pricing::MakeProductFreeForOrder.new(order_id: order_id, product_id: product_id) - ) - end - - private - - def set_price(product_id, amount) - Pricing::PriceSet.new(data: { product_id: product_id, price: amount }) - end - - def item_added_event(order_id, product_id, times) - times.times.collect do - Pricing::PriceItemAdded.new( - data: { - order_id: order_id, - product_id: product_id - } - ) - end - end - - def item_removed_event(order_id, product_id, times) - times.times.collect do - Pricing::PriceItemRemoved.new( - data: { - order_id: order_id, - product_id: product_id - } - ) - end - end - - def product_made_for_free(order_id, product_id) - [ - Pricing::ProductMadeFreeForOrder.new( - data: { - order_id: order_id, - product_id: product_id - } - ) - ] - end - - def free_product_removed(order_id, product_id) - [ - Pricing::FreeProductRemovedFromOrder.new( - data: { - order_id: order_id, - product_id: product_id - } - ) - ] - end - end -end diff --git a/ecommerce/product_catalog/.mutant.yml b/ecommerce/product_catalog/.mutant.yml deleted file mode 100644 index e01cd617f..000000000 --- a/ecommerce/product_catalog/.mutant.yml +++ /dev/null @@ -1,8 +0,0 @@ -requires: - - ./test/test_helper -integration: minitest -coverage_criteria: - process_abort: true -matcher: - subjects: - - ProductCatalog* diff --git a/ecommerce/product_catalog/Gemfile b/ecommerce/product_catalog/Gemfile deleted file mode 100644 index 00fef6d3c..000000000 --- a/ecommerce/product_catalog/Gemfile +++ /dev/null @@ -1,4 +0,0 @@ -source "https://rubygems.org" - -eval_gemfile "../../infra/Gemfile.test" -gem "infra", path: "../../infra" diff --git a/ecommerce/product_catalog/Gemfile.lock b/ecommerce/product_catalog/Gemfile.lock deleted file mode 100644 index 4a73abff2..000000000 --- a/ecommerce/product_catalog/Gemfile.lock +++ /dev/null @@ -1,119 +0,0 @@ -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.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.13.0) - ruby_event_store (= 2.13.0) - arkency-command_bus (0.4.1) - concurrent-ruby - ast (2.4.2) - base64 (0.2.0) - bigdecimal (3.1.4) - concurrent-ruby (1.2.2) - connection_pool (2.4.1) - diff-lcs (1.5.0) - drb (2.2.0) - ruby2_keywords - 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.1) - concurrent-ruby (~> 1.0) - dry-core (~> 1.0) - dry-inflector (~> 1.0) - dry-logic (~> 1.4) - zeitwerk (~> 2.6) - i18n (1.14.1) - 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.8) - rake (13.1.0) - redis-client (0.19.0) - connection_pool - regexp_parser (2.8.3) - ruby2_keywords (0.0.5) - ruby_event_store (2.13.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.0) - concurrent-ruby (< 2) - connection_pool (>= 2.3.0) - rack (>= 2.2.4) - redis-client (>= 0.14.0) - sorbet-runtime (0.5.11190) - tzinfo (2.0.6) - concurrent-ruby (~> 1.0) - unparser (0.6.12) - diff-lcs (~> 1.3) - parser (>= 3.2.2.4) - zeitwerk (2.6.12) - -PLATFORMS - arm64-darwin-20 - arm64-darwin-21 - ruby - x86_64-darwin-20 - x86_64-linux - -DEPENDENCIES - infra! - minitest (= 5.15.0)! - mutant-license! - mutant-minitest (= 0.11.26)! - -BUNDLED WITH - 2.5.9 diff --git a/ecommerce/product_catalog/Makefile b/ecommerce/product_catalog/Makefile deleted file mode 100644 index 23850fab1..000000000 --- a/ecommerce/product_catalog/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -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/product_catalog/README.md b/ecommerce/product_catalog/README.md deleted file mode 100644 index ffef06baa..000000000 --- a/ecommerce/product_catalog/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# Product Catalog - -[![Build Status](https://github.com/RailsEventStore/cqrs-es-sample-with-res/workflows/product_catalog/badge.svg)](https://github.com/RailsEventStore/cqrs-es-sample-with-res/actions/workflows/product_catalog.yml) - -We implement this domain as a CRUD-based bounded context. The goal is to present -how to deal with such CRUD-ish domains and to show how to integrate it with -parts of the system. - -It's just a single ActiveRecord `Product` class. - -We wrap it with a `ProductCatalog` namespace to explicitly set its boundaries. - -This Bounded Context has both - the write part and the read part as the -same model. You can say it's not really CQRS - which is true for many CRUDish -bounded contexts. - -#### Up and running - -``` -make install test mutate -``` diff --git a/ecommerce/product_catalog/lib/product_catalog.rb b/ecommerce/product_catalog/lib/product_catalog.rb deleted file mode 100644 index dd2048eab..000000000 --- a/ecommerce/product_catalog/lib/product_catalog.rb +++ /dev/null @@ -1,15 +0,0 @@ -require "infra" -require_relative "product_catalog/commands" -require_relative "product_catalog/events" -require_relative "product_catalog/registration" -require_relative "product_catalog/naming" - -module ProductCatalog - - class Configuration - def call(event_store, command_bus) - command_bus.register(RegisterProduct, Registration.new(event_store)) - command_bus.register(NameProduct, Naming.new(event_store)) - end - end -end diff --git a/ecommerce/product_catalog/lib/product_catalog/commands.rb b/ecommerce/product_catalog/lib/product_catalog/commands.rb deleted file mode 100644 index 98b2ee7fe..000000000 --- a/ecommerce/product_catalog/lib/product_catalog/commands.rb +++ /dev/null @@ -1,10 +0,0 @@ -module ProductCatalog - class RegisterProduct < Infra::Command - attribute :product_id, Infra::Types::UUID - end - - class NameProduct < Infra::Command - attribute :product_id, Infra::Types::UUID - attribute :name, Infra::Types::String - end -end diff --git a/ecommerce/product_catalog/lib/product_catalog/events.rb b/ecommerce/product_catalog/lib/product_catalog/events.rb deleted file mode 100644 index 413a7b085..000000000 --- a/ecommerce/product_catalog/lib/product_catalog/events.rb +++ /dev/null @@ -1,11 +0,0 @@ -module ProductCatalog - - class ProductRegistered < Infra::Event - attribute :product_id, Infra::Types::UUID - end - - class ProductNamed < Infra::Event - attribute :product_id, Infra::Types::String - end - -end diff --git a/ecommerce/product_catalog/lib/product_catalog/naming.rb b/ecommerce/product_catalog/lib/product_catalog/naming.rb deleted file mode 100644 index dec9d67cf..000000000 --- a/ecommerce/product_catalog/lib/product_catalog/naming.rb +++ /dev/null @@ -1,27 +0,0 @@ -module ProductCatalog - - class Naming - def initialize(event_store) - @event_store = event_store - end - - def call(cmd) - @event_store.publish(product_named_event(cmd), stream_name: stream_name(cmd)) - end - - private - - def product_named_event(cmd) - ProductNamed.new( - data: { - product_id: cmd.product_id, - name: cmd.name - } - ) - end - - def stream_name(cmd) - "Catalog::ProductName$#{cmd.product_id}" - end - end -end diff --git a/ecommerce/product_catalog/lib/product_catalog/registration.rb b/ecommerce/product_catalog/lib/product_catalog/registration.rb deleted file mode 100644 index 244676896..000000000 --- a/ecommerce/product_catalog/lib/product_catalog/registration.rb +++ /dev/null @@ -1,34 +0,0 @@ -module ProductCatalog - AlreadyRegistered = Class.new(StandardError) - - class Registration - def initialize(event_store) - @event_store = event_store - end - - def call(cmd) - events = all_events_from_stream(stream_name(cmd)) - raise AlreadyRegistered unless events.empty? - - @event_store.publish(product_registered_event(cmd), stream_name: stream_name(cmd)) - end - - private - - def all_events_from_stream(name) - @event_store.read.stream(name).to_a - end - - def product_registered_event(cmd) - ProductRegistered.new( - data: { - product_id: cmd.product_id, - } - ) - end - - def stream_name(cmd) - "Catalog::Product$#{cmd.product_id}" - end - end -end diff --git a/ecommerce/product_catalog/test/naming_test.rb b/ecommerce/product_catalog/test/naming_test.rb deleted file mode 100644 index e5851df06..000000000 --- a/ecommerce/product_catalog/test/naming_test.rb +++ /dev/null @@ -1,24 +0,0 @@ -require_relative 'test_helper' -module ProductCatalog - class NamingTest < Test - cover "ProductCatalog*" - - def test_should_publish_event - uid = SecureRandom.uuid - product_named = ProductCatalog::ProductNamed.new(data: {product_id: uid, name: fake_name}) - assert_events("Catalog::ProductName$#{uid}", product_named) do - name_product(uid, fake_name) - end - end - - private - - def name_product(uid, name) - run_command(NameProduct.new(product_id: uid, name: name)) - end - - def fake_name - "Fake name" - end - end -end diff --git a/ecommerce/product_catalog/test/registration_test.rb b/ecommerce/product_catalog/test/registration_test.rb deleted file mode 100644 index c4140ee61..000000000 --- a/ecommerce/product_catalog/test/registration_test.rb +++ /dev/null @@ -1,52 +0,0 @@ -require_relative 'test_helper' -module ProductCatalog - class RegistrationTest < Test - cover "ProductCatalog*" - - def test_product_should_get_registered - uid = SecureRandom.uuid - assert register_product(uid) - end - - def test_should_not_allow_for_double_registration - uid = SecureRandom.uuid - assert_raises(AlreadyRegistered) do - register_product(uid) - register_product(uid) - end - end - - def test_should_publish_event - uid = SecureRandom.uuid - product_registered = ProductCatalog::ProductRegistered.new(data: { product_id: uid }) - assert_events("Catalog::Product$#{uid}", product_registered) do - register_product(uid) - end - end - - def test_each_product_has_its_own_lifecycle - product_1_id = SecureRandom.uuid - product_1_registered = ProductCatalog::ProductRegistered.new(data: { product_id: product_1_id }) - product_2_id = SecureRandom.uuid - product_2_registered = ProductCatalog::ProductRegistered.new(data: { product_id: product_2_id }) - - assert_events("Catalog::Product$#{product_1_id}", product_1_registered) do - register_product(product_1_id) - end - - assert_events("Catalog::Product$#{product_2_id}", product_2_registered) do - register_product(product_2_id) - end - end - - private - - def register_product(uid) - run_command(RegisterProduct.new(product_id: uid)) - end - - def fake_name - "Fake name" - end - end -end diff --git a/ecommerce/product_catalog/test/test_helper.rb b/ecommerce/product_catalog/test/test_helper.rb deleted file mode 100644 index 5f5820683..000000000 --- a/ecommerce/product_catalog/test/test_helper.rb +++ /dev/null @@ -1,14 +0,0 @@ -require "minitest/autorun" -require "mutant/minitest/coverage" - -require_relative "../lib/product_catalog" - -module ProductCatalog - class Test < Infra::InMemoryTest - - def before_setup - super() - Configuration.new.call(event_store, command_bus) - end - end -end diff --git a/ecommerce/shipping/.mutant.yml b/ecommerce/shipping/.mutant.yml deleted file mode 100644 index 074917e2b..000000000 --- a/ecommerce/shipping/.mutant.yml +++ /dev/null @@ -1,12 +0,0 @@ -requires: - - ./test/test_helper -integration: minitest -coverage_criteria: - process_abort: true -matcher: - subjects: - - Shipping* - ignore: - - Shipping::Test* - - Shipping::Configuration#initialize - - Shipping::Configuration#call diff --git a/ecommerce/shipping/Gemfile b/ecommerce/shipping/Gemfile deleted file mode 100644 index 8fd887144..000000000 --- a/ecommerce/shipping/Gemfile +++ /dev/null @@ -1,4 +0,0 @@ -source "https://rubygems.org" - -eval_gemfile "../../infra/Gemfile.test" -gem "infra", path: "../../infra" \ No newline at end of file diff --git a/ecommerce/shipping/Gemfile.lock b/ecommerce/shipping/Gemfile.lock deleted file mode 100644 index 43c29a1da..000000000 --- a/ecommerce/shipping/Gemfile.lock +++ /dev/null @@ -1,115 +0,0 @@ -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.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.13.0) - ruby_event_store (= 2.13.0) - arkency-command_bus (0.4.1) - concurrent-ruby - ast (2.4.2) - base64 (0.2.0) - bigdecimal (3.1.4) - concurrent-ruby (1.2.2) - connection_pool (2.4.1) - diff-lcs (1.5.0) - drb (2.2.0) - ruby2_keywords - 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.1) - concurrent-ruby (~> 1.0) - dry-core (~> 1.0) - dry-inflector (~> 1.0) - dry-logic (~> 1.4) - zeitwerk (~> 2.6) - i18n (1.14.1) - 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.8) - rake (13.1.0) - redis-client (0.19.0) - connection_pool - regexp_parser (2.8.3) - ruby2_keywords (0.0.5) - ruby_event_store (2.13.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.0) - concurrent-ruby (< 2) - connection_pool (>= 2.3.0) - rack (>= 2.2.4) - redis-client (>= 0.14.0) - sorbet-runtime (0.5.11190) - tzinfo (2.0.6) - concurrent-ruby (~> 1.0) - unparser (0.6.12) - diff-lcs (~> 1.3) - parser (>= 3.2.2.4) - zeitwerk (2.6.12) - -PLATFORMS - ruby - -DEPENDENCIES - infra! - minitest (= 5.15.0)! - mutant-license! - mutant-minitest (= 0.11.26)! - -BUNDLED WITH - 2.5.9 diff --git a/ecommerce/shipping/Makefile b/ecommerce/shipping/Makefile deleted file mode 100644 index 23850fab1..000000000 --- a/ecommerce/shipping/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -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/shipping/README.md b/ecommerce/shipping/README.md deleted file mode 100644 index 54ffc7e08..000000000 --- a/ecommerce/shipping/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# Shipping - -[![Build Status](https://github.com/RailsEventStore/cqrs-es-sample-with-res/workflows/inventory/badge.svg)](https://github.com/RailsEventStore/cqrs-es-sample-with-res/actions/workflows/shipping.yml) - -#### Up and running - -``` -make install test mutate -``` diff --git a/ecommerce/shipping/lib/shipping.rb b/ecommerce/shipping/lib/shipping.rb deleted file mode 100644 index 78fa022d8..000000000 --- a/ecommerce/shipping/lib/shipping.rb +++ /dev/null @@ -1,51 +0,0 @@ -require "infra" -require_relative "shipping/commands/add_item_to_shipment_picking_list" -require_relative "shipping/events/item_added_to_shipment_picking_list" -require_relative "shipping/services/on_add_item_to_shipment_picking_list" - -require_relative "shipping/commands/remove_item_from_shipment_picking_list" -require_relative "shipping/events/item_removed_from_shipment_picking_list" -require_relative "shipping/services/on_remove_item_from_shipment_picking_list" - -require_relative "shipping/commands/add_shipping_address_to_shipment" -require_relative "shipping/events/shipping_address_added_to_shipment" -require_relative "shipping/services/on_add_shipping_address_to_shipment" - -require_relative "shipping/commands/submit_shipment" -require_relative "shipping/events/shipment_submitted" -require_relative "shipping/services/on_submit_shipment" - -require_relative "shipping/commands/authorize_shipment" -require_relative "shipping/events/shipment_authorized" -require_relative "shipping/services/on_authorize_shipment" - -require_relative "shipping/shipment" -require_relative "shipping/picking_list" -require_relative "shipping/picking_list_item" - -module Shipping - class Configuration - def call(event_store, command_bus) - command_bus.register( - AddItemToShipmentPickingList, - OnAddItemToShipmentPickingList.new(event_store) - ) - command_bus.register( - RemoveItemFromShipmentPickingList, - OnRemoveItemFromShipmentPickingList.new(event_store) - ) - command_bus.register( - AddShippingAddressToShipment, - OnAddShippingAddressToShipment.new(event_store) - ) - command_bus.register( - SubmitShipment, - OnSubmitShipment.new(event_store) - ) - command_bus.register( - AuthorizeShipment, - OnAuthorizeShipment.new(event_store) - ) - end - end -end diff --git a/ecommerce/shipping/lib/shipping/commands/add_item_to_shipment_picking_list.rb b/ecommerce/shipping/lib/shipping/commands/add_item_to_shipment_picking_list.rb deleted file mode 100644 index 500cb32bc..000000000 --- a/ecommerce/shipping/lib/shipping/commands/add_item_to_shipment_picking_list.rb +++ /dev/null @@ -1,8 +0,0 @@ -module Shipping - class AddItemToShipmentPickingList < Infra::Command - attribute :order_id, Infra::Types::UUID - attribute :product_id, Infra::Types::UUID - - alias aggregate_id order_id - end -end diff --git a/ecommerce/shipping/lib/shipping/commands/add_shipping_address_to_shipment.rb b/ecommerce/shipping/lib/shipping/commands/add_shipping_address_to_shipment.rb deleted file mode 100644 index 19febbd0c..000000000 --- a/ecommerce/shipping/lib/shipping/commands/add_shipping_address_to_shipment.rb +++ /dev/null @@ -1,8 +0,0 @@ -module Shipping - class AddShippingAddressToShipment < Infra::Command - attribute :order_id, Infra::Types::UUID - attribute :postal_address, Infra::Types::PostalAddress - - alias aggregate_id order_id - end -end diff --git a/ecommerce/shipping/lib/shipping/commands/authorize_shipment.rb b/ecommerce/shipping/lib/shipping/commands/authorize_shipment.rb deleted file mode 100644 index 7078acc36..000000000 --- a/ecommerce/shipping/lib/shipping/commands/authorize_shipment.rb +++ /dev/null @@ -1,5 +0,0 @@ -module Shipping - class AuthorizeShipment < Infra::Command - attribute :order_id, Infra::Types::UUID - end -end \ No newline at end of file diff --git a/ecommerce/shipping/lib/shipping/commands/remove_item_from_shipment_picking_list.rb b/ecommerce/shipping/lib/shipping/commands/remove_item_from_shipment_picking_list.rb deleted file mode 100644 index 91da4283f..000000000 --- a/ecommerce/shipping/lib/shipping/commands/remove_item_from_shipment_picking_list.rb +++ /dev/null @@ -1,8 +0,0 @@ -module Shipping - class RemoveItemFromShipmentPickingList < Infra::Command - attribute :order_id, Infra::Types::UUID - attribute :product_id, Infra::Types::UUID - - alias aggregate_id order_id - end -end diff --git a/ecommerce/shipping/lib/shipping/commands/submit_shipment.rb b/ecommerce/shipping/lib/shipping/commands/submit_shipment.rb deleted file mode 100644 index 3ccef5452..000000000 --- a/ecommerce/shipping/lib/shipping/commands/submit_shipment.rb +++ /dev/null @@ -1,5 +0,0 @@ -module Shipping - class SubmitShipment < Infra::Command - attribute :order_id, Infra::Types::UUID - end -end \ No newline at end of file diff --git a/ecommerce/shipping/lib/shipping/events/item_added_to_shipment_picking_list.rb b/ecommerce/shipping/lib/shipping/events/item_added_to_shipment_picking_list.rb deleted file mode 100644 index 3b64f1c70..000000000 --- a/ecommerce/shipping/lib/shipping/events/item_added_to_shipment_picking_list.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Shipping - class ItemAddedToShipmentPickingList < Infra::Event - attribute :order_id, Infra::Types::UUID - attribute :product_id, Infra::Types::UUID - end -end diff --git a/ecommerce/shipping/lib/shipping/events/item_removed_from_shipment_picking_list.rb b/ecommerce/shipping/lib/shipping/events/item_removed_from_shipment_picking_list.rb deleted file mode 100644 index 8898e43b8..000000000 --- a/ecommerce/shipping/lib/shipping/events/item_removed_from_shipment_picking_list.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Shipping - class ItemRemovedFromShipmentPickingList < Infra::Event - attribute :order_id, Infra::Types::UUID - attribute :product_id, Infra::Types::UUID - end -end diff --git a/ecommerce/shipping/lib/shipping/events/shipment_authorized.rb b/ecommerce/shipping/lib/shipping/events/shipment_authorized.rb deleted file mode 100644 index 34af937f5..000000000 --- a/ecommerce/shipping/lib/shipping/events/shipment_authorized.rb +++ /dev/null @@ -1,5 +0,0 @@ -module Shipping - class ShipmentAuthorized < Infra::Event - attribute :order_id, Infra::Types::UUID - end -end \ No newline at end of file diff --git a/ecommerce/shipping/lib/shipping/events/shipment_submitted.rb b/ecommerce/shipping/lib/shipping/events/shipment_submitted.rb deleted file mode 100644 index e5a5a63c9..000000000 --- a/ecommerce/shipping/lib/shipping/events/shipment_submitted.rb +++ /dev/null @@ -1,5 +0,0 @@ -module Shipping - class ShipmentSubmitted < Infra::Event - attribute :order_id, Infra::Types::UUID - end -end \ No newline at end of file diff --git a/ecommerce/shipping/lib/shipping/events/shipping_address_added_to_shipment.rb b/ecommerce/shipping/lib/shipping/events/shipping_address_added_to_shipment.rb deleted file mode 100644 index decc5f22a..000000000 --- a/ecommerce/shipping/lib/shipping/events/shipping_address_added_to_shipment.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Shipping - class ShippingAddressAddedToShipment < Infra::Event - attribute :order_id, Infra::Types::UUID - attribute :postal_address, Infra::Types::PostalAddress - end -end diff --git a/ecommerce/shipping/lib/shipping/picking_list.rb b/ecommerce/shipping/lib/shipping/picking_list.rb deleted file mode 100644 index 6275eb4ce..000000000 --- a/ecommerce/shipping/lib/shipping/picking_list.rb +++ /dev/null @@ -1,44 +0,0 @@ -module Shipping - class PickingList - attr_reader :items - - def initialize - @items = [] - end - - def increase_item_quantity(product_id) - item = find_or_add_item(product_id) - item.increase - end - - def decrease_item_quantity(product_id) - item = find_item(product_id) - item.decrease - remove_item(item) if item.quantity.zero? - end - - def has_item?(product_id) - find_item(product_id) - end - - def find_or_add_item(product_id) - find_item(product_id) || add_item(product_id) - end - - def find_item(product_id) - items.find {|i| i.product_id === product_id } - end - - private - - def add_item(product_id) - item = PickingListItem.new(product_id) - items << item - item - end - - def remove_item(item) - items.delete(item) - end - end -end \ No newline at end of file diff --git a/ecommerce/shipping/lib/shipping/picking_list_item.rb b/ecommerce/shipping/lib/shipping/picking_list_item.rb deleted file mode 100644 index 67a5a227c..000000000 --- a/ecommerce/shipping/lib/shipping/picking_list_item.rb +++ /dev/null @@ -1,18 +0,0 @@ -module Shipping - class PickingListItem - attr_reader :product_id, :quantity - - def initialize(product_id) - @product_id = product_id - @quantity = 0 - end - - def increase - @quantity += 1 - end - - def decrease - @quantity -= 1 - end - end -end \ No newline at end of file diff --git a/ecommerce/shipping/lib/shipping/services/on_add_item_to_shipment_picking_list.rb b/ecommerce/shipping/lib/shipping/services/on_add_item_to_shipment_picking_list.rb deleted file mode 100644 index 178fa2a77..000000000 --- a/ecommerce/shipping/lib/shipping/services/on_add_item_to_shipment_picking_list.rb +++ /dev/null @@ -1,16 +0,0 @@ -module Shipping - class OnAddItemToShipmentPickingList - def initialize(event_store) - @repository = AggregateRoot::Repository.new(event_store) - end - - def call(command) - @repository.with_aggregate( - Shipment.new(command.order_id), - "Shipping::Shipment$#{command.order_id}" - ) do |shipment| - shipment.add_item(command.product_id) - end - end - end -end diff --git a/ecommerce/shipping/lib/shipping/services/on_add_shipping_address_to_shipment.rb b/ecommerce/shipping/lib/shipping/services/on_add_shipping_address_to_shipment.rb deleted file mode 100644 index 4df479b36..000000000 --- a/ecommerce/shipping/lib/shipping/services/on_add_shipping_address_to_shipment.rb +++ /dev/null @@ -1,16 +0,0 @@ -module Shipping - class OnAddShippingAddressToShipment - def initialize(event_store) - @repository = AggregateRoot::Repository.new(event_store) - end - - def call(command) - @repository.with_aggregate( - Shipment.new(command.order_id), - "Shipping::Shipment$#{command.order_id}" - ) do |shipment| - shipment.add_address(command.postal_address) - end - end - end -end diff --git a/ecommerce/shipping/lib/shipping/services/on_authorize_shipment.rb b/ecommerce/shipping/lib/shipping/services/on_authorize_shipment.rb deleted file mode 100644 index 706a6e372..000000000 --- a/ecommerce/shipping/lib/shipping/services/on_authorize_shipment.rb +++ /dev/null @@ -1,16 +0,0 @@ -module Shipping - class OnAuthorizeShipment - def initialize(event_store) - @repository = AggregateRoot::Repository.new(event_store) - end - - def call(command) - @repository.with_aggregate( - Shipment.new(command.order_id), - "Shipping::Shipment$#{command.order_id}" - ) do |shipment| - shipment.authorize - end - end - end -end diff --git a/ecommerce/shipping/lib/shipping/services/on_remove_item_from_shipment_picking_list.rb b/ecommerce/shipping/lib/shipping/services/on_remove_item_from_shipment_picking_list.rb deleted file mode 100644 index 883bd3c0b..000000000 --- a/ecommerce/shipping/lib/shipping/services/on_remove_item_from_shipment_picking_list.rb +++ /dev/null @@ -1,16 +0,0 @@ -module Shipping - class OnRemoveItemFromShipmentPickingList - def initialize(event_store) - @repository = AggregateRoot::Repository.new(event_store) - end - - def call(command) - @repository.with_aggregate( - Shipment.new(command.order_id), - "Shipping::Shipment$#{command.order_id}" - ) do |shipment| - shipment.remove_item(command.product_id) - end - end - end -end diff --git a/ecommerce/shipping/lib/shipping/services/on_submit_shipment.rb b/ecommerce/shipping/lib/shipping/services/on_submit_shipment.rb deleted file mode 100644 index f36e3daa3..000000000 --- a/ecommerce/shipping/lib/shipping/services/on_submit_shipment.rb +++ /dev/null @@ -1,16 +0,0 @@ -module Shipping - class OnSubmitShipment - def initialize(event_store) - @repository = AggregateRoot::Repository.new(event_store) - end - - def call(command) - @repository.with_aggregate( - Shipment.new(command.order_id), - "Shipping::Shipment$#{command.order_id}" - ) do |shipment| - shipment.submit - end - end - end -end diff --git a/ecommerce/shipping/lib/shipping/shipment.rb b/ecommerce/shipping/lib/shipping/shipment.rb deleted file mode 100644 index ce272c672..000000000 --- a/ecommerce/shipping/lib/shipping/shipment.rb +++ /dev/null @@ -1,98 +0,0 @@ -module Shipping - class Shipment - include AggregateRoot - attr_reader :state - - ItemNotFound = Class.new(StandardError) - ShippingAddressMissing = Class.new(StandardError) - NotSubmitted = Class.new(StandardError) - AlreadySubmitted = Class.new(StandardError) - AlreadyAuthorized = Class.new(StandardError) - - def initialize(order_id) - @order_id = order_id - @picking_list = PickingList.new - @state = :draft - end - - def add_item(product_id) - apply ItemAddedToShipmentPickingList.new( - data: { - order_id: @order_id, - product_id: product_id - } - ) - end - - def remove_item(product_id) - raise ItemNotFound unless has_item?(product_id) - - apply ItemRemovedFromShipmentPickingList.new( - data: { - order_id: @order_id, - product_id: product_id - } - ) - end - - def add_address(postal_address) - apply ShippingAddressAddedToShipment.new( - data: { - order_id: @order_id, - postal_address: postal_address - } - ) - end - - def submit - raise AlreadySubmitted if state.equal?(:submitted) - raise ShippingAddressMissing unless state.equal?(:address_set) - - apply ShipmentSubmitted.new( - data: { - order_id: @order_id - } - ) - end - - def authorize - raise AlreadyAuthorized if state.equal?(:authorized) - raise NotSubmitted unless state.equal?(:submitted) - - apply ShipmentAuthorized.new( - data: { - order_id: @order_id - } - ) - end - - private - - attr_reader :shipping_address - - on ItemAddedToShipmentPickingList do |event| - @picking_list.increase_item_quantity(event.data.fetch(:product_id)) - end - - on ItemRemovedFromShipmentPickingList do |event| - @picking_list.decrease_item_quantity(event.data.fetch(:product_id)) - end - - on ShippingAddressAddedToShipment do |event| - @shipping_address = event.data.fetch(:postal_address) - @state = :address_set - end - - on ShipmentSubmitted do |event| - @state = :submitted - end - - on ShipmentAuthorized do |event| - @state = :authorized - end - - def has_item?(product_id) - @picking_list.has_item?(product_id) - end - end -end diff --git a/ecommerce/shipping/test/on_add_item_to_shipment_picking_list_test.rb b/ecommerce/shipping/test/on_add_item_to_shipment_picking_list_test.rb deleted file mode 100644 index 11bbfd0fa..000000000 --- a/ecommerce/shipping/test/on_add_item_to_shipment_picking_list_test.rb +++ /dev/null @@ -1,23 +0,0 @@ -require_relative "test_helper" - -module Shipping - class OnAddItemToShipmentPickingListTest < Test - cover "Shipping::OnAddItemToShipmentPickingList*" - - def test_add_item_to_shipment_picking_list - order_id = SecureRandom.uuid - product_id = SecureRandom.uuid - stream = "Shipping::Shipment$#{order_id}" - - assert_events( - stream, - ItemAddedToShipmentPickingList.new( - data: { - order_id: order_id, - product_id: product_id - } - ) - ) { act(AddItemToShipmentPickingList.new(order_id: order_id, product_id: product_id)) } - end - end -end diff --git a/ecommerce/shipping/test/on_add_shipping_address_to_shipment_test.rb b/ecommerce/shipping/test/on_add_shipping_address_to_shipment_test.rb deleted file mode 100644 index def22c50c..000000000 --- a/ecommerce/shipping/test/on_add_shipping_address_to_shipment_test.rb +++ /dev/null @@ -1,30 +0,0 @@ -require_relative "test_helper" - -module Shipping - class OnAddShippingAddressToShipmentTest < Test - cover "Shipping::OnAddShippingAddressToShipment*" - - def test_add_item_to_shipment_picking_list - order_id = SecureRandom.uuid - address = fake_address - stream = "Shipping::Shipment$#{order_id}" - - assert_events( - stream, - ShippingAddressAddedToShipment.new( - data: { - order_id: order_id, - postal_address: address - } - ) - ) do - act( - AddShippingAddressToShipment.new( - order_id: order_id, - postal_address: address - ) - ) - end - end - end -end \ No newline at end of file diff --git a/ecommerce/shipping/test/on_authorize_shipment_test.rb b/ecommerce/shipping/test/on_authorize_shipment_test.rb deleted file mode 100644 index ad0137603..000000000 --- a/ecommerce/shipping/test/on_authorize_shipment_test.rb +++ /dev/null @@ -1,56 +0,0 @@ -require_relative "test_helper" - -module Shipping - class OnAuthorizeShipmentTest < Test - cover "Shipping::OnAuthorizeShipment*" - - def test_authorize_shipment - order_id = SecureRandom.uuid - address = fake_address - stream = "Shipping::Shipment$#{order_id}" - - arrange( - AddShippingAddressToShipment.new( - order_id: order_id, - postal_address: address - ), - SubmitShipment.new(order_id: order_id) - ) - - assert_events( - stream, - ShipmentAuthorized.new( - data: { - order_id: order_id - } - ) - ) { act(AuthorizeShipment.new(order_id: order_id)) } - end - - def test_shipment_cannot_be_authorized_when_not_submitted - order_id = SecureRandom.uuid - - assert_raises(Shipment::NotSubmitted) do - act(AuthorizeShipment.new(order_id: order_id)) - end - end - - def test_shipment_cannot_be_authorized_when_already_authorized - order_id = SecureRandom.uuid - address = fake_address - - arrange( - AddShippingAddressToShipment.new( - order_id: order_id, - postal_address: address - ), - SubmitShipment.new(order_id: order_id), - AuthorizeShipment.new(order_id: order_id) - ) - - assert_raises(Shipment::AlreadyAuthorized) do - act(AuthorizeShipment.new(order_id: order_id)) - end - end - end -end diff --git a/ecommerce/shipping/test/on_remove_item_from_shipment_picking_list_test.rb b/ecommerce/shipping/test/on_remove_item_from_shipment_picking_list_test.rb deleted file mode 100644 index 9b4a903ff..000000000 --- a/ecommerce/shipping/test/on_remove_item_from_shipment_picking_list_test.rb +++ /dev/null @@ -1,41 +0,0 @@ -require_relative "test_helper" - -module Shipping - class OnRemoveItemFromShipmentPickingListTest < Test - cover "Shipping::OnRemoveItemFromShipmentPickingList*" - - def test_remove_item_from_shipment_picking_list - order_id = SecureRandom.uuid - product_id = SecureRandom.uuid - stream = "Shipping::Shipment$#{order_id}" - - run_command(AddItemToShipmentPickingList.new( - order_id: order_id, - product_id: product_id - )) - - assert_events( - stream, - ItemRemovedFromShipmentPickingList.new( - data: { - order_id: order_id, - product_id: product_id - } - ) - ) { act(RemoveItemFromShipmentPickingList.new(order_id: order_id, product_id: product_id)) } - end - - def test_should_not_allow_removing_non_existing_items - order_id = SecureRandom.uuid - product_id = SecureRandom.uuid - stream = "Shipping::Shipment$#{order_id}" - - assert_raises(Shipment::ItemNotFound) do - act(RemoveItemFromShipmentPickingList.new( - order_id: order_id, - product_id: product_id - )) - end - end - end -end diff --git a/ecommerce/shipping/test/on_submit_shipment_test.rb b/ecommerce/shipping/test/on_submit_shipment_test.rb deleted file mode 100644 index df0756b0a..000000000 --- a/ecommerce/shipping/test/on_submit_shipment_test.rb +++ /dev/null @@ -1,54 +0,0 @@ -require_relative "test_helper" - -module Shipping - class OnSubmitShipmentTest < Test - cover "Shipping::OnSubmitShipment*" - - def test_submit_shipment - order_id = SecureRandom.uuid - address = fake_address - stream = "Shipping::Shipment$#{order_id}" - - run_command( - AddShippingAddressToShipment.new( - order_id: order_id, - postal_address: address - ) - ) - - assert_events( - stream, - ShipmentSubmitted.new( - data: { - order_id: order_id - } - ) - ) { act(SubmitShipment.new(order_id: order_id)) } - end - - def test_shipment_cannot_be_submitted_when_shipping_address_is_missing - order_id = SecureRandom.uuid - - assert_raises(Shipment::ShippingAddressMissing) do - act(SubmitShipment.new(order_id: order_id)) - end - end - - def test_shipment_cannot_be_submitted_when_already_submitted - order_id = SecureRandom.uuid - address = fake_address - - arrange( - AddShippingAddressToShipment.new( - order_id: order_id, - postal_address: address - ), - SubmitShipment.new(order_id: order_id) - ) - - assert_raises(Shipment::AlreadySubmitted) do - act(SubmitShipment.new(order_id: order_id)) - end - end - end -end diff --git a/ecommerce/shipping/test/picking_list_item_test.rb b/ecommerce/shipping/test/picking_list_item_test.rb deleted file mode 100644 index cb70bd492..000000000 --- a/ecommerce/shipping/test/picking_list_item_test.rb +++ /dev/null @@ -1,33 +0,0 @@ -require_relative "test_helper" - -module Shipping - class PickingListItemTest < Test - - def test_initialize - product_id = SecureRandom.uuid - list_item = PickingListItem.new(product_id) - - assert_equal product_id, list_item.product_id - assert_equal 0, list_item.quantity - end - - def test_increase - product_id = SecureRandom.uuid - list_item = PickingListItem.new(product_id) - - list_item.increase - - assert_equal 1, list_item.quantity - end - - def test_decrease - product_id = SecureRandom.uuid - list_item = PickingListItem.new(product_id) - - list_item.increase - list_item.decrease - - assert_equal 0, list_item.quantity - end - end -end \ No newline at end of file diff --git a/ecommerce/shipping/test/picking_list_test.rb b/ecommerce/shipping/test/picking_list_test.rb deleted file mode 100644 index b72d85e70..000000000 --- a/ecommerce/shipping/test/picking_list_test.rb +++ /dev/null @@ -1,48 +0,0 @@ -require_relative "test_helper" - -module Shipping - class PickingListTest < Test - - def test_initialize - list = PickingList.new - - assert_equal 0, list.items.size - end - - def test_increase_item_quantity - product_one_id = SecureRandom.uuid - product_two_id = SecureRandom.uuid - list = PickingList.new - - list.increase_item_quantity(product_one_id) - - assert_equal 1, list.items.size - assert_equal 1, list.find_item(product_one_id).quantity - - list.increase_item_quantity(product_two_id) - - assert_equal 2, list.items.size - assert_equal 1, list.find_item(product_two_id).quantity - end - - def test_decrease_item_quantity - product_id = SecureRandom.uuid - list = PickingList.new - - list.increase_item_quantity(product_id) - list.increase_item_quantity(product_id) - - assert_equal 1, list.items.size - assert_equal 2, list.find_item(product_id).quantity - - list.decrease_item_quantity(product_id) - - assert_equal 1, list.items.size - assert_equal 1, list.find_item(product_id).quantity - - list.decrease_item_quantity(product_id) - - assert_equal 0, list.items.size - end - end -end \ No newline at end of file diff --git a/ecommerce/shipping/test/shipment_test.rb b/ecommerce/shipping/test/shipment_test.rb deleted file mode 100644 index 83da43f65..000000000 --- a/ecommerce/shipping/test/shipment_test.rb +++ /dev/null @@ -1,145 +0,0 @@ -require_relative "test_helper" - -module Shipping - class ShipmentTest < Test - cover "Shipping::Shipment*" - - def test_add_item_publishes_event - product_id = SecureRandom.uuid - shipment = Shipment.new(order_id) - - shipment.add_item(product_id) - - assert_changes( - shipment.unpublished_events, - [ - ItemAddedToShipmentPickingList.new( - data: { - order_id: order_id, - product_id: product_id - } - ) - ] - ) - end - - def test_remove_item_publishes_event - product_id = SecureRandom.uuid - shipment = Shipment.new(order_id) - - shipment.add_item(product_id) - shipment.remove_item(product_id) - - assert_changes( - shipment.unpublished_events, - [ - ItemAddedToShipmentPickingList.new( - data: { - order_id: order_id, - product_id: product_id - } - ), - ItemRemovedFromShipmentPickingList.new( - data: { - order_id: order_id, - product_id: product_id - } - ) - ] - ) - end - - def test_should_not_allow_removing_non_existing_items - product_id = SecureRandom.uuid - shipment = Shipment.new(order_id) - - assert_raises(Shipment::ItemNotFound) { shipment.remove_item(product_id) } - end - - def test_add_address_publishes_event - shipment = Shipment.new(order_id) - address = fake_address - - shipment.add_address(address) - - assert_changes( - shipment.unpublished_events, - [ - ShippingAddressAddedToShipment.new( - data: { - order_id: order_id, - postal_address: address - } - ) - ] - ) - end - - def test_submit_shipment_publishes_event - shipment = Shipment.new(order_id) - address = fake_address - - shipment.add_address(address) - shipment.submit - - assert_changes( - shipment.unpublished_events, - [ - ShippingAddressAddedToShipment.new( - data: { - order_id: order_id, - postal_address: address - } - ), - ShipmentSubmitted.new( - data: { - order_id: order_id - } - ) - ] - ) - end - def test_authorize_shipment_publishes_event - shipment = Shipment.new(order_id) - address = fake_address - - shipment.add_address(address) - shipment.submit - shipment.authorize - - assert_changes( - shipment.unpublished_events, - [ - ShippingAddressAddedToShipment.new( - data: { - order_id: order_id, - postal_address: address - } - ), - ShipmentSubmitted.new( - data: { - order_id: order_id - } - ), - ShipmentAuthorized.new( - data: { - order_id: order_id - } - ) - ] - ) - end - - def test_default_state_is_draft - shipment = Shipment.new(order_id) - - assert_equal :draft, shipment.state - end - - private - - def order_id - @order_id ||= SecureRandom.uuid - end - end -end diff --git a/ecommerce/shipping/test/test_helper.rb b/ecommerce/shipping/test/test_helper.rb deleted file mode 100644 index 6064aab04..000000000 --- a/ecommerce/shipping/test/test_helper.rb +++ /dev/null @@ -1,25 +0,0 @@ -require "minitest/autorun" -require "mutant/minitest/coverage" - -require_relative "../lib/shipping" - -module Shipping - class Test < Infra::InMemoryTest - - def before_setup - super - Shipping::Configuration.new.call(event_store, command_bus) - end - - private - - def fake_address - Infra::Types::PostalAddress.new( - line_1: "Mme Anna Kowalska", - line_2: "Ul. Bosmanska 1", - line_3: "81-116 GDYNIA", - line_4: "POLAND" - ) - end - end -end diff --git a/ecommerce/taxes/.mutant.yml b/ecommerce/taxes/.mutant.yml deleted file mode 100644 index 327ec3984..000000000 --- a/ecommerce/taxes/.mutant.yml +++ /dev/null @@ -1,12 +0,0 @@ -requires: - - ./test/test_helper -integration: minitest -coverage_criteria: - process_abort: true -matcher: - subjects: - - Taxes* - ignore: - - Taxes::Test* - - Taxes::Configuration* - - Taxes::VatRateCatalog#vat_rate_for \ No newline at end of file diff --git a/ecommerce/taxes/Gemfile b/ecommerce/taxes/Gemfile deleted file mode 100644 index 8fd887144..000000000 --- a/ecommerce/taxes/Gemfile +++ /dev/null @@ -1,4 +0,0 @@ -source "https://rubygems.org" - -eval_gemfile "../../infra/Gemfile.test" -gem "infra", path: "../../infra" \ No newline at end of file diff --git a/ecommerce/taxes/Gemfile.lock b/ecommerce/taxes/Gemfile.lock deleted file mode 100644 index 4a73abff2..000000000 --- a/ecommerce/taxes/Gemfile.lock +++ /dev/null @@ -1,119 +0,0 @@ -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.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.13.0) - ruby_event_store (= 2.13.0) - arkency-command_bus (0.4.1) - concurrent-ruby - ast (2.4.2) - base64 (0.2.0) - bigdecimal (3.1.4) - concurrent-ruby (1.2.2) - connection_pool (2.4.1) - diff-lcs (1.5.0) - drb (2.2.0) - ruby2_keywords - 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.1) - concurrent-ruby (~> 1.0) - dry-core (~> 1.0) - dry-inflector (~> 1.0) - dry-logic (~> 1.4) - zeitwerk (~> 2.6) - i18n (1.14.1) - 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.8) - rake (13.1.0) - redis-client (0.19.0) - connection_pool - regexp_parser (2.8.3) - ruby2_keywords (0.0.5) - ruby_event_store (2.13.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.0) - concurrent-ruby (< 2) - connection_pool (>= 2.3.0) - rack (>= 2.2.4) - redis-client (>= 0.14.0) - sorbet-runtime (0.5.11190) - tzinfo (2.0.6) - concurrent-ruby (~> 1.0) - unparser (0.6.12) - diff-lcs (~> 1.3) - parser (>= 3.2.2.4) - zeitwerk (2.6.12) - -PLATFORMS - arm64-darwin-20 - arm64-darwin-21 - ruby - x86_64-darwin-20 - x86_64-linux - -DEPENDENCIES - infra! - minitest (= 5.15.0)! - mutant-license! - mutant-minitest (= 0.11.26)! - -BUNDLED WITH - 2.5.9 diff --git a/ecommerce/taxes/Makefile b/ecommerce/taxes/Makefile deleted file mode 100644 index 23850fab1..000000000 --- a/ecommerce/taxes/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -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/taxes/README.md b/ecommerce/taxes/README.md deleted file mode 100644 index e4423ba4c..000000000 --- a/ecommerce/taxes/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# Taxes - -[![Build Status](https://github.com/RailsEventStore/cqrs-es-sample-with-res/workflows/taxes/badge.svg)](https://github.com/RailsEventStore/cqrs-es-sample-with-res/actions/workflows/taxes.yml) - - -#### Up and running - -``` -make install test mutate -``` diff --git a/ecommerce/taxes/lib/taxes.rb b/ecommerce/taxes/lib/taxes.rb deleted file mode 100644 index f1c9db7a7..000000000 --- a/ecommerce/taxes/lib/taxes.rb +++ /dev/null @@ -1,24 +0,0 @@ -require 'infra' -require_relative 'taxes/commands' -require_relative 'taxes/events' -require_relative 'taxes/services' -require_relative 'taxes/product' -require_relative 'taxes/vat_rate_catalog' - -module Taxes - class Configuration - def self.available_vat_rates - @@available_vat_rates - end - - def initialize(available_vat_rates = []) - @available_vat_rates = available_vat_rates - end - - def call(event_store, command_bus) - @@available_vat_rates = @available_vat_rates - command_bus.register(SetVatRate, SetVatRateHandler.new(event_store)) - command_bus.register(DetermineVatRate, DetermineVatRateHandler.new(event_store)) - end - end -end diff --git a/ecommerce/taxes/lib/taxes/commands.rb b/ecommerce/taxes/lib/taxes/commands.rb deleted file mode 100644 index b3bb5153a..000000000 --- a/ecommerce/taxes/lib/taxes/commands.rb +++ /dev/null @@ -1,11 +0,0 @@ -module Taxes - class SetVatRate < Infra::Command - attribute :product_id, Infra::Types::UUID - attribute :vat_rate, Infra::Types::VatRate - end - - class DetermineVatRate < Infra::Command - attribute :product_id, Infra::Types::UUID - attribute :order_id, Infra::Types::UUID - end -end \ No newline at end of file diff --git a/ecommerce/taxes/lib/taxes/events.rb b/ecommerce/taxes/lib/taxes/events.rb deleted file mode 100644 index 7f3f308b9..000000000 --- a/ecommerce/taxes/lib/taxes/events.rb +++ /dev/null @@ -1,12 +0,0 @@ -module Taxes - class VatRateSet < Infra::Event - attribute :product_id, Infra::Types::UUID - attribute :vat_rate, Infra::Types::VatRate - end - - class VatRateDetermined < Infra::Event - attribute :order_id, Infra::Types::UUID - attribute :product_id, Infra::Types::UUID - attribute :vat_rate, Infra::Types::VatRate - end -end \ No newline at end of file diff --git a/ecommerce/taxes/lib/taxes/product.rb b/ecommerce/taxes/lib/taxes/product.rb deleted file mode 100644 index 493c1825c..000000000 --- a/ecommerce/taxes/lib/taxes/product.rb +++ /dev/null @@ -1,24 +0,0 @@ -module Taxes - class Product - include AggregateRoot - - VatRateNotApplicable = Class.new(StandardError) - - def initialize(id) - @id = id - end - - def set_vat_rate(vat_rate) - raise VatRateNotApplicable unless vat_rate_applicable?(vat_rate) - apply(VatRateSet.new(data: { product_id: @id, vat_rate: vat_rate })) - end - - private - - def vat_rate_applicable?(vat_rate) - Configuration.available_vat_rates.include?(vat_rate) - end - - on(VatRateSet) { |_| } - end -end diff --git a/ecommerce/taxes/lib/taxes/services.rb b/ecommerce/taxes/lib/taxes/services.rb deleted file mode 100644 index eb639f8bf..000000000 --- a/ecommerce/taxes/lib/taxes/services.rb +++ /dev/null @@ -1,37 +0,0 @@ -module Taxes - class SetVatRateHandler - def initialize(event_store) - @repository = Infra::AggregateRootRepository.new(event_store) - end - - def call(cmd) - @repository.with_aggregate(Product, cmd.product_id) do |product| - product.set_vat_rate(cmd.vat_rate) - end - end - end - - class DetermineVatRateHandler - def initialize(event_store) - @catalog = VatRateCatalog.new(event_store) - @event_store = event_store - end - - def call(cmd) - order_id = cmd.order_id - product_id = cmd.product_id - vat_rate = catalog.vat_rate_for(product_id) - return unless vat_rate - event = VatRateDetermined.new(data: { order_id: order_id, product_id: product_id, vat_rate: vat_rate }) - event_store.publish(event, stream_name: stream_name(order_id)) - end - - private - - attr_reader :catalog, :event_store - - def stream_name(order_id) - "Taxes::Order$#{order_id}" - end - end -end \ No newline at end of file diff --git a/ecommerce/taxes/lib/taxes/vat_rate_catalog.rb b/ecommerce/taxes/lib/taxes/vat_rate_catalog.rb deleted file mode 100644 index d00fd4266..000000000 --- a/ecommerce/taxes/lib/taxes/vat_rate_catalog.rb +++ /dev/null @@ -1,18 +0,0 @@ -module Taxes - class VatRateCatalog - def initialize(event_store) - @event_store = event_store - end - - def vat_rate_for(product_id) - @event_store - .read - .of_type(VatRateSet) - .to_a - .filter { |e| e.data.fetch(:product_id).eql?(product_id) } - .last - &.data - &.fetch(:vat_rate) - end - end -end \ No newline at end of file diff --git a/ecommerce/taxes/test/taxes_test.rb b/ecommerce/taxes/test/taxes_test.rb deleted file mode 100644 index 77e58d57f..000000000 --- a/ecommerce/taxes/test/taxes_test.rb +++ /dev/null @@ -1,53 +0,0 @@ -require_relative "test_helper" - -module Taxes - class TaxesTest < Test - def test_setting_available_vat_rate - product_id = SecureRandom.uuid - vat_rate_set = VatRateSet.new(data: { product_id: product_id, vat_rate: available_vat_rate }) - assert_events("Taxes::Product$#{product_id}", vat_rate_set) do - set_vat_rate(product_id, available_vat_rate) - end - end - - def test_setting_unavailable_vat_rate_should_raise_error - product_id = SecureRandom.uuid - assert_raises(Product::VatRateNotApplicable) do - set_vat_rate(product_id, unavailable_vat_rate) - end - end - - def test_determining_vat_rate - order_id = SecureRandom.uuid - product_id = SecureRandom.uuid - another_product_id = SecureRandom.uuid - - set_vat_rate(product_id, available_vat_rate) - vat_rate_determined = VatRateDetermined.new(data: { order_id: order_id, product_id: product_id, vat_rate: available_vat_rate }) - assert_events("Taxes::Order$#{order_id}", vat_rate_determined) do - determine_vat_rate(order_id, product_id, available_vat_rate) - end - assert_events("Taxes::Order$#{order_id}") do - determine_vat_rate(order_id, another_product_id, available_vat_rate) - end - end - - private - - def set_vat_rate(product_id, vat_rate) - run_command(SetVatRate.new(product_id: product_id, vat_rate: vat_rate)) - end - - def determine_vat_rate(order_id, product_id, vat_rate) - run_command(DetermineVatRate.new(order_id: order_id, product_id: product_id, vat_rate: vat_rate)) - end - - def available_vat_rate - Configuration.available_vat_rates.first - end - - def unavailable_vat_rate - Infra::Types::VatRate.new(code: "50", rate: 50) - end - end -end diff --git a/ecommerce/taxes/test/test_helper.rb b/ecommerce/taxes/test/test_helper.rb deleted file mode 100644 index a23c2d113..000000000 --- a/ecommerce/taxes/test/test_helper.rb +++ /dev/null @@ -1,21 +0,0 @@ -require "minitest/autorun" -require "mutant/minitest/coverage" - -require_relative "../lib/taxes" - -module Taxes - class Test < Infra::InMemoryTest - cover "Taxes*" - - def before_setup - super - Configuration.new([dummy_vat_rate]).call(event_store, command_bus) - end - - private - - def dummy_vat_rate - Infra::Types::VatRate.new(code: "20", rate: 20) - end - end -end diff --git a/hanami_application/README.md b/hanami_application/README.md deleted file mode 100644 index 1c13d671a..000000000 --- a/hanami_application/README.md +++ /dev/null @@ -1,4 +0,0 @@ -Coming soon, there's no obstacle to use it with ~~Rails~~ **RubyEventStore**. - -It will reimplement most, if not all, of counterpart Rails application. It will also reuse contexts from [ecommerce/](../ecommerce/) - diff --git a/infra/Gemfile.lock b/infra/Gemfile.lock index 6af14d8eb..61ce38f5b 100644 --- a/infra/Gemfile.lock +++ b/infra/Gemfile.lock @@ -4,8 +4,6 @@ PATH 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 @@ -41,28 +39,8 @@ GEM diff-lcs (1.5.0) drb (2.2.0) ruby2_keywords - 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.1) - concurrent-ruby (~> 1.0) - dry-core (~> 1.0) - dry-inflector (~> 1.0) - dry-logic (~> 1.4) - zeitwerk (~> 2.6) i18n (1.14.1) concurrent-ruby (~> 1.0) - ice_nine (0.11.2) minitest (5.15.0) mutant (0.11.26) diff-lcs (~> 1.3) @@ -100,7 +78,6 @@ GEM unparser (0.6.12) diff-lcs (~> 1.3) parser (>= 3.2.2.4) - zeitwerk (2.6.12) PLATFORMS arm64-darwin-20 diff --git a/infra/infra.gemspec b/infra/infra.gemspec index d11576240..d6600e089 100644 --- a/infra/infra.gemspec +++ b/infra/infra.gemspec @@ -10,8 +10,6 @@ Gem::Specification.new do |spec| spec.summary = "infrastructure for the application" spec.add_dependency "rake" - spec.add_dependency "dry-struct" - spec.add_dependency "dry-types" spec.add_dependency "aggregate_root", "~> 2.13" spec.add_dependency "arkency-command_bus" spec.add_dependency "ruby_event_store", "~> 2.13" diff --git a/infra/lib/infra.rb b/infra/lib/infra.rb index fe6255798..f1d55b580 100644 --- a/infra/lib/infra.rb +++ b/infra/lib/infra.rb @@ -1,8 +1,6 @@ require "ruby_event_store" require "aggregate_root" require "arkency/command_bus" -require "dry-struct" -require "dry-types" require "aggregate_root" require "active_support/notifications" require "minitest" @@ -15,5 +13,4 @@ require_relative "infra/event" require_relative "infra/event_store" require_relative "infra/process" -require_relative "infra/types" require_relative "infra/testing" diff --git a/infra/lib/infra/command.rb b/infra/lib/infra/command.rb index 00c1aa263..37916b6af 100644 --- a/infra/lib/infra/command.rb +++ b/infra/lib/infra/command.rb @@ -1,11 +1,5 @@ module Infra - class Command < Dry::Struct + class Command Invalid = Class.new(StandardError) - - def self.new(*) - super - rescue Dry::Struct::Error => doh - raise Invalid, doh - end end end diff --git a/infra/lib/infra/event.rb b/infra/lib/infra/event.rb index 67a10176f..2548b377c 100644 --- a/infra/lib/infra/event.rb +++ b/infra/lib/infra/event.rb @@ -1,32 +1,4 @@ -require "active_support/core_ext/hash" - module Infra class Event < RubyEventStore::Event - module WithSchema - class Schema < Dry::Struct - transform_keys(&:to_sym) - end - - module ClassMethods - extend Forwardable - def_delegators :schema, :attribute, :attribute? - - def schema - @schema ||= Class.new(Schema) - end - end - - module Constructor - def initialize(event_id: SecureRandom.uuid, metadata: nil, data: {}) - super(event_id: event_id, metadata: metadata, data: data.deep_merge(self.class.schema.new(data.deep_symbolize_keys).to_h)) - end - end - - def self.included(klass) - klass.extend WithSchema::ClassMethods - klass.include WithSchema::Constructor - end - end - include WithSchema end end diff --git a/infra/lib/infra/types.rb b/infra/lib/infra/types.rb deleted file mode 100644 index f4f1d45fb..000000000 --- a/infra/lib/infra/types.rb +++ /dev/null @@ -1,41 +0,0 @@ -module Infra - module Types - include Dry.Types - UUID = - Types::Strict::String.constrained( - format: /\A[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}\z/i - ) - ID = Types::Strict::Integer - Metadata = - Types::Hash.schema( - timestamp: Types::Time.meta(omittable: true) - ) - OrderNumber = - Types::Strict::String.constrained(format: /\A\d{4}\/\d{2}\/\d+\z/i) - Quantity = Types::Strict::Integer.constrained(gt: 0) - Price = Types::Coercible::Decimal.constrained(gt: 0) - Value = Types::Coercible::Decimal - PercentageDiscount = Types::Coercible::Decimal.constrained(gt: 0, lteq: 100) - CouponDiscount = Types::Coercible::Float.constrained(gt: 0, lteq: 100) - UUIDQuantityHash = Types::Hash.map(UUID, Quantity) - - class VatRate < Dry::Struct - include Comparable - attribute :code, Types::String - attribute :rate, Types::Coercible::Decimal.constrained(gteq: 0, lteq: 100) - - def <=>(other) - rate <=> other.rate - end - - alias to_d rate - end - - class PostalAddress < Dry::Struct - attribute :line_1, Types::String - attribute :line_2, Types::String - attribute :line_3, Types::String - attribute :line_4, Types::String - end - end -end diff --git a/pricing_catalog_rails_app/.dockerignore b/pricing_catalog_rails_app/.dockerignore deleted file mode 100644 index 96123753a..000000000 --- a/pricing_catalog_rails_app/.dockerignore +++ /dev/null @@ -1,37 +0,0 @@ -# See https://docs.docker.com/engine/reference/builder/#dockerignore-file for more about ignoring files. - -# Ignore git directory. -/.git/ - -# Ignore bundler config. -/.bundle - -# Ignore all environment files (except templates). -/.env* -!/.env*.erb - -# Ignore all default key files. -/config/master.key -/config/credentials/*.key - -# Ignore all logfiles and tempfiles. -/log/* -/tmp/* -!/log/.keep -!/tmp/.keep - -# Ignore pidfiles, but keep the directory. -/tmp/pids/* -!/tmp/pids/.keep - -# Ignore storage (uploaded files in development and any SQLite databases). -/storage/* -!/storage/.keep -/tmp/storage/* -!/tmp/storage/.keep - -# Ignore assets. -/node_modules/ -/app/assets/builds/* -!/app/assets/builds/.keep -/public/assets diff --git a/pricing_catalog_rails_app/.gitignore b/pricing_catalog_rails_app/.gitignore deleted file mode 100644 index 802489bb8..000000000 --- a/pricing_catalog_rails_app/.gitignore +++ /dev/null @@ -1,37 +0,0 @@ -!/log/.keep -!/storage/.keep -!/tmp/.keep -.byebug_history -.yarn-integrity -/.bundle -/config/master.key -/db/*.sqlite3* -/db/*.sqlite3-journal -/elm-stuff -/log/* -/node_modules -/public/assets -/public/packs -/public/packs-test -/storage/* -/tmp/* -/yarn-error.log -coverage -yarn-debug.log* - -/public/packs -/public/packs-test -/node_modules -/yarn-error.log -yarn-debug.log* -.yarn-integrity -.env*.local - -.idea -.ruby-version -/app/assets/builds/* -!/app/assets/builds/.keep - -# Event to handlers and handler to events mappings generated by big_picture.rb script -/lib/event_to_handlers.rb -/lib/handler_to_events.rb \ No newline at end of file diff --git a/pricing_catalog_rails_app/Dockerfile b/pricing_catalog_rails_app/Dockerfile deleted file mode 100644 index 0ffa0232b..000000000 --- a/pricing_catalog_rails_app/Dockerfile +++ /dev/null @@ -1,62 +0,0 @@ -# syntax = docker/dockerfile:1 - -# Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile -ARG RUBY_VERSION=3.2.0 -FROM registry.docker.com/library/ruby:$RUBY_VERSION-slim as base - -# Rails app lives here -WORKDIR /rails - -# Set production environment -ENV RAILS_ENV="production" \ - BUNDLE_DEPLOYMENT="1" \ - BUNDLE_PATH="/usr/local/bundle" \ - BUNDLE_WITHOUT="development" - - -# Throw-away build stage to reduce size of final image -FROM base as build - -# Install packages needed to build gems -RUN apt-get update -qq && \ - apt-get install --no-install-recommends -y build-essential git pkg-config - -# Install application gems -COPY Gemfile Gemfile.lock ./ -RUN bundle install && \ - rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \ - bundle exec bootsnap precompile --gemfile - -# Copy application code -COPY . . - -# Precompile bootsnap code for faster boot times -RUN bundle exec bootsnap precompile app/ lib/ - -# Precompiling assets for production without requiring secret RAILS_MASTER_KEY -RUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile - - -# Final stage for app image -FROM base - -# Install packages needed for deployment -RUN apt-get update -qq && \ - apt-get install --no-install-recommends -y curl libsqlite3-0 && \ - rm -rf /var/lib/apt/lists /var/cache/apt/archives - -# Copy built artifacts: gems, application -COPY --from=build /usr/local/bundle /usr/local/bundle -COPY --from=build /rails /rails - -# Run and own only the runtime files as a non-root user for security -RUN useradd rails --create-home --shell /bin/bash && \ - chown -R rails:rails db log storage tmp -USER rails:rails - -# Entrypoint prepares the database. -ENTRYPOINT ["/rails/bin/docker-entrypoint"] - -# Start the server by default, this can be overwritten at runtime -EXPOSE 3000 -CMD ["./bin/rails", "server"] diff --git a/pricing_catalog_rails_app/Gemfile b/pricing_catalog_rails_app/Gemfile deleted file mode 100644 index 124d5f633..000000000 --- a/pricing_catalog_rails_app/Gemfile +++ /dev/null @@ -1,50 +0,0 @@ -source "https://rubygems.org" - -ruby "3.2.0" -gem "rails", "~> 7.1.3" -gem "sqlite3", "~> 1.4" - -# Use the Puma web server [https://github.com/puma/puma] -gem "puma", ">= 5.0" - -# Use JavaScript with ESM import maps [https://github.com/rails/importmap-rails] -gem "importmap-rails" - -# Hotwire's SPA-like page accelerator [https://turbo.hotwired.dev] -gem "turbo-rails" - -# Hotwire's modest JavaScript framework [https://stimulus.hotwired.dev] -gem "stimulus-rails" - -# Use Redis adapter to run Action Cable in production -gem "redis", ">= 4.0.1" - -# Windows does not include zoneinfo files, so bundle the tzinfo-data gem -gem "tzinfo-data", platforms: %i[ windows jruby ] - -# Reduces boot times through caching; required in config/boot.rb -gem "bootsnap", require: false - -group :development, :test do - # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem - gem "debug", platforms: %i[ mri windows ] -end - -group :development do - # Use console on exceptions pages [https://github.com/rails/web-console] - gem "web-console" - - # Add speed badges [https://github.com/MiniProfiler/rack-mini-profiler] - # gem "rack-mini-profiler" - - # Speed up commands on slow machines / big apps [https://github.com/rails/spring] - # gem "spring" -end - -group :test do - # Use system testing [https://guides.rubyonrails.org/testing.html#system-testing] - gem "capybara" - gem "selenium-webdriver" -end -gem "rails_event_store", "~> 2.14.0" -gem "infra", path: "../infra" \ No newline at end of file diff --git a/pricing_catalog_rails_app/Gemfile.lock b/pricing_catalog_rails_app/Gemfile.lock deleted file mode 100644 index 0ddc0d01e..000000000 --- a/pricing_catalog_rails_app/Gemfile.lock +++ /dev/null @@ -1,337 +0,0 @@ -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://rubygems.org/ - specs: - actioncable (7.1.3) - actionpack (= 7.1.3) - activesupport (= 7.1.3) - nio4r (~> 2.0) - websocket-driver (>= 0.6.1) - zeitwerk (~> 2.6) - actionmailbox (7.1.3) - actionpack (= 7.1.3) - activejob (= 7.1.3) - activerecord (= 7.1.3) - activestorage (= 7.1.3) - activesupport (= 7.1.3) - mail (>= 2.7.1) - net-imap - net-pop - net-smtp - actionmailer (7.1.3) - actionpack (= 7.1.3) - actionview (= 7.1.3) - activejob (= 7.1.3) - activesupport (= 7.1.3) - mail (~> 2.5, >= 2.5.4) - net-imap - net-pop - net-smtp - rails-dom-testing (~> 2.2) - actionpack (7.1.3) - actionview (= 7.1.3) - activesupport (= 7.1.3) - nokogiri (>= 1.8.5) - racc - rack (>= 2.2.4) - rack-session (>= 1.0.1) - rack-test (>= 0.6.3) - rails-dom-testing (~> 2.2) - rails-html-sanitizer (~> 1.6) - actiontext (7.1.3) - actionpack (= 7.1.3) - activerecord (= 7.1.3) - activestorage (= 7.1.3) - activesupport (= 7.1.3) - globalid (>= 0.6.0) - nokogiri (>= 1.8.5) - actionview (7.1.3) - activesupport (= 7.1.3) - builder (~> 3.1) - erubi (~> 1.11) - rails-dom-testing (~> 2.2) - rails-html-sanitizer (~> 1.6) - activejob (7.1.3) - activesupport (= 7.1.3) - globalid (>= 0.3.6) - activemodel (7.1.3) - activesupport (= 7.1.3) - activerecord (7.1.3) - activemodel (= 7.1.3) - activesupport (= 7.1.3) - timeout (>= 0.4.0) - activestorage (7.1.3) - actionpack (= 7.1.3) - activejob (= 7.1.3) - activerecord (= 7.1.3) - activesupport (= 7.1.3) - marcel (~> 1.0) - activesupport (7.1.3) - 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) - addressable (2.8.6) - public_suffix (>= 2.0.2, < 6.0) - aggregate_root (2.14.0) - base64 - ruby_event_store (= 2.14.0) - arkency-command_bus (0.4.1) - concurrent-ruby - base64 (0.2.0) - bigdecimal (3.1.6) - bindex (0.8.1) - bootsnap (1.17.1) - msgpack (~> 1.2) - builder (3.2.4) - capybara (3.40.0) - addressable - matrix - mini_mime (>= 0.1.3) - nokogiri (~> 1.11) - rack (>= 1.6.0) - rack-test (>= 0.6.3) - regexp_parser (>= 1.5, < 3.0) - xpath (~> 3.2) - concurrent-ruby (1.2.3) - connection_pool (2.4.1) - crass (1.0.6) - date (3.3.4) - debug (1.9.1) - irb (~> 1.10) - reline (>= 0.3.8) - drb (2.2.0) - ruby2_keywords - 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) - erubi (1.12.0) - globalid (1.2.1) - activesupport (>= 6.1) - i18n (1.14.1) - concurrent-ruby (~> 1.0) - ice_nine (0.11.2) - importmap-rails (2.0.1) - actionpack (>= 6.0.0) - activesupport (>= 6.0.0) - railties (>= 6.0.0) - io-console (0.7.2) - irb (1.11.1) - rdoc - reline (>= 0.4.2) - loofah (2.22.0) - crass (~> 1.0.2) - nokogiri (>= 1.12.0) - mail (2.8.1) - mini_mime (>= 0.1.1) - net-imap - net-pop - net-smtp - marcel (1.0.2) - matrix (0.4.2) - mini_mime (1.1.5) - minitest (5.21.2) - msgpack (1.7.2) - mutex_m (0.2.0) - net-imap (0.4.9.1) - date - net-protocol - net-pop (0.1.2) - net-protocol - net-protocol (0.2.2) - timeout - net-smtp (0.4.0.1) - net-protocol - nio4r (2.7.0) - nokogiri (1.16.0-aarch64-linux) - racc (~> 1.4) - nokogiri (1.16.0-arm-linux) - racc (~> 1.4) - nokogiri (1.16.0-arm64-darwin) - racc (~> 1.4) - nokogiri (1.16.0-x86-linux) - racc (~> 1.4) - nokogiri (1.16.0-x86_64-darwin) - racc (~> 1.4) - nokogiri (1.16.0-x86_64-linux) - racc (~> 1.4) - psych (5.1.2) - stringio - public_suffix (5.0.4) - puma (6.4.2) - nio4r (~> 2.0) - racc (1.7.3) - rack (3.0.8) - rack-session (2.0.0) - rack (>= 3.0.0) - rack-test (2.1.0) - rack (>= 1.3) - rackup (2.1.0) - rack (>= 3) - webrick (~> 1.8) - rails (7.1.3) - actioncable (= 7.1.3) - actionmailbox (= 7.1.3) - actionmailer (= 7.1.3) - actionpack (= 7.1.3) - actiontext (= 7.1.3) - actionview (= 7.1.3) - activejob (= 7.1.3) - activemodel (= 7.1.3) - activerecord (= 7.1.3) - activestorage (= 7.1.3) - activesupport (= 7.1.3) - bundler (>= 1.15.0) - railties (= 7.1.3) - rails-dom-testing (2.2.0) - activesupport (>= 5.0.0) - minitest - nokogiri (>= 1.6) - rails-html-sanitizer (1.6.0) - loofah (~> 2.21) - nokogiri (~> 1.14) - rails_event_store (2.14.0) - activejob (>= 6.0) - activemodel (>= 6.0) - activesupport (>= 6.0) - aggregate_root (= 2.14.0) - arkency-command_bus (>= 0.4) - rails_event_store_active_record (= 2.14.0) - ruby_event_store (= 2.14.0) - ruby_event_store-browser (= 2.14.0) - rails_event_store_active_record (2.14.0) - ruby_event_store-active_record (= 2.14.0) - railties (7.1.3) - actionpack (= 7.1.3) - activesupport (= 7.1.3) - irb - rackup (>= 1.0.0) - rake (>= 12.2) - thor (~> 1.0, >= 1.2.2) - zeitwerk (~> 2.6) - rake (13.1.0) - rdoc (6.6.2) - psych (>= 4.0.0) - redis (5.0.8) - redis-client (>= 0.17.0) - redis-client (0.19.1) - connection_pool - regexp_parser (2.9.0) - reline (0.4.2) - io-console (~> 0.5) - rexml (3.2.6) - ruby2_keywords (0.0.5) - ruby_event_store (2.14.0) - concurrent-ruby (~> 1.0, >= 1.1.6) - ruby_event_store-active_record (2.14.0) - activerecord (>= 6.0) - ruby_event_store (= 2.14.0) - ruby_event_store-browser (2.14.0) - rack - ruby_event_store (= 2.14.0) - ruby_event_store-transformations (0.1.0) - activesupport (>= 5.0) - ruby_event_store (>= 2.0.0, < 3.0.0) - rubyzip (2.3.2) - selenium-webdriver (4.17.0) - base64 (~> 0.2) - rexml (~> 3.2, >= 3.2.5) - rubyzip (>= 1.2.2, < 3.0) - websocket (~> 1.0) - sidekiq (7.2.1) - concurrent-ruby (< 2) - connection_pool (>= 2.3.0) - rack (>= 2.2.4) - redis-client (>= 0.19.0) - sqlite3 (1.7.1-aarch64-linux) - sqlite3 (1.7.1-arm-linux) - sqlite3 (1.7.1-arm64-darwin) - sqlite3 (1.7.1-x86-linux) - sqlite3 (1.7.1-x86_64-darwin) - sqlite3 (1.7.1-x86_64-linux) - stimulus-rails (1.3.3) - railties (>= 6.0.0) - stringio (3.1.0) - thor (1.3.0) - timeout (0.4.1) - turbo-rails (1.5.0) - actionpack (>= 6.0.0) - activejob (>= 6.0.0) - railties (>= 6.0.0) - tzinfo (2.0.6) - concurrent-ruby (~> 1.0) - web-console (4.2.1) - actionview (>= 6.0.0) - activemodel (>= 6.0.0) - bindex (>= 0.4.0) - railties (>= 6.0.0) - webrick (1.8.1) - websocket (1.2.10) - websocket-driver (0.7.6) - websocket-extensions (>= 0.1.0) - websocket-extensions (0.1.5) - xpath (3.2.0) - nokogiri (~> 1.8) - zeitwerk (2.6.12) - -PLATFORMS - aarch64-linux - arm-linux - arm64-darwin - x86-linux - x86_64-darwin - x86_64-linux - -DEPENDENCIES - bootsnap - capybara - debug - importmap-rails - infra! - puma (>= 5.0) - rails (~> 7.1.3) - rails_event_store (~> 2.14.0) - redis (>= 4.0.1) - selenium-webdriver - sqlite3 (~> 1.4) - stimulus-rails - turbo-rails - tzinfo-data - web-console - -BUNDLED WITH - 2.5.9 diff --git a/pricing_catalog_rails_app/README.md b/pricing_catalog_rails_app/README.md deleted file mode 100644 index 7db80e4ca..000000000 --- a/pricing_catalog_rails_app/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# README - -This README would normally document whatever steps are necessary to get the -application up and running. - -Things you may want to cover: - -* Ruby version - -* System dependencies - -* Configuration - -* Database creation - -* Database initialization - -* How to run the test suite - -* Services (job queues, cache servers, search engines, etc.) - -* Deployment instructions - -* ... diff --git a/pricing_catalog_rails_app/Rakefile b/pricing_catalog_rails_app/Rakefile deleted file mode 100644 index 9a5ea7383..000000000 --- a/pricing_catalog_rails_app/Rakefile +++ /dev/null @@ -1,6 +0,0 @@ -# Add your own tasks in files placed in lib/tasks ending in .rake, -# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. - -require_relative "config/application" - -Rails.application.load_tasks diff --git a/pricing_catalog_rails_app/app/admin/read_models/admin_catalog/admin_catalog.rb b/pricing_catalog_rails_app/app/admin/read_models/admin_catalog/admin_catalog.rb deleted file mode 100644 index d7cc7575f..000000000 --- a/pricing_catalog_rails_app/app/admin/read_models/admin_catalog/admin_catalog.rb +++ /dev/null @@ -1,36 +0,0 @@ -module AdminCatalog - - class Migration - def change - ActiveRecord::Base.connection.create_table :admin_catalog_products do |t| - t.string :product_id - t.string :name - t.decimal :price - - t.timestamps - end - end - end - - class Product < ActiveRecord::Base - self.table_name = 'admin_catalog_products' - end - - class Configuration - def call(event_store) - event_store.subscribe( - -> (event) {Product.create(product_id: event.data[:product_id])}, - to: [ProductCatalog::ProductRegistered]) - event_store.subscribe( - -> (event) {Product.find_by(product_id: event.data[:product_id]).update(name: event.data[:name])}, - to: [ProductCatalog::ProductNamed]) - event_store.subscribe( - -> (event) {Product.find_by(product_id: event.data[:product_id]).update(price: event.data[:price])}, - to: [Pricing::PriceSet]) - end - - private - - end - -end \ No newline at end of file diff --git a/pricing_catalog_rails_app/app/admin/read_models/admin_catalog/index.html.erb b/pricing_catalog_rails_app/app/admin/read_models/admin_catalog/index.html.erb deleted file mode 100644 index 67a6aa093..000000000 --- a/pricing_catalog_rails_app/app/admin/read_models/admin_catalog/index.html.erb +++ /dev/null @@ -1,19 +0,0 @@ -Admin Catalog - -<%= form_for new_product, url: {controller: "admin/catalog", action: "create"} do |f| %> -
- <%= f.label :name %> - <%= f.text_field :name %> -
-- <%= f.label :price %> - <%= f.text_field :price %> -
- <%= f.submit %> -<% end %> - -You may have mistyped the address or the page may have moved.
-If you are the application owner check the logs for more information.
-Maybe you tried to change something you didn't have access to.
-If you are the application owner check the logs for more information.
-If you are the application owner check the logs for more information.
-