diff --git a/rails_application/app/controllers/client/orders_controller.rb b/rails_application/app/controllers/client/orders_controller.rb index 37addc53..ffc59a5b 100644 --- a/rails_application/app/controllers/client/orders_controller.rb +++ b/rails_application/app/controllers/client/orders_controller.rb @@ -12,7 +12,7 @@ def new end def create - Orders::SubmitService.new(order_id: params[:order_id], customer_id: cookies[:client_id]).call + Client::Orders::SubmitService.new(order_id: params[:order_id], customer_id: cookies[:client_id]).call rescue Orders::OrderHasUnavailableProducts => e unavailable_products = e.unavailable_products.join(", ") redirect_to edit_client_order_path(params[:order_id]), alert: "Order can not be submitted! #{unavailable_products} not available in requested quantity!" diff --git a/rails_application/app/services/client/orders/submit_service.rb b/rails_application/app/services/client/orders/submit_service.rb new file mode 100644 index 00000000..3def1ce2 --- /dev/null +++ b/rails_application/app/services/client/orders/submit_service.rb @@ -0,0 +1,43 @@ +module Client + module Orders + class OrderHasUnavailableProducts < StandardError + attr_reader :unavailable_products + + def initialize(unavailable_products) + @unavailable_products = unavailable_products + end + end + + class SubmitService < ApplicationService + def initialize(order_id:, customer_id:) + @order_id = order_id + @customer_id = customer_id + end + + def call + unavailable_products = [] + event_store + .within { submit_order } + .subscribe(to: Processes::ReservationProcessFailed) do |event| + unavailable_products = Products::Product.where(id: event.data.fetch(:unavailable_products)).pluck(:name) + end + .call + + if unavailable_products.any? + raise OrderHasUnavailableProducts.new(unavailable_products) + end + end + + private + + attr_reader :order_id, :customer_id + + def submit_order + ActiveRecord::Base.transaction do + command_bus.(Ordering::SubmitOrder.new(order_id: order_id)) + command_bus.(Crm::AssignCustomerToOrder.new(order_id: order_id, customer_id: customer_id)) + end + end + end + end +end diff --git a/rails_application/test/services/client/orders/submit_service_test.rb b/rails_application/test/services/client/orders/submit_service_test.rb new file mode 100644 index 00000000..412351d2 --- /dev/null +++ b/rails_application/test/services/client/orders/submit_service_test.rb @@ -0,0 +1,68 @@ +require "test_helper" + +module Client + module Orders + class SubmitServiceTest < InMemoryTestCase + cover Client::Orders::SubmitService + + def test_successful_order_submission + order_id = SecureRandom.uuid + customer_id = SecureRandom.uuid + product_id = SecureRandom.uuid + + run_command(Crm::RegisterCustomer.new(customer_id: customer_id, name: "John Doe")) + prepare_product(product_id, "Async Remote", 49) + run_command(Ordering::AddItemToBasket.new(order_id: order_id, product_id: product_id)) + + Client::Orders::SubmitService.new(order_id: order_id, customer_id: customer_id).call + + order = ClientOrders::Order.find_by!(order_uid: order_id) + + assert_equal "Submitted", order.state + assert_equal customer_id, order.client_uid + end + + def test_order_submission_with_unavailable_products + order_id = SecureRandom.uuid + customer_id = SecureRandom.uuid + product_id = SecureRandom.uuid + another_product_id = SecureRandom.uuid + + run_command(Crm::RegisterCustomer.new(customer_id: customer_id, name: "John Doe")) + prepare_product(product_id, "Async Remote", 49) + run_command(Inventory::Supply.new(product_id: product_id, quantity: 1)) + run_command(Inventory::Reserve.new(product_id: product_id, quantity: 1)) + run_command(Ordering::AddItemToBasket.new(order_id: order_id, product_id: product_id)) + prepare_product(another_product_id, "Fearless Refactoring", 49) + run_command(Ordering::AddItemToBasket.new(order_id: order_id, product_id: another_product_id)) + + error = assert_raises(OrderHasUnavailableProducts) do + SubmitService.new(order_id: order_id, customer_id: customer_id).call + end + + assert_equal ["Async Remote"], error.unavailable_products + end + + private + + def event_store + Rails.configuration.event_store + end + + def prepare_product(product_id, name, price) + run_command( + ProductCatalog::RegisterProduct.new( + product_id: product_id, + ) + ) + run_command( + ProductCatalog::NameProduct.new( + product_id: product_id, + name: name + ) + ) + run_command(Pricing::SetPrice.new(product_id: product_id, price: price)) + end + end + end +end