From 9d919938f38b564161fedbc61743ac7958fc5d24 Mon Sep 17 00:00:00 2001 From: Feruz Oripov Date: Sat, 16 Mar 2024 19:07:08 +0500 Subject: [PATCH 1/3] Group Order && OrderCycle related services and specs --- .rubocop_todo.yml | 12 +- .../admin/order_cycles_controller.rb | 6 +- .../api/v0/order_cycles_controller.rb | 3 +- app/controllers/api/v0/orders_controller.rb | 2 +- .../api/v0/shipments_controller.rb | 2 +- app/controllers/checkout_controller.rb | 2 +- .../concerns/checkout_callbacks.rb | 2 +- app/controllers/concerns/order_completion.rb | 2 +- app/controllers/concerns/order_stock_check.rb | 2 +- app/controllers/enterprises_controller.rb | 2 +- .../payment_gateways/stripe_controller.rb | 2 +- .../spree/admin/base_controller.rb | 2 +- .../spree/admin/invoices_controller.rb | 2 +- .../orders/customer_details_controller.rb | 2 +- .../spree/admin/orders_controller.rb | 4 +- .../spree/admin/payments_controller.rb | 2 +- app/controllers/spree/orders_controller.rb | 4 +- app/helpers/checkout_helper.rb | 2 +- app/helpers/enterprises_helper.rb | 4 +- app/helpers/order_helper.rb | 4 +- app/jobs/bulk_invoice_job.rb | 2 +- app/jobs/order_cycle_opened_job.rb | 2 +- app/mailers/spree/order_mailer.rb | 3 +- app/models/concerns/order_validations.rb | 2 +- app/models/order_cycle.rb | 2 +- app/models/proxy_order.rb | 2 +- app/models/spree/order.rb | 4 +- app/models/spree/payment/processing.rb | 2 +- app/reflexes/admin/orders_reflex.rb | 4 +- app/services/cap_quantity.rb | 3 +- app/services/cart_service.rb | 2 +- .../checkout/post_checkout_actions.rb | 2 +- app/services/create_order_cycle.rb | 67 ----- app/services/customer_order_cancellation.rb | 17 -- app/services/order_adjustments_fetcher.rb | 79 ------ .../order_available_payment_methods.rb | 43 ---- .../order_available_shipping_methods.rb | 56 ----- app/services/order_capture_service.rb | 22 -- app/services/order_cart_reset.rb | 56 ----- app/services/order_checkout_restart.rb | 34 --- app/services/order_cycle_clone.rb | 43 ---- .../order_cycle_distributed_products.rb | 83 ------- .../order_cycle_distributed_variants.rb | 22 -- app/services/order_cycle_form.rb | 230 ----------------- app/services/order_cycle_warning.rb | 37 --- app/services/order_cycle_webhook_service.rb | 21 -- app/services/order_cycles/clone_service.rb | 45 ++++ .../distributed_products_service.rb | 86 +++++++ .../distributed_variants_service.rb | 24 ++ app/services/order_cycles/form_service.rb | 233 ++++++++++++++++++ app/services/order_cycles/warning_service.rb | 39 +++ app/services/order_cycles/webhook_service.rb | 24 ++ app/services/order_data_masker.rb | 35 --- app/services/order_factory.rb | 97 -------- app/services/order_fees_handler.rb | 68 ----- app/services/order_invoice_comparator.rb | 86 ------- app/services/order_invoice_generator.rb | 38 --- app/services/order_payment_finder.rb | 28 --- app/services/order_syncer.rb | 138 ----------- app/services/order_tax_adjustments_fetcher.rb | 20 -- app/services/order_update_issues.rb | 21 -- app/services/order_workflow.rb | 95 ------- .../available_payment_methods_service.rb | 45 ++++ .../available_shipping_methods_service.rb | 58 +++++ app/services/orders/bulk_cancel_service.rb | 26 ++ app/services/orders/capture_service.rb | 24 ++ app/services/orders/cart_reset_service.rb | 59 +++++ .../orders/checkout_restart_service.rb | 37 +++ .../orders/compare_invoice_service.rb | 88 +++++++ .../orders/customer_cancellation_service.rb | 19 ++ app/services/orders/factory_service.rb | 99 ++++++++ .../orders/fetch_adjustments_service.rb | 81 ++++++ .../orders/fetch_tax_adjustments_service.rb | 22 ++ app/services/orders/find_payment_service.rb | 30 +++ .../orders/generate_invoice_service.rb | 40 +++ app/services/orders/handle_fees_service.rb | 70 ++++++ app/services/orders/mask_data_service.rb | 37 +++ app/services/orders/sync_service.rb | 141 +++++++++++ app/services/orders/update_issues_service.rb | 23 ++ app/services/orders/workflow_service.rb | 98 ++++++++ app/services/orders_bulk_cancel_service.rb | 24 -- app/services/place_proxy_order.rb | 2 +- app/services/process_payment_intent.rb | 2 +- app/services/products_renderer.rb | 2 +- app/services/shop/order_cycles_list.rb | 4 +- .../order/stripe_sca_payment_authorize.rb | 2 +- .../order_management/subscriptions/form.rb | 2 +- .../subscriptions/payment_setup.rb | 2 +- .../subscriptions/proxy_order_syncer.rb | 2 +- .../subscriptions/stripe_payment_setup.rb | 2 +- lib/reporting/line_items.rb | 2 +- .../reports/orders_and_distributors/base.rb | 2 +- lib/reporting/reports/sales_tax/tax_rates.rb | 2 +- lib/tasks/sample_data/order_factory.rb | 2 +- .../admin/bulk_line_items_controller_spec.rb | 2 +- .../admin/order_cycles_controller_spec.rb | 18 +- .../admin/proxy_orders_controller_spec.rb | 2 +- spec/controllers/checkout_controller_spec.rb | 6 +- .../stripe_controller_spec.rb | 8 +- spec/factories/order_factory.rb | 2 +- spec/jobs/order_cycle_opened_job_spec.rb | 12 +- spec/jobs/subscription_confirm_job_spec.rb | 4 +- ...e_fees_with_tax_report_by_producer_spec.rb | 2 +- .../reports/sales_tax_totals_by_order_spec.rb | 12 +- spec/mailers/order_mailer_spec.rb | 4 +- spec/models/invoice/data_presenter_spec.rb | 6 +- spec/models/proxy_order_spec.rb | 10 +- spec/models/spree/order_spec.rb | 4 +- .../requests/checkout/failed_checkout_spec.rb | 2 +- spec/requests/checkout/routes_spec.rb | 2 +- spec/requests/checkout/stripe_sca_spec.rb | 4 +- spec/requests/voucher_adjustments_spec.rb | 2 +- spec/services/cart_service_spec.rb | 6 +- .../checkout/post_checkout_actions_spec.rb | 6 +- .../services/checkout/stripe_redirect_spec.rb | 2 +- .../clone_service_spec.rb} | 4 +- .../distributed_products_service_spec.rb} | 2 +- .../distributed_variants_service_spec.rb} | 6 +- .../form_service_spec.rb} | 34 +-- .../warning_service_spec.rb} | 4 +- .../webhook_service_spec.rb} | 28 ++- ...available_payment_methods_service_spec.rb} | 26 +- ...vailable_shipping_methods_service_spec.rb} | 26 +- .../cart_reset_service_spec.rb} | 8 +- .../checkout_restart_service_spec.rb} | 12 +- .../compare_invoice_service_spec.rb} | 6 +- .../customer_cancellation_service_spec.rb} | 6 +- .../factory_service_spec.rb} | 6 +- .../find_payment_service_spec.rb} | 4 +- .../generate_invoice_service_spec.rb} | 4 +- .../handle_fees_service_spec.rb} | 4 +- .../mask_data_service_spec.rb} | 2 +- .../order_tax_adjustments_fetcher_spec.rb | 4 +- .../sync_service_spec.rb} | 26 +- .../workflow_service_spec.rb} | 2 +- spec/services/place_proxy_order_spec.rb | 4 +- spec/system/admin/invoice_print_spec.rb | 2 +- spec/system/admin/payments_stripe_spec.rb | 9 +- ...mmary_fee_with_tax_report_by_order_spec.rb | 4 +- .../sales_tax_totals_by_order_spec.rb | 8 +- 140 files changed, 1700 insertions(+), 1686 deletions(-) delete mode 100644 app/services/create_order_cycle.rb delete mode 100644 app/services/customer_order_cancellation.rb delete mode 100644 app/services/order_adjustments_fetcher.rb delete mode 100644 app/services/order_available_payment_methods.rb delete mode 100644 app/services/order_available_shipping_methods.rb delete mode 100644 app/services/order_capture_service.rb delete mode 100644 app/services/order_cart_reset.rb delete mode 100644 app/services/order_checkout_restart.rb delete mode 100644 app/services/order_cycle_clone.rb delete mode 100644 app/services/order_cycle_distributed_products.rb delete mode 100644 app/services/order_cycle_distributed_variants.rb delete mode 100644 app/services/order_cycle_form.rb delete mode 100644 app/services/order_cycle_warning.rb delete mode 100644 app/services/order_cycle_webhook_service.rb create mode 100644 app/services/order_cycles/clone_service.rb create mode 100644 app/services/order_cycles/distributed_products_service.rb create mode 100644 app/services/order_cycles/distributed_variants_service.rb create mode 100644 app/services/order_cycles/form_service.rb create mode 100644 app/services/order_cycles/warning_service.rb create mode 100644 app/services/order_cycles/webhook_service.rb delete mode 100644 app/services/order_data_masker.rb delete mode 100644 app/services/order_factory.rb delete mode 100644 app/services/order_fees_handler.rb delete mode 100644 app/services/order_invoice_comparator.rb delete mode 100644 app/services/order_invoice_generator.rb delete mode 100644 app/services/order_payment_finder.rb delete mode 100644 app/services/order_syncer.rb delete mode 100644 app/services/order_tax_adjustments_fetcher.rb delete mode 100644 app/services/order_update_issues.rb delete mode 100644 app/services/order_workflow.rb create mode 100644 app/services/orders/available_payment_methods_service.rb create mode 100644 app/services/orders/available_shipping_methods_service.rb create mode 100644 app/services/orders/bulk_cancel_service.rb create mode 100644 app/services/orders/capture_service.rb create mode 100644 app/services/orders/cart_reset_service.rb create mode 100644 app/services/orders/checkout_restart_service.rb create mode 100644 app/services/orders/compare_invoice_service.rb create mode 100644 app/services/orders/customer_cancellation_service.rb create mode 100644 app/services/orders/factory_service.rb create mode 100644 app/services/orders/fetch_adjustments_service.rb create mode 100644 app/services/orders/fetch_tax_adjustments_service.rb create mode 100644 app/services/orders/find_payment_service.rb create mode 100644 app/services/orders/generate_invoice_service.rb create mode 100644 app/services/orders/handle_fees_service.rb create mode 100644 app/services/orders/mask_data_service.rb create mode 100644 app/services/orders/sync_service.rb create mode 100644 app/services/orders/update_issues_service.rb create mode 100644 app/services/orders/workflow_service.rb delete mode 100644 app/services/orders_bulk_cancel_service.rb rename spec/services/{order_cycle_clone_spec.rb => order_cycles/clone_service_spec.rb} (97%) rename spec/services/{order_cycle_distributed_products_spec.rb => order_cycles/distributed_products_service_spec.rb} (98%) rename spec/services/{order_cycle_distributed_variants_spec.rb => order_cycles/distributed_variants_service_spec.rb} (86%) rename spec/services/{order_cycle_form_spec.rb => order_cycles/form_service_spec.rb} (95%) rename spec/services/{order_cycle_warning_spec.rb => order_cycles/warning_service_spec.rb} (91%) rename spec/services/{order_cycle_webhook_service_spec.rb => order_cycles/webhook_service_spec.rb} (81%) rename spec/services/{order_available_payment_methods_spec.rb => orders/available_payment_methods_service_spec.rb} (89%) rename spec/services/{order_available_shipping_methods_spec.rb => orders/available_shipping_methods_service_spec.rb} (90%) rename spec/services/{order_cart_reset_spec.rb => orders/cart_reset_service_spec.rb} (81%) rename spec/services/{order_checkout_restart_spec.rb => orders/checkout_restart_service_spec.rb} (86%) rename spec/services/{order_invoice_comparator_spec.rb => orders/compare_invoice_service_spec.rb} (98%) rename spec/services/{customer_order_cancellation_spec.rb => orders/customer_cancellation_service_spec.rb} (82%) rename spec/services/{order_factory_spec.rb => orders/factory_service_spec.rb} (97%) rename spec/services/{order_payment_finder_spec.rb => orders/find_payment_service_spec.rb} (93%) rename spec/services/{order_invoice_generator_spec.rb => orders/generate_invoice_service_spec.rb} (95%) rename spec/services/{order_fees_handler_spec.rb => orders/handle_fees_service_spec.rb} (95%) rename spec/services/{order_data_masker_spec.rb => orders/mask_data_service_spec.rb} (98%) rename spec/services/{ => orders}/order_tax_adjustments_fetcher_spec.rb (97%) rename spec/services/{order_syncer_spec.rb => orders/sync_service_spec.rb} (97%) rename spec/services/{order_workflow_spec.rb => orders/workflow_service_spec.rb} (98%) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 250bf7c60f..759d01801c 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -141,7 +141,7 @@ Metrics/AbcSize: - 'lib/open_food_network/order_cycle_permissions.rb' - 'lib/spree/core/controller_helpers/order.rb' - 'lib/tasks/enterprises.rake' - - 'spec/services/order_checkout_restart_spec.rb' + - 'spec/services/orders/checkout_restart_service_spec.rb' # Offense count: 9 # Configuration parameters: CountComments, Max, CountAsOne, AllowedMethods, AllowedPatterns, inherit_mode. @@ -200,8 +200,8 @@ Metrics/ClassLength: - 'app/serializers/api/cached_enterprise_serializer.rb' - 'app/serializers/api/enterprise_shopfront_serializer.rb' - 'app/services/cart_service.rb' - - 'app/services/order_cycle_form.rb' - - 'app/services/order_syncer.rb' + - 'app/services/orders/sync_service.rb' + - 'app/services/order_cycles/form_service.rb' - 'engines/order_management/app/services/order_management/order/updater.rb' - 'lib/open_food_network/enterprise_fee_calculator.rb' - 'lib/open_food_network/order_cycle_form_applicator.rb' @@ -397,7 +397,7 @@ Rails/FindEach: Exclude: - 'app/controllers/admin/order_cycles_controller.rb' - 'app/jobs/subscription_confirm_job.rb' - - 'app/services/orders_bulk_cancel_service.rb' + - 'app/services/orders/bulk_cancel_service.rb' - 'app/services/products_renderer.rb' - 'lib/tasks/data.rake' - 'lib/tasks/subscriptions/debug.rake' @@ -618,8 +618,8 @@ Rails/TimeZone: Exclude: - 'app/models/spree/gateway/pay_pal_express.rb' - 'spec/controllers/spree/credit_cards_controller_spec.rb' - - 'spec/services/customer_order_cancellation_spec.rb' - - 'spec/services/order_cycle_webhook_service_spec.rb' + - 'spec/services/orders/customer_cancellation_service_spec.rb' + - 'spec/services/order_cycles/webhook_service_spec.rb' # Offense count: 1 # Configuration parameters: TransactionMethods. diff --git a/app/controllers/admin/order_cycles_controller.rb b/app/controllers/admin/order_cycles_controller.rb index 2e1258eaa0..c06695d10b 100644 --- a/app/controllers/admin/order_cycles_controller.rb +++ b/app/controllers/admin/order_cycles_controller.rb @@ -45,7 +45,8 @@ module Admin end def create - @order_cycle_form = OrderCycleForm.new(@order_cycle, order_cycle_params, spree_current_user) + @order_cycle_form = OrderCycles::FormService.new(@order_cycle, order_cycle_params, + spree_current_user) if @order_cycle_form.save flash[:success] = t('.success') @@ -61,7 +62,8 @@ module Admin end def update - @order_cycle_form = OrderCycleForm.new(@order_cycle, order_cycle_params, spree_current_user) + @order_cycle_form = OrderCycles::FormService.new(@order_cycle, order_cycle_params, + spree_current_user) if @order_cycle_form.save update_nil_subscription_line_items_price_estimate(@order_cycle) diff --git a/app/controllers/api/v0/order_cycles_controller.rb b/app/controllers/api/v0/order_cycles_controller.rb index 289b0260e4..2c3c0b2318 100644 --- a/app/controllers/api/v0/order_cycles_controller.rb +++ b/app/controllers/api/v0/order_cycles_controller.rb @@ -101,7 +101,8 @@ module Api end def distributed_products - OrderCycleDistributedProducts.new(distributor, order_cycle, customer).products_relation + OrderCycles::DistributedProductsService.new(distributor, order_cycle, + customer).products_relation end end end diff --git a/app/controllers/api/v0/orders_controller.rb b/app/controllers/api/v0/orders_controller.rb index 8570ac3db5..2ffb4304b3 100644 --- a/app/controllers/api/v0/orders_controller.rb +++ b/app/controllers/api/v0/orders_controller.rb @@ -47,7 +47,7 @@ module Api def capture authorize! :admin, order - payment_capture = OrderCaptureService.new(order) + payment_capture = Orders::CaptureService.new(order) if payment_capture.call render json: order.reload, serializer: Api::Admin::OrderSerializer, status: :ok diff --git a/app/controllers/api/v0/shipments_controller.rb b/app/controllers/api/v0/shipments_controller.rb index d742f2c29e..82a042c8f4 100644 --- a/app/controllers/api/v0/shipments_controller.rb +++ b/app/controllers/api/v0/shipments_controller.rb @@ -21,7 +21,7 @@ module Api @shipment.refresh_rates @shipment.save! - OrderWorkflow.new(@order).advance_to_payment if @order.line_items.any? + Orders::WorkflowService.new(@order).advance_to_payment if @order.line_items.any? @order.recreate_all_fees! diff --git a/app/controllers/checkout_controller.rb b/app/controllers/checkout_controller.rb index 3c0254e0e4..efd8e80eeb 100644 --- a/app/controllers/checkout_controller.rb +++ b/app/controllers/checkout_controller.rb @@ -128,7 +128,7 @@ class CheckoutController < BaseController def advance_order_state return if @order.complete? - OrderWorkflow.new(@order).advance_checkout(raw_params.slice(:shipping_method_id)) + Orders::WorkflowService.new(@order).advance_checkout(raw_params.slice(:shipping_method_id)) end def order_params diff --git a/app/controllers/concerns/checkout_callbacks.rb b/app/controllers/concerns/checkout_callbacks.rb index 7da81a592b..c7eb90ebde 100644 --- a/app/controllers/concerns/checkout_callbacks.rb +++ b/app/controllers/concerns/checkout_callbacks.rb @@ -65,7 +65,7 @@ module CheckoutCallbacks def valid_order_line_items? @order.insufficient_stock_lines.empty? && - OrderCycleDistributedVariants.new(@order.order_cycle, @order.distributor). + OrderCycles::DistributedVariantsService.new(@order.order_cycle, @order.distributor). distributes_order_variants?(@order) end diff --git a/app/controllers/concerns/order_completion.rb b/app/controllers/concerns/order_completion.rb index 5e3d2c198c..58bf7a03b9 100644 --- a/app/controllers/concerns/order_completion.rb +++ b/app/controllers/concerns/order_completion.rb @@ -64,7 +64,7 @@ module OrderCompletion return redirect_to order_failed_route(step: 'payment') end - if OrderWorkflow.new(@order).next && @order.complete? + if Orders::WorkflowService.new(@order).next && @order.complete? processing_succeeded redirect_to order_completion_route else diff --git a/app/controllers/concerns/order_stock_check.rb b/app/controllers/concerns/order_stock_check.rb index c979948686..13ff145ae8 100644 --- a/app/controllers/concerns/order_stock_check.rb +++ b/app/controllers/concerns/order_stock_check.rb @@ -6,7 +6,7 @@ module OrderStockCheck def valid_order_line_items? @order.insufficient_stock_lines.empty? && - OrderCycleDistributedVariants.new(@order.order_cycle, @order.distributor). + OrderCycles::DistributedVariantsService.new(@order.order_cycle, @order.distributor). distributes_order_variants?(@order) end diff --git a/app/controllers/enterprises_controller.rb b/app/controllers/enterprises_controller.rb index 1043fdb4c6..bc16d12f18 100644 --- a/app/controllers/enterprises_controller.rb +++ b/app/controllers/enterprises_controller.rb @@ -70,7 +70,7 @@ class EnterprisesController < BaseController order = current_order(true) # reset_distributor must be called before any call to current_customer or current_distributor - order_cart_reset = OrderCartReset.new(order, params[:id]) + order_cart_reset = Orders::CartResetService.new(order, params[:id]) order_cart_reset.reset_distributor order_cart_reset.reset_other!(spree_current_user, current_customer) rescue ActiveRecord::RecordNotFound diff --git a/app/controllers/payment_gateways/stripe_controller.rb b/app/controllers/payment_gateways/stripe_controller.rb index cabf14b4bf..8364e8e376 100644 --- a/app/controllers/payment_gateways/stripe_controller.rb +++ b/app/controllers/payment_gateways/stripe_controller.rb @@ -79,7 +79,7 @@ module PaymentGateways end def last_payment - @last_payment ||= OrderPaymentFinder.new(@order).last_payment + @last_payment ||= Orders::FindPaymentService.new(@order).last_payment end def cancel_incomplete_payments diff --git a/app/controllers/spree/admin/base_controller.rb b/app/controllers/spree/admin/base_controller.rb index c03756814e..f926612ef0 100644 --- a/app/controllers/spree/admin/base_controller.rb +++ b/app/controllers/spree/admin/base_controller.rb @@ -26,7 +26,7 @@ module Spree def warn_invalid_order_cycles return if flash[:notice].present? - warning = OrderCycleWarning.new(spree_current_user).call + warning = OrderCycles::WarningService.new(spree_current_user).call flash[:notice] = warning if warning.present? end diff --git a/app/controllers/spree/admin/invoices_controller.rb b/app/controllers/spree/admin/invoices_controller.rb index 81f79a299e..8fa92475a3 100644 --- a/app/controllers/spree/admin/invoices_controller.rb +++ b/app/controllers/spree/admin/invoices_controller.rb @@ -20,7 +20,7 @@ module Spree def generate @order = Order.find_by(number: params[:order_id]) authorize! :invoice, @order - OrderInvoiceGenerator.new(@order).generate_or_update_latest_invoice + ::Orders::GenerateInvoiceService.new(@order).generate_or_update_latest_invoice redirect_back(fallback_location: spree.admin_dashboard_path) end diff --git a/app/controllers/spree/admin/orders/customer_details_controller.rb b/app/controllers/spree/admin/orders/customer_details_controller.rb index 7f93651e48..1f67f790df 100644 --- a/app/controllers/spree/admin/orders/customer_details_controller.rb +++ b/app/controllers/spree/admin/orders/customer_details_controller.rb @@ -24,7 +24,7 @@ module Spree end refresh_shipment_rates - OrderWorkflow.new(@order).advance_to_payment + ::Orders::WorkflowService.new(@order).advance_to_payment flash[:success] = Spree.t('customer_details_updated') redirect_to spree.admin_order_customer_path(@order) diff --git a/app/controllers/spree/admin/orders_controller.rb b/app/controllers/spree/admin/orders_controller.rb index 4e2b729dd6..a73adf58c4 100644 --- a/app/controllers/spree/admin/orders_controller.rb +++ b/app/controllers/spree/admin/orders_controller.rb @@ -50,7 +50,7 @@ module Spree return redirect_to spree.edit_admin_order_path(@order) end - OrderWorkflow.new(@order).advance_to_payment + ::Orders::WorkflowService.new(@order).advance_to_payment if @order.complete? redirect_to spree.edit_admin_order_path(@order) @@ -104,7 +104,7 @@ module Spree @order = if params[:invoice_id].present? @order.invoices.find(params[:invoice_id]).presenter else - OrderInvoiceGenerator.new(@order).generate_or_update_latest_invoice + ::Orders::GenerateInvoiceService.new(@order).generate_or_update_latest_invoice @order.invoices.first.presenter end end diff --git a/app/controllers/spree/admin/payments_controller.rb b/app/controllers/spree/admin/payments_controller.rb index 041dacf8d6..0afaa5227c 100644 --- a/app/controllers/spree/admin/payments_controller.rb +++ b/app/controllers/spree/admin/payments_controller.rb @@ -33,7 +33,7 @@ module Spree return end - OrderWorkflow.new(@order).complete! unless @order.completed? + ::Orders::WorkflowService.new(@order).complete! unless @order.completed? authorize_stripe_sca_payment @payment.process_offline! diff --git a/app/controllers/spree/orders_controller.rb b/app/controllers/spree/orders_controller.rb index 113f827628..f1055785c6 100644 --- a/app/controllers/spree/orders_controller.rb +++ b/app/controllers/spree/orders_controller.rb @@ -42,7 +42,7 @@ module Spree # Patching to redirect to shop if order is empty def edit @insufficient_stock_lines = @order.insufficient_stock_lines - @unavailable_order_variants = OrderCycleDistributedVariants. + @unavailable_order_variants = OrderCycles::DistributedVariantsService. new(current_order_cycle, current_distributor).unavailable_order_variants(@order) if @order.line_items.empty? @@ -102,7 +102,7 @@ module Spree @order = Spree::Order.find_by!(number: params[:id]) authorize! :cancel, @order - if CustomerOrderCancellation.new(@order).call + if Orders::CustomerCancellationService.new(@order).call flash[:success] = I18n.t(:orders_your_order_has_been_cancelled) else flash[:error] = I18n.t(:orders_could_not_cancel) diff --git a/app/helpers/checkout_helper.rb b/app/helpers/checkout_helper.rb index eb96a28dd7..393c606ed7 100644 --- a/app/helpers/checkout_helper.rb +++ b/app/helpers/checkout_helper.rb @@ -59,7 +59,7 @@ module CheckoutHelper end def display_checkout_taxes_hash(order) - totals = OrderTaxAdjustmentsFetcher.new(order).totals + totals = Orders::FetchTaxAdjustmentsService.new(order).totals totals.map do |tax_rate, tax_amount| { diff --git a/app/helpers/enterprises_helper.rb b/app/helpers/enterprises_helper.rb index efb09655dd..4a7c6ae817 100644 --- a/app/helpers/enterprises_helper.rb +++ b/app/helpers/enterprises_helper.rb @@ -12,11 +12,11 @@ module EnterprisesHelper end def available_shipping_methods - OrderAvailableShippingMethods.new(current_order, current_customer).to_a + Orders::AvailableShippingMethodsService.new(current_order, current_customer).to_a end def available_payment_methods - OrderAvailablePaymentMethods.new(current_order, current_customer).to_a + Orders::AvailablePaymentMethodsService.new(current_order, current_customer).to_a end def managed_enterprises diff --git a/app/helpers/order_helper.rb b/app/helpers/order_helper.rb index cdafb9f55b..e0d6c65313 100644 --- a/app/helpers/order_helper.rb +++ b/app/helpers/order_helper.rb @@ -2,7 +2,7 @@ module OrderHelper def last_payment_method(order) - OrderPaymentFinder.new(order).last_payment&.payment_method + Orders::FindPaymentService.new(order).last_payment&.payment_method end def outstanding_balance_label(order) @@ -16,6 +16,6 @@ module OrderHelper end def order_comparator(order) - OrderInvoiceComparator.new(order) + Orders::CompareInvoiceService.new(order) end end diff --git a/app/jobs/bulk_invoice_job.rb b/app/jobs/bulk_invoice_job.rb index 3c360005fa..517cba1c22 100644 --- a/app/jobs/bulk_invoice_job.rb +++ b/app/jobs/bulk_invoice_job.rb @@ -33,7 +33,7 @@ class BulkInvoiceJob < ApplicationJob def generate_invoice(order) renderer_data = if OpenFoodNetwork::FeatureToggle.enabled?(:invoices, current_user) - OrderInvoiceGenerator.new(order).generate_or_update_latest_invoice + Orders::GenerateInvoiceService.new(order).generate_or_update_latest_invoice order.invoices.first.presenter else order diff --git a/app/jobs/order_cycle_opened_job.rb b/app/jobs/order_cycle_opened_job.rb index 9d84027fe3..3b4cee16db 100644 --- a/app/jobs/order_cycle_opened_job.rb +++ b/app/jobs/order_cycle_opened_job.rb @@ -5,7 +5,7 @@ class OrderCycleOpenedJob < ApplicationJob def perform ActiveRecord::Base.transaction do recently_opened_order_cycles.find_each do |order_cycle| - OrderCycleWebhookService.create_webhook_job(order_cycle, 'order_cycle.opened') + OrderCycles::WebhookService.create_webhook_job(order_cycle, 'order_cycle.opened') end mark_as_opened(recently_opened_order_cycles) end diff --git a/app/mailers/spree/order_mailer.rb b/app/mailers/spree/order_mailer.rb index e3430c7787..97ffd3f6b1 100644 --- a/app/mailers/spree/order_mailer.rb +++ b/app/mailers/spree/order_mailer.rb @@ -52,7 +52,8 @@ module Spree find_user(options[:current_user_id]) end renderer_data = if OpenFoodNetwork::FeatureToggle.enabled?(:invoices, current_user) - OrderInvoiceGenerator.new(@order).generate_or_update_latest_invoice + ::Orders::GenerateInvoiceService + .new(@order).generate_or_update_latest_invoice @order.invoices.first.presenter else @order diff --git a/app/models/concerns/order_validations.rb b/app/models/concerns/order_validations.rb index 36733f5c35..52aa257b5f 100644 --- a/app/models/concerns/order_validations.rb +++ b/app/models/concerns/order_validations.rb @@ -15,7 +15,7 @@ module OrderValidations # Check that line_items in the current order are available from a newly selected distribution def products_available_from_new_distribution - return if OrderCycleDistributedVariants.new(order_cycle, distributor) + return if OrderCycles::DistributedVariantsService.new(order_cycle, distributor) .distributes_order_variants?(self) errors.add(:base, I18n.t(:spree_order_availability_error)) diff --git a/app/models/order_cycle.rb b/app/models/order_cycle.rb index b6e7d80913..7fa53009eb 100644 --- a/app/models/order_cycle.rb +++ b/app/models/order_cycle.rb @@ -175,7 +175,7 @@ class OrderCycle < ApplicationRecord end def clone! - OrderCycleClone.new(self).create + OrderCycles::CloneService.new(self).create end def variants diff --git a/app/models/proxy_order.rb b/app/models/proxy_order.rb index 449478b44e..2f64fe0a2b 100644 --- a/app/models/proxy_order.rb +++ b/app/models/proxy_order.rb @@ -58,7 +58,7 @@ class ProxyOrder < ApplicationRecord def initialise_order! return order if order.present? - factory = OrderFactory.new(order_attrs, skip_stock_check: true) + factory = Orders::FactoryService.new(order_attrs, skip_stock_check: true) self.order = factory.create save! order diff --git a/app/models/spree/order.rb b/app/models/spree/order.rb index a663b9b9c8..5e56610c07 100644 --- a/app/models/spree/order.rb +++ b/app/models/spree/order.rb @@ -652,7 +652,7 @@ module Spree end def fee_handler - @fee_handler ||= OrderFeesHandler.new(self) + @fee_handler ||= Orders::HandleFeesService.new(self) end def clear_legacy_taxes! @@ -701,7 +701,7 @@ module Spree end def adjustments_fetcher - @adjustments_fetcher ||= OrderAdjustmentsFetcher.new(self) + @adjustments_fetcher ||= Orders::FetchAdjustmentsService.new(self) end def skip_payment_for_subscription? diff --git a/app/models/spree/payment/processing.rb b/app/models/spree/payment/processing.rb index 499a669987..8f9d0e4573 100644 --- a/app/models/spree/payment/processing.rb +++ b/app/models/spree/payment/processing.rb @@ -48,7 +48,7 @@ module Spree end def capture_and_complete_order! - OrderWorkflow.new(order).complete! + Orders::WorkflowService.new(order).complete! capture! end diff --git a/app/reflexes/admin/orders_reflex.rb b/app/reflexes/admin/orders_reflex.rb index fe84ebf7ea..8e5f43eb65 100644 --- a/app/reflexes/admin/orders_reflex.rb +++ b/app/reflexes/admin/orders_reflex.rb @@ -5,7 +5,7 @@ module Admin before_reflex :authorize_order, only: [:capture, :ship] def capture - payment_capture = OrderCaptureService.new(@order) + payment_capture = Orders::CaptureService.new(@order) if payment_capture.call cable_ready.replace(selector: dom_id(@order), @@ -55,7 +55,7 @@ module Admin end def cancel_orders(params) - cancelled_orders = OrdersBulkCancelService.new(params, current_user).call + cancelled_orders = Orders::BulkCancelService.new(params, current_user).call cable_ready.dispatch_event(name: "modal:close") diff --git a/app/services/cap_quantity.rb b/app/services/cap_quantity.rb index c1bfefaf5a..27bb86302c 100644 --- a/app/services/cap_quantity.rb +++ b/app/services/cap_quantity.rb @@ -46,6 +46,7 @@ class CapQuantity end def available_variants_for - OrderCycleDistributedVariants.new(order.order_cycle, order.distributor).available_variants + OrderCycles::DistributedVariantsService.new(order.order_cycle, + order.distributor).available_variants end end diff --git a/app/services/cart_service.rb b/app/services/cart_service.rb index 97a53613b0..ce6bc85652 100644 --- a/app/services/cart_service.rb +++ b/app/services/cart_service.rb @@ -154,7 +154,7 @@ class CartService end def check_variant_available_under_distribution(variant) - return true if OrderCycleDistributedVariants.new(@order_cycle, @distributor) + return true if OrderCycles::DistributedVariantsService.new(@order_cycle, @distributor) .available_variants.include? variant errors.add(:base, I18n.t(:spree_order_populator_availability_error)) diff --git a/app/services/checkout/post_checkout_actions.rb b/app/services/checkout/post_checkout_actions.rb index 5e8071012d..5484a70c09 100644 --- a/app/services/checkout/post_checkout_actions.rb +++ b/app/services/checkout/post_checkout_actions.rb @@ -14,7 +14,7 @@ module Checkout def failure @order.updater.shipping_address_from_distributor - OrderCheckoutRestart.new(@order).call + Orders::CheckoutRestartService.new(@order).call end private diff --git a/app/services/create_order_cycle.rb b/app/services/create_order_cycle.rb deleted file mode 100644 index 50900f1c88..0000000000 --- a/app/services/create_order_cycle.rb +++ /dev/null @@ -1,67 +0,0 @@ -# frozen_string_literal: true - -# Creates an order cycle for the provided enterprise and selecting all the -# variants specified for both incoming and outgoing exchanges -class CreateOrderCycle - # Constructor - # - # @param enterprise [Enterprise] - # @param variants [Array] - def initialize(enterprise, variants) - @enterprise = enterprise - @variants = variants - end - - # Creates the order cycle - def call - incoming_exchange.order_cycle = order_cycle - incoming_exchange.variants << variants - - outgoing_exchange.order_cycle = order_cycle - outgoing_exchange.variants << variants - - order_cycle.exchanges << incoming_exchange - order_cycle.exchanges << outgoing_exchange - - order_cycle.save! - end - - private - - attr_reader :enterprise, :variants - - # Builds an order cycle for the next month, starting now - # - # @return [OrderCycle] - def order_cycle - @order_cycle ||= OrderCycle.new( - coordinator_id: enterprise.id, - name: 'Monthly order cycle', - orders_open_at: Time.zone.now, - orders_close_at: 1.month.from_now - ) - end - - # Builds an exchange with the enterprise both as sender and receiver - # - # @return [Exchange] - def incoming_exchange - @incoming_exchange ||= Exchange.new( - sender_id: enterprise.id, - receiver_id: enterprise.id, - incoming: true - ) - end - - # Builds an exchange with the enterprise both as sender and receiver - # - # @return [Exchange] - def outgoing_exchange - @outgoing_exchange ||= Exchange.new( - sender_id: enterprise.id, - receiver_id: enterprise.id, - pickup_time: '8 am', - incoming: false - ) - end -end diff --git a/app/services/customer_order_cancellation.rb b/app/services/customer_order_cancellation.rb deleted file mode 100644 index 2e3f51c6e6..0000000000 --- a/app/services/customer_order_cancellation.rb +++ /dev/null @@ -1,17 +0,0 @@ -# frozen_string_literal: true - -class CustomerOrderCancellation - def initialize(order) - @order = order - end - - def call - return unless order.cancel - - Spree::OrderMailer.cancel_email_for_shop(order).deliver_later - end - - private - - attr_reader :order -end diff --git a/app/services/order_adjustments_fetcher.rb b/app/services/order_adjustments_fetcher.rb deleted file mode 100644 index 6f236074b9..0000000000 --- a/app/services/order_adjustments_fetcher.rb +++ /dev/null @@ -1,79 +0,0 @@ -# frozen_string_literal: true - -# This class allows orders with eager-loaded adjustment objects to calculate various adjustment -# types without triggering additional queries. -# -# For example; `order.adjustments.shipping.sum(:amount)` would normally trigger a new query -# regardless of whether or not adjustments have been preloaded, as `#shipping` is an adjustment -# scope, eg; `scope :shipping, where(originator_type: 'Spree::ShippingMethod')`. -# -# Here the adjustment scopes are moved to a shared module, and `adjustments.loaded?` is used to -# check if the objects have already been fetched and initialized. If they have, `order.adjustments` -# will be an Array, and we can select the required objects without hitting the database. If not, it -# will fetch the adjustments via their scopes as normal. - -class OrderAdjustmentsFetcher - include AdjustmentScopes - - def initialize(order) - @order = order - end - - def admin_and_handling_total - admin_and_handling_fees.map(&:amount).sum - end - - def payment_fee - sum_adjustments "payment_fee" - end - - def ship_total - sum_adjustments "shipping" - end - - private - - attr_reader :order - - def adjustments - order.all_adjustments - end - - def adjustments_eager_loaded? - adjustments.loaded? - end - - def sum_adjustments(scope) - collect_adjustments(scope).map(&:amount).sum - end - - def collect_adjustments(scope) - if adjustments_eager_loaded? - adjustment_scope = public_send("#{scope}_scope") - - # Adjustments are already loaded here, this block is using `Array#select` - adjustments.select do |adjustment| - match_by_scope(adjustment, adjustment_scope) && match_by_scope(adjustment, eligible_scope) - end - else - adjustments.where(nil).eligible.public_send scope - end - end - - def admin_and_handling_fees - if adjustments_eager_loaded? - adjustments.select do |adjustment| - match_by_scope(adjustment, eligible_scope) && - adjustment.originator_type == 'EnterpriseFee' && - adjustment.adjustable_type != 'Spree::LineItem' - end - else - adjustments.eligible. - where("originator_type = ? AND adjustable_type != ?", 'EnterpriseFee', 'Spree::LineItem') - end - end - - def match_by_scope(adjustment, scope) - adjustment.public_send(scope.keys.first) == scope.values.first - end -end diff --git a/app/services/order_available_payment_methods.rb b/app/services/order_available_payment_methods.rb deleted file mode 100644 index 84ea0f870f..0000000000 --- a/app/services/order_available_payment_methods.rb +++ /dev/null @@ -1,43 +0,0 @@ -# frozen_string_literal: true - -require 'open_food_network/tag_rule_applicator' - -class OrderAvailablePaymentMethods - attr_reader :order, :customer - - delegate :distributor, - :order_cycle, - to: :order - - def initialize(order, customer = nil) - @order, @customer = order, customer - end - - def to_a - return [] if distributor.blank? - - payment_methods = payment_methods_before_tag_rules_applied - - applicator = OpenFoodNetwork::TagRuleApplicator.new(distributor, - "FilterPaymentMethods", customer&.tag_list) - applicator.filter(payment_methods) - end - - private - - def payment_methods_before_tag_rules_applied - if order_cycle.nil? || order_cycle.simple? - distributor.payment_methods - else - distributor.payment_methods.where( - id: available_distributor_payment_methods_ids - ) - end.available.select(&:configured?).uniq - end - - def available_distributor_payment_methods_ids - order_cycle.distributor_payment_methods - .where(distributor_id: distributor.id) - .select(:payment_method_id) - end -end diff --git a/app/services/order_available_shipping_methods.rb b/app/services/order_available_shipping_methods.rb deleted file mode 100644 index 8cd30fd804..0000000000 --- a/app/services/order_available_shipping_methods.rb +++ /dev/null @@ -1,56 +0,0 @@ -# frozen_string_literal: true - -require 'open_food_network/tag_rule_applicator' - -class OrderAvailableShippingMethods - attr_reader :order, :customer - - delegate :distributor, :order_cycle, to: :order - - def initialize(order, customer = nil) - @order, @customer = order, customer - end - - def to_a - return [] if distributor.blank? - - filter_by_category(tag_rules.filter(shipping_methods)) - end - - private - - def filter_by_category(methods) - return methods unless OpenFoodNetwork::FeatureToggle.enabled?(:match_shipping_categories, - distributor&.owner) - - required_category_ids = order.variants.pluck(:shipping_category_id).to_set - return methods if required_category_ids.empty? - - methods.select do |method| - provided_category_ids = method.shipping_categories.pluck(:id).to_set - required_category_ids.subset?(provided_category_ids) - end - end - - def shipping_methods - if order_cycle.nil? || order_cycle.simple? - distributor.shipping_methods - else - distributor.shipping_methods.where( - id: available_distributor_shipping_methods_ids - ) - end.frontend.to_a.uniq - end - - def available_distributor_shipping_methods_ids - order_cycle.distributor_shipping_methods - .where(distributor_id: distributor.id) - .select(:shipping_method_id) - end - - def tag_rules - OpenFoodNetwork::TagRuleApplicator.new( - distributor, "FilterShippingMethods", customer&.tag_list - ) - end -end diff --git a/app/services/order_capture_service.rb b/app/services/order_capture_service.rb deleted file mode 100644 index 78e69c9a1d..0000000000 --- a/app/services/order_capture_service.rb +++ /dev/null @@ -1,22 +0,0 @@ -# frozen_string_literal: true - -# Use `authorize! :admin order` before calling this service - -class OrderCaptureService - attr_reader :gateway_error - - def initialize(order) - @order = order - @gateway_error = nil - end - - def call - return false unless @order.payment_required? - return false unless (pending_payment = @order.pending_payments.first) - - pending_payment.capture! - rescue Spree::Core::GatewayError => e - @gateway_error = e - false - end -end diff --git a/app/services/order_cart_reset.rb b/app/services/order_cart_reset.rb deleted file mode 100644 index e84fd67e88..0000000000 --- a/app/services/order_cart_reset.rb +++ /dev/null @@ -1,56 +0,0 @@ -# frozen_string_literal: false - -# Resets an order by verifying it's state and fixing any issues -class OrderCartReset - def initialize(order, distributor_id) - @order = order - @distributor ||= Enterprise.is_distributor.find_by(permalink: distributor_id) || - Enterprise.is_distributor.find(distributor_id) - end - - def reset_distributor - if order.distributor && order.distributor != distributor - order.empty! - order.set_order_cycle! nil - end - order.distributor = distributor - end - - def reset_other!(current_user, current_customer) - reset_user_and_customer(current_user) - reset_order_cycle(current_customer) - order.save! - end - - private - - attr_reader :order, :distributor, :current_user - - def reset_user_and_customer(current_user) - return unless current_user - - order.associate_user!(current_user) if order.user.blank? || order.email.blank? - end - - def reset_order_cycle(current_customer) - listed_order_cycles = Shop::OrderCyclesList.active_for(distributor, current_customer) - - if order_cycle_not_listed?(order.order_cycle, listed_order_cycles) - order.order_cycle = nil - order.empty! - end - - select_default_order_cycle(order, listed_order_cycles) - end - - def order_cycle_not_listed?(order_cycle, listed_order_cycles) - order_cycle.present? && !listed_order_cycles.include?(order_cycle) - end - - # If no OC is selected and there is only one in the list of OCs, selects it - def select_default_order_cycle(order, listed_order_cycles) - return unless order.order_cycle.blank? && listed_order_cycles.size == 1 - - order.order_cycle = listed_order_cycles.first - end -end diff --git a/app/services/order_checkout_restart.rb b/app/services/order_checkout_restart.rb deleted file mode 100644 index f43380636f..0000000000 --- a/app/services/order_checkout_restart.rb +++ /dev/null @@ -1,34 +0,0 @@ -# frozen_string_literal: true - -# Resets the passed order to cart state while clearing associated payments and shipments -class OrderCheckoutRestart - def initialize(order) - @order = order - end - - def call - return if order.cart? - - reset_state_to_cart - clear_shipments - clear_payments - - order.reload.update_order! - end - - private - - attr_reader :order - - def reset_state_to_cart - order.restart_checkout! - end - - def clear_shipments - order.shipments.with_state(:pending).destroy_all - end - - def clear_payments - order.payments.with_state(:checkout).destroy_all - end -end diff --git a/app/services/order_cycle_clone.rb b/app/services/order_cycle_clone.rb deleted file mode 100644 index 2d349a4f29..0000000000 --- a/app/services/order_cycle_clone.rb +++ /dev/null @@ -1,43 +0,0 @@ -# frozen_string_literal: true - -class OrderCycleClone - def initialize(order_cycle) - @original_order_cycle = order_cycle - end - - def create - oc = @original_order_cycle.dup - oc.name = I18n.t("models.order_cycle.cloned_order_cycle_name", order_cycle: oc.name) - oc.orders_open_at = oc.orders_close_at = oc.mails_sent = oc.processed_at = nil - oc.coordinator_fee_ids = @original_order_cycle.coordinator_fee_ids - oc.preferred_product_selection_from_coordinator_inventory_only = - @original_order_cycle.preferred_product_selection_from_coordinator_inventory_only - oc.schedule_ids = @original_order_cycle.schedule_ids - oc.save! - @original_order_cycle.exchanges.each { |e| e.clone!(oc) } - oc.selected_distributor_payment_method_ids = selected_distributor_payment_method_ids - oc.selected_distributor_shipping_method_ids = selected_distributor_shipping_method_ids - sync_subscriptions - oc.reload - end - - private - - def selected_distributor_payment_method_ids - @original_order_cycle.attachable_distributor_payment_methods.map(&:id) & - @original_order_cycle.selected_distributor_payment_method_ids - end - - def selected_distributor_shipping_method_ids - @original_order_cycle.attachable_distributor_shipping_methods.map(&:id) & - @original_order_cycle.selected_distributor_shipping_method_ids - end - - def sync_subscriptions - return unless @original_order_cycle.schedule_ids.any? - - OrderManagement::Subscriptions::ProxyOrderSyncer.new( - Subscription.where(schedule_id: @original_order_cycle.schedule_ids) - ).sync! - end -end diff --git a/app/services/order_cycle_distributed_products.rb b/app/services/order_cycle_distributed_products.rb deleted file mode 100644 index afe47b6cf7..0000000000 --- a/app/services/order_cycle_distributed_products.rb +++ /dev/null @@ -1,83 +0,0 @@ -# frozen_string_literal: true - -# Returns a (paginatable) AR object for the products or variants in stock for a given shop and OC. -# The stock-checking includes on_demand and stock level overrides from variant_overrides. -class OrderCycleDistributedProducts - def initialize(distributor, order_cycle, customer) - @distributor = distributor - @order_cycle = order_cycle - @customer = customer - end - - def products_relation - Spree::Product.where(id: stocked_products).group("spree_products.id") - end - - def variants_relation - order_cycle. - variants_distributed_by(distributor). - merge(stocked_variants_and_overrides). - select("DISTINCT spree_variants.*") - end - - private - - attr_reader :distributor, :order_cycle, :customer - - def stocked_products - order_cycle. - variants_distributed_by(distributor). - merge(stocked_variants_and_overrides). - select("DISTINCT spree_variants.product_id") - end - - def stocked_variants_and_overrides - stocked_variants = Spree::Variant. - joins("LEFT OUTER JOIN variant_overrides ON variant_overrides.variant_id = spree_variants.id - AND variant_overrides.hub_id = #{distributor.id}"). - joins(:stock_items). - where(query_stock_with_overrides) - - ProductTagRulesFilterer.new(distributor, customer, stocked_variants).call - end - - def query_stock_with_overrides - "( #{variant_not_overriden} AND ( #{variant_on_demand} OR #{variant_in_stock} ) ) - OR ( #{variant_overriden} AND ( #{override_on_demand} OR #{override_in_stock} ) ) - OR ( #{variant_overriden} AND ( #{override_on_demand_null} AND #{variant_on_demand} ) ) - OR ( #{variant_overriden} AND ( #{override_on_demand_null} - AND #{variant_not_on_demand} AND #{variant_in_stock} ) )" - end - - def variant_not_overriden - "variant_overrides.id IS NULL" - end - - def variant_overriden - "variant_overrides.id IS NOT NULL" - end - - def variant_in_stock - "spree_stock_items.count_on_hand > 0" - end - - def variant_on_demand - "spree_stock_items.backorderable IS TRUE" - end - - def variant_not_on_demand - "spree_stock_items.backorderable IS FALSE" - end - - def override_on_demand - "variant_overrides.on_demand IS TRUE" - end - - def override_in_stock - "variant_overrides.count_on_hand > 0" - end - - def override_on_demand_null - "variant_overrides.on_demand IS NULL" - end -end diff --git a/app/services/order_cycle_distributed_variants.rb b/app/services/order_cycle_distributed_variants.rb deleted file mode 100644 index 1b5c64c83e..0000000000 --- a/app/services/order_cycle_distributed_variants.rb +++ /dev/null @@ -1,22 +0,0 @@ -# frozen_string_literal: true - -class OrderCycleDistributedVariants - def initialize(order_cycle, distributor) - @order_cycle = order_cycle - @distributor = distributor - end - - def distributes_order_variants?(order) - unavailable_order_variants(order).empty? - end - - def unavailable_order_variants(order) - order.line_item_variants - available_variants - end - - def available_variants - return [] unless @order_cycle - - @order_cycle.variants_distributed_by(@distributor) - end -end diff --git a/app/services/order_cycle_form.rb b/app/services/order_cycle_form.rb deleted file mode 100644 index fbcfdf401d..0000000000 --- a/app/services/order_cycle_form.rb +++ /dev/null @@ -1,230 +0,0 @@ -# frozen_string_literal: true - -require 'open_food_network/permissions' -require 'open_food_network/order_cycle_form_applicator' - -class OrderCycleForm - def initialize(order_cycle, order_cycle_params, user) - @order_cycle = order_cycle - @order_cycle_params = order_cycle_params - @specified_params = order_cycle_params.keys - @user = user - @permissions = OpenFoodNetwork::Permissions.new(user) - @schedule_ids = order_cycle_params.delete(:schedule_ids) - @selected_distributor_payment_method_ids = order_cycle_params.delete( - :selected_distributor_payment_method_ids - ) - @selected_distributor_shipping_method_ids = order_cycle_params.delete( - :selected_distributor_shipping_method_ids - ) - end - - def save - schedule_ids = build_schedule_ids - order_cycle.assign_attributes(order_cycle_params) - return false unless order_cycle.valid? - - order_cycle.transaction do - order_cycle.save! - order_cycle.schedule_ids = schedule_ids if parameter_specified?(:schedule_ids) - order_cycle.save! - apply_exchange_changes - if can_update_selected_payment_or_shipping_methods? - attach_selected_distributor_payment_methods - attach_selected_distributor_shipping_methods - end - sync_subscriptions - true - end - rescue ActiveRecord::RecordInvalid => e - add_exception_to_order_cycle_errors(e) - false - end - - private - - attr_accessor :order_cycle, :order_cycle_params, :user, :permissions - - def add_exception_to_order_cycle_errors(exception) - error = exception.message.split(":").last.strip - order_cycle.errors.add(:base, error) if order_cycle.errors.to_a.exclude?(error) - end - - def apply_exchange_changes - return if exchanges_unchanged? - - OpenFoodNetwork::OrderCycleFormApplicator.new(order_cycle, user).go! - - # reload so outgoing exchanges are up-to-date for shipping/payment method validations - order_cycle.reload - end - - def attach_selected_distributor_payment_methods - return if @selected_distributor_payment_method_ids.nil? - - if distributor_only? - payment_method_ids = order_cycle.selected_distributor_payment_method_ids - payment_method_ids -= user_distributor_payment_method_ids - payment_method_ids += user_only_selected_distributor_payment_method_ids - order_cycle.selected_distributor_payment_method_ids = payment_method_ids - else - order_cycle.selected_distributor_payment_method_ids = selected_distributor_payment_method_ids - end - order_cycle.save! - end - - def attach_selected_distributor_shipping_methods - return if @selected_distributor_shipping_method_ids.nil? - - if distributor_only? - # A distributor can only update methods associated with their own - # enterprise, so we load all previously selected methods, and replace - # only the distributor's methods with their selection (not touching other - # distributor's methods). - shipping_method_ids = order_cycle.selected_distributor_shipping_method_ids - shipping_method_ids -= user_distributor_shipping_method_ids - shipping_method_ids += user_only_selected_distributor_shipping_method_ids - order_cycle.selected_distributor_shipping_method_ids = shipping_method_ids - else - order_cycle.selected_distributor_shipping_method_ids = - selected_distributor_shipping_method_ids - end - - order_cycle.save! - end - - def attachable_distributor_payment_method_ids - @attachable_distributor_payment_method_ids ||= - order_cycle.attachable_distributor_payment_methods.map(&:id) - end - - def attachable_distributor_shipping_method_ids - @attachable_distributor_shipping_method_ids ||= - order_cycle.attachable_distributor_shipping_methods.map(&:id) - end - - def exchanges_unchanged? - [:incoming_exchanges, :outgoing_exchanges].all? do |direction| - order_cycle_params[direction].nil? - end - end - - def selected_distributor_payment_method_ids - @selected_distributor_payment_method_ids = ( - attachable_distributor_payment_method_ids & - @selected_distributor_payment_method_ids.compact_blank.map(&:to_i) - ) - - if attachable_distributor_payment_method_ids.sort == - @selected_distributor_payment_method_ids.sort - @selected_distributor_payment_method_ids = [] - end - - @selected_distributor_payment_method_ids - end - - def user_only_selected_distributor_payment_method_ids - user_distributor_payment_method_ids.intersection(selected_distributor_payment_method_ids) - end - - def selected_distributor_shipping_method_ids - @selected_distributor_shipping_method_ids = ( - attachable_distributor_shipping_method_ids & - @selected_distributor_shipping_method_ids.compact_blank.map(&:to_i) - ) - - if attachable_distributor_shipping_method_ids.sort == - @selected_distributor_shipping_method_ids.sort - @selected_distributor_shipping_method_ids = [] - end - - @selected_distributor_shipping_method_ids - end - - def user_only_selected_distributor_shipping_method_ids - user_distributor_shipping_method_ids.intersection(selected_distributor_shipping_method_ids) - end - - def build_schedule_ids - return unless parameter_specified?(:schedule_ids) - - result = existing_schedule_ids - result |= (requested_schedule_ids & permitted_schedule_ids) # Add permitted and requested - # Remove permitted but not requested - result -= ((result & permitted_schedule_ids) - requested_schedule_ids) - result - end - - def sync_subscriptions - return unless parameter_specified?(:schedule_ids) - return unless schedule_sync_required? - - OrderManagement::Subscriptions::ProxyOrderSyncer.new(subscriptions_to_sync).sync! - end - - def schedule_sync_required? - removed_schedule_ids.any? || new_schedule_ids.any? - end - - def subscriptions_to_sync - Subscription.where(schedule_id: removed_schedule_ids + new_schedule_ids) - end - - def requested_schedule_ids - @schedule_ids.map(&:to_i) - end - - def parameter_specified?(key) - @specified_params.map(&:to_s).include?(key.to_s) - end - - def permitted_schedule_ids - Schedule.where(id: requested_schedule_ids | existing_schedule_ids) - .merge(permissions.editable_schedules).pluck(:id) - end - - def existing_schedule_ids - @existing_schedule_ids ||= order_cycle.persisted? ? order_cycle.schedule_ids : [] - end - - def removed_schedule_ids - existing_schedule_ids - order_cycle.schedule_ids - end - - def new_schedule_ids - @order_cycle.schedule_ids - existing_schedule_ids - end - - def can_update_selected_payment_or_shipping_methods? - @user.admin? || coordinator? || distributor? - end - - def coordinator? - @user.enterprises.include?(@order_cycle.coordinator) - end - - def distributor? - !user_distributors_ids.empty? - end - - def distributor_only? - distributor? && !@user.admin? && !coordinator? - end - - def user_distributors_ids - @user_distributors_ids ||= @user.enterprises.pluck(:id) - .intersection(@order_cycle.distributors.pluck(:id)) - end - - def user_distributor_payment_method_ids - @user_distributor_payment_method_ids ||= - DistributorPaymentMethod.where(distributor_id: user_distributors_ids) - .pluck(:id) - end - - def user_distributor_shipping_method_ids - @user_distributor_shipping_method_ids ||= - DistributorShippingMethod.where(distributor_id: user_distributors_ids) - .pluck(:id) - end -end diff --git a/app/services/order_cycle_warning.rb b/app/services/order_cycle_warning.rb deleted file mode 100644 index 7e7afad8d8..0000000000 --- a/app/services/order_cycle_warning.rb +++ /dev/null @@ -1,37 +0,0 @@ -# frozen_string_literal: true - -class OrderCycleWarning - def initialize(current_user) - @current_user = current_user - end - - def call - distributors = active_distributors_not_ready_for_checkout - - return if distributors.empty? - - active_distributors_not_ready_for_checkout_message(distributors) - end - - private - - attr_reader :current_user - - def active_distributors_not_ready_for_checkout - ocs = OrderCycle.managed_by(current_user).active - distributors = ocs.includes(:distributors).map(&:distributors).flatten.uniq - Enterprise.where(id: distributors.map(&:id)).not_ready_for_checkout - end - - def active_distributors_not_ready_for_checkout_message(distributors) - distributor_names = distributors.map(&:name).join ', ' - - if distributors.count > 1 - I18n.t(:active_distributors_not_ready_for_checkout_message_plural, - distributor_names:) - else - I18n.t(:active_distributors_not_ready_for_checkout_message_singular, - distributor_names:) - end - end -end diff --git a/app/services/order_cycle_webhook_service.rb b/app/services/order_cycle_webhook_service.rb deleted file mode 100644 index f2d4df152a..0000000000 --- a/app/services/order_cycle_webhook_service.rb +++ /dev/null @@ -1,21 +0,0 @@ -# frozen_string_literal: true - -# Create a webhook payload for an order cycle event. -# The payload will be delivered asynchronously. -class OrderCycleWebhookService - def self.create_webhook_job(order_cycle, event) - webhook_payload = order_cycle - .slice(:id, :name, :orders_open_at, :orders_close_at, :coordinator_id) - .merge(coordinator_name: order_cycle.coordinator.name) - - # Endpoints for coordinator owner - webhook_endpoints = order_cycle.coordinator.owner.webhook_endpoints - - # Plus unique endpoints for distributor owners (ignore duplicates) - webhook_endpoints |= order_cycle.distributors.map(&:owner).flat_map(&:webhook_endpoints) - - webhook_endpoints.each do |endpoint| - WebhookDeliveryJob.perform_later(endpoint.url, event, webhook_payload) - end - end -end diff --git a/app/services/order_cycles/clone_service.rb b/app/services/order_cycles/clone_service.rb new file mode 100644 index 0000000000..56e8c79247 --- /dev/null +++ b/app/services/order_cycles/clone_service.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +module OrderCycles + class CloneService + def initialize(order_cycle) + @original_order_cycle = order_cycle + end + + def create + oc = @original_order_cycle.dup + oc.name = I18n.t("models.order_cycle.cloned_order_cycle_name", order_cycle: oc.name) + oc.orders_open_at = oc.orders_close_at = oc.mails_sent = oc.processed_at = nil + oc.coordinator_fee_ids = @original_order_cycle.coordinator_fee_ids + oc.preferred_product_selection_from_coordinator_inventory_only = + @original_order_cycle.preferred_product_selection_from_coordinator_inventory_only + oc.schedule_ids = @original_order_cycle.schedule_ids + oc.save! + @original_order_cycle.exchanges.each { |e| e.clone!(oc) } + oc.selected_distributor_payment_method_ids = selected_distributor_payment_method_ids + oc.selected_distributor_shipping_method_ids = selected_distributor_shipping_method_ids + sync_subscriptions + oc.reload + end + + private + + def selected_distributor_payment_method_ids + @original_order_cycle.attachable_distributor_payment_methods.map(&:id) & + @original_order_cycle.selected_distributor_payment_method_ids + end + + def selected_distributor_shipping_method_ids + @original_order_cycle.attachable_distributor_shipping_methods.map(&:id) & + @original_order_cycle.selected_distributor_shipping_method_ids + end + + def sync_subscriptions + return unless @original_order_cycle.schedule_ids.any? + + OrderManagement::Subscriptions::ProxyOrderSyncer.new( + Subscription.where(schedule_id: @original_order_cycle.schedule_ids) + ).sync! + end + end +end diff --git a/app/services/order_cycles/distributed_products_service.rb b/app/services/order_cycles/distributed_products_service.rb new file mode 100644 index 0000000000..567478c7eb --- /dev/null +++ b/app/services/order_cycles/distributed_products_service.rb @@ -0,0 +1,86 @@ +# frozen_string_literal: true + +# Returns a (paginatable) AR object for the products or variants in stock for a given shop and OC. +# The stock-checking includes on_demand and stock level overrides from variant_overrides. + +module OrderCycles + class DistributedProductsService + def initialize(distributor, order_cycle, customer) + @distributor = distributor + @order_cycle = order_cycle + @customer = customer + end + + def products_relation + Spree::Product.where(id: stocked_products).group("spree_products.id") + end + + def variants_relation + order_cycle. + variants_distributed_by(distributor). + merge(stocked_variants_and_overrides). + select("DISTINCT spree_variants.*") + end + + private + + attr_reader :distributor, :order_cycle, :customer + + def stocked_products + order_cycle. + variants_distributed_by(distributor). + merge(stocked_variants_and_overrides). + select("DISTINCT spree_variants.product_id") + end + + def stocked_variants_and_overrides + stocked_variants = Spree::Variant. + joins("LEFT OUTER JOIN variant_overrides ON variant_overrides.variant_id = spree_variants.id + AND variant_overrides.hub_id = #{distributor.id}"). + joins(:stock_items). + where(query_stock_with_overrides) + + ProductTagRulesFilterer.new(distributor, customer, stocked_variants).call + end + + def query_stock_with_overrides + "( #{variant_not_overriden} AND ( #{variant_on_demand} OR #{variant_in_stock} ) ) + OR ( #{variant_overriden} AND ( #{override_on_demand} OR #{override_in_stock} ) ) + OR ( #{variant_overriden} AND ( #{override_on_demand_null} AND #{variant_on_demand} ) ) + OR ( #{variant_overriden} AND ( #{override_on_demand_null} + AND #{variant_not_on_demand} AND #{variant_in_stock} ) )" + end + + def variant_not_overriden + "variant_overrides.id IS NULL" + end + + def variant_overriden + "variant_overrides.id IS NOT NULL" + end + + def variant_in_stock + "spree_stock_items.count_on_hand > 0" + end + + def variant_on_demand + "spree_stock_items.backorderable IS TRUE" + end + + def variant_not_on_demand + "spree_stock_items.backorderable IS FALSE" + end + + def override_on_demand + "variant_overrides.on_demand IS TRUE" + end + + def override_in_stock + "variant_overrides.count_on_hand > 0" + end + + def override_on_demand_null + "variant_overrides.on_demand IS NULL" + end + end +end diff --git a/app/services/order_cycles/distributed_variants_service.rb b/app/services/order_cycles/distributed_variants_service.rb new file mode 100644 index 0000000000..cf4bb1c03f --- /dev/null +++ b/app/services/order_cycles/distributed_variants_service.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +module OrderCycles + class DistributedVariantsService + def initialize(order_cycle, distributor) + @order_cycle = order_cycle + @distributor = distributor + end + + def distributes_order_variants?(order) + unavailable_order_variants(order).empty? + end + + def unavailable_order_variants(order) + order.line_item_variants - available_variants + end + + def available_variants + return [] unless @order_cycle + + @order_cycle.variants_distributed_by(@distributor) + end + end +end diff --git a/app/services/order_cycles/form_service.rb b/app/services/order_cycles/form_service.rb new file mode 100644 index 0000000000..0b2f62d988 --- /dev/null +++ b/app/services/order_cycles/form_service.rb @@ -0,0 +1,233 @@ +# frozen_string_literal: true + +require 'open_food_network/permissions' +require 'open_food_network/order_cycle_form_applicator' + +module OrderCycles + class FormService + def initialize(order_cycle, order_cycle_params, user) + @order_cycle = order_cycle + @order_cycle_params = order_cycle_params + @specified_params = order_cycle_params.keys + @user = user + @permissions = OpenFoodNetwork::Permissions.new(user) + @schedule_ids = order_cycle_params.delete(:schedule_ids) + @selected_distributor_payment_method_ids = order_cycle_params.delete( + :selected_distributor_payment_method_ids + ) + @selected_distributor_shipping_method_ids = order_cycle_params.delete( + :selected_distributor_shipping_method_ids + ) + end + + def save + schedule_ids = build_schedule_ids + order_cycle.assign_attributes(order_cycle_params) + return false unless order_cycle.valid? + + order_cycle.transaction do + order_cycle.save! + order_cycle.schedule_ids = schedule_ids if parameter_specified?(:schedule_ids) + order_cycle.save! + apply_exchange_changes + if can_update_selected_payment_or_shipping_methods? + attach_selected_distributor_payment_methods + attach_selected_distributor_shipping_methods + end + sync_subscriptions + true + end + rescue ActiveRecord::RecordInvalid => e + add_exception_to_order_cycle_errors(e) + false + end + + private + + attr_accessor :order_cycle, :order_cycle_params, :user, :permissions + + def add_exception_to_order_cycle_errors(exception) + error = exception.message.split(":").last.strip + order_cycle.errors.add(:base, error) if order_cycle.errors.to_a.exclude?(error) + end + + def apply_exchange_changes + return if exchanges_unchanged? + + OpenFoodNetwork::OrderCycleFormApplicator.new(order_cycle, user).go! + + # reload so outgoing exchanges are up-to-date for shipping/payment method validations + order_cycle.reload + end + + def attach_selected_distributor_payment_methods + return if @selected_distributor_payment_method_ids.nil? + + if distributor_only? + payment_method_ids = order_cycle.selected_distributor_payment_method_ids + payment_method_ids -= user_distributor_payment_method_ids + payment_method_ids += user_only_selected_distributor_payment_method_ids + order_cycle.selected_distributor_payment_method_ids = payment_method_ids + else + order_cycle + .selected_distributor_payment_method_ids = selected_distributor_payment_method_ids + end + order_cycle.save! + end + + def attach_selected_distributor_shipping_methods + return if @selected_distributor_shipping_method_ids.nil? + + if distributor_only? + # A distributor can only update methods associated with their own + # enterprise, so we load all previously selected methods, and replace + # only the distributor's methods with their selection (not touching other + # distributor's methods). + shipping_method_ids = order_cycle.selected_distributor_shipping_method_ids + shipping_method_ids -= user_distributor_shipping_method_ids + shipping_method_ids += user_only_selected_distributor_shipping_method_ids + order_cycle.selected_distributor_shipping_method_ids = shipping_method_ids + else + order_cycle.selected_distributor_shipping_method_ids = + selected_distributor_shipping_method_ids + end + + order_cycle.save! + end + + def attachable_distributor_payment_method_ids + @attachable_distributor_payment_method_ids ||= + order_cycle.attachable_distributor_payment_methods.map(&:id) + end + + def attachable_distributor_shipping_method_ids + @attachable_distributor_shipping_method_ids ||= + order_cycle.attachable_distributor_shipping_methods.map(&:id) + end + + def exchanges_unchanged? + [:incoming_exchanges, :outgoing_exchanges].all? do |direction| + order_cycle_params[direction].nil? + end + end + + def selected_distributor_payment_method_ids + @selected_distributor_payment_method_ids = ( + attachable_distributor_payment_method_ids & + @selected_distributor_payment_method_ids.compact_blank.map(&:to_i) + ) + + if attachable_distributor_payment_method_ids.sort == + @selected_distributor_payment_method_ids.sort + @selected_distributor_payment_method_ids = [] + end + + @selected_distributor_payment_method_ids + end + + def user_only_selected_distributor_payment_method_ids + user_distributor_payment_method_ids.intersection(selected_distributor_payment_method_ids) + end + + def selected_distributor_shipping_method_ids + @selected_distributor_shipping_method_ids = ( + attachable_distributor_shipping_method_ids & + @selected_distributor_shipping_method_ids.compact_blank.map(&:to_i) + ) + + if attachable_distributor_shipping_method_ids.sort == + @selected_distributor_shipping_method_ids.sort + @selected_distributor_shipping_method_ids = [] + end + + @selected_distributor_shipping_method_ids + end + + def user_only_selected_distributor_shipping_method_ids + user_distributor_shipping_method_ids.intersection(selected_distributor_shipping_method_ids) + end + + def build_schedule_ids + return unless parameter_specified?(:schedule_ids) + + result = existing_schedule_ids + result |= (requested_schedule_ids & permitted_schedule_ids) # Add permitted and requested + # Remove permitted but not requested + result -= ((result & permitted_schedule_ids) - requested_schedule_ids) + result + end + + def sync_subscriptions + return unless parameter_specified?(:schedule_ids) + return unless schedule_sync_required? + + OrderManagement::Subscriptions::ProxyOrderSyncer.new(subscriptions_to_sync).sync! + end + + def schedule_sync_required? + removed_schedule_ids.any? || new_schedule_ids.any? + end + + def subscriptions_to_sync + Subscription.where(schedule_id: removed_schedule_ids + new_schedule_ids) + end + + def requested_schedule_ids + @schedule_ids.map(&:to_i) + end + + def parameter_specified?(key) + @specified_params.map(&:to_s).include?(key.to_s) + end + + def permitted_schedule_ids + Schedule.where(id: requested_schedule_ids | existing_schedule_ids) + .merge(permissions.editable_schedules).pluck(:id) + end + + def existing_schedule_ids + @existing_schedule_ids ||= order_cycle.persisted? ? order_cycle.schedule_ids : [] + end + + def removed_schedule_ids + existing_schedule_ids - order_cycle.schedule_ids + end + + def new_schedule_ids + @order_cycle.schedule_ids - existing_schedule_ids + end + + def can_update_selected_payment_or_shipping_methods? + @user.admin? || coordinator? || distributor? + end + + def coordinator? + @user.enterprises.include?(@order_cycle.coordinator) + end + + def distributor? + !user_distributors_ids.empty? + end + + def distributor_only? + distributor? && !@user.admin? && !coordinator? + end + + def user_distributors_ids + @user_distributors_ids ||= @user.enterprises.pluck(:id) + .intersection(@order_cycle.distributors.pluck(:id)) + end + + def user_distributor_payment_method_ids + @user_distributor_payment_method_ids ||= + DistributorPaymentMethod.where(distributor_id: user_distributors_ids) + .pluck(:id) + end + + def user_distributor_shipping_method_ids + @user_distributor_shipping_method_ids ||= + DistributorShippingMethod.where(distributor_id: user_distributors_ids) + .pluck(:id) + end + end +end diff --git a/app/services/order_cycles/warning_service.rb b/app/services/order_cycles/warning_service.rb new file mode 100644 index 0000000000..35859424d0 --- /dev/null +++ b/app/services/order_cycles/warning_service.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +module OrderCycles + class WarningService + def initialize(current_user) + @current_user = current_user + end + + def call + distributors = active_distributors_not_ready_for_checkout + + return if distributors.empty? + + active_distributors_not_ready_for_checkout_message(distributors) + end + + private + + attr_reader :current_user + + def active_distributors_not_ready_for_checkout + ocs = OrderCycle.managed_by(current_user).active + distributors = ocs.includes(:distributors).map(&:distributors).flatten.uniq + Enterprise.where(id: distributors.map(&:id)).not_ready_for_checkout + end + + def active_distributors_not_ready_for_checkout_message(distributors) + distributor_names = distributors.map(&:name).join ', ' + + if distributors.count > 1 + I18n.t(:active_distributors_not_ready_for_checkout_message_plural, + distributor_names:) + else + I18n.t(:active_distributors_not_ready_for_checkout_message_singular, + distributor_names:) + end + end + end +end diff --git a/app/services/order_cycles/webhook_service.rb b/app/services/order_cycles/webhook_service.rb new file mode 100644 index 0000000000..f12c94ea1b --- /dev/null +++ b/app/services/order_cycles/webhook_service.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +# Create a webhook payload for an order cycle event. +# The payload will be delivered asynchronously. + +module OrderCycles + class WebhookService + def self.create_webhook_job(order_cycle, event) + webhook_payload = order_cycle + .slice(:id, :name, :orders_open_at, :orders_close_at, :coordinator_id) + .merge(coordinator_name: order_cycle.coordinator.name) + + # Endpoints for coordinator owner + webhook_endpoints = order_cycle.coordinator.owner.webhook_endpoints + + # Plus unique endpoints for distributor owners (ignore duplicates) + webhook_endpoints |= order_cycle.distributors.map(&:owner).flat_map(&:webhook_endpoints) + + webhook_endpoints.each do |endpoint| + WebhookDeliveryJob.perform_later(endpoint.url, event, webhook_payload) + end + end + end +end diff --git a/app/services/order_data_masker.rb b/app/services/order_data_masker.rb deleted file mode 100644 index e5ae198332..0000000000 --- a/app/services/order_data_masker.rb +++ /dev/null @@ -1,35 +0,0 @@ -# frozen_string_literal: true - -class OrderDataMasker - def initialize(order) - @order = order - end - - def call - mask_customer_names unless customer_names_allowed? - mask_contact_data - end - - private - - attr_accessor :order - - def customer_names_allowed? - order.distributor.show_customer_names_to_suppliers - end - - def mask_customer_names - order.bill_address&.assign_attributes(firstname: I18n.t('admin.reports.hidden'), - lastname: "") - order.ship_address&.assign_attributes(firstname: I18n.t('admin.reports.hidden'), - lastname: "") - end - - def mask_contact_data - order.bill_address&.assign_attributes(phone: "", address1: "", address2: "", - city: "", zipcode: "", state: nil) - order.ship_address&.assign_attributes(phone: "", address1: "", address2: "", - city: "", zipcode: "", state: nil) - order.assign_attributes(email: I18n.t('admin.reports.hidden')) - end -end diff --git a/app/services/order_factory.rb b/app/services/order_factory.rb deleted file mode 100644 index 077dbac288..0000000000 --- a/app/services/order_factory.rb +++ /dev/null @@ -1,97 +0,0 @@ -# frozen_string_literal: true - -require 'open_food_network/scope_variant_to_hub' - -# Builds orders based on a set of attributes -# There are some idiosyncracies in the order creation process, -# and it is nice to have them dealt with in one place. - -class OrderFactory - def initialize(attrs, opts = {}) - @attrs = attrs.with_indifferent_access - @opts = opts.with_indifferent_access - end - - def create - create_order - set_user - build_line_items - set_addresses - create_shipment - set_shipping_method - create_payment - - @order - end - - private - - attr_reader :attrs, :opts - - def customer - @customer ||= Customer.find(attrs[:customer_id]) - end - - def shop - @shop ||= Enterprise.find(attrs[:distributor_id]) - end - - def create_order - @order = Spree::Order.create!(create_attrs) - end - - def create_attrs - create_attrs = attrs.slice(:customer_id, :order_cycle_id, :distributor_id) - create_attrs[:email] = customer.email - create_attrs - end - - def build_line_items - attrs[:line_items].each do |li| - next unless variant = Spree::Variant.find_by(id: li[:variant_id]) - - scoper.scope(variant) - li[:quantity] = stock_limited_quantity(variant.on_demand, variant.on_hand, li[:quantity]) - li[:price] = variant.price - build_item_from(li) - end - end - - def build_item_from(attrs) - @order.line_items.build( - attrs.merge(skip_stock_check: opts[:skip_stock_check]) - ) - end - - def set_user - @order.update_attribute(:user_id, customer.user_id) - end - - def set_addresses - @order.update(attrs.slice(:bill_address_attributes, :ship_address_attributes)) - end - - def create_shipment - @order.create_proposed_shipments - end - - def set_shipping_method - @order.select_shipping_method(attrs[:shipping_method_id]) - end - - def create_payment - @order.recreate_all_fees! - @order.payments.create(payment_method_id: attrs[:payment_method_id], - amount: @order.reload.total) - end - - def stock_limited_quantity(variant_on_demand, variant_on_hand, requested) - return requested if opts[:skip_stock_check] || variant_on_demand - - [variant_on_hand, requested].min - end - - def scoper - @scoper ||= OpenFoodNetwork::ScopeVariantToHub.new(shop) - end -end diff --git a/app/services/order_fees_handler.rb b/app/services/order_fees_handler.rb deleted file mode 100644 index 47be2c9903..0000000000 --- a/app/services/order_fees_handler.rb +++ /dev/null @@ -1,68 +0,0 @@ -# frozen_string_literal: true - -class OrderFeesHandler - attr_reader :order - - delegate :distributor, :order_cycle, to: :order - - def initialize(order) - @order = order - end - - def recreate_all_fees! - # `with_lock` acquires an exclusive row lock on order so no other - # requests can update it until the transaction is commited. - # See https://github.com/rails/rails/blob/3-2-stable/activerecord/lib/active_record/locking/pessimistic.rb#L69 - # and https://www.postgresql.org/docs/current/static/sql-select.html#SQL-FOR-UPDATE-SHARE - order.with_lock do - EnterpriseFee.clear_all_adjustments order - - create_line_item_fees! - create_order_fees! - end - - tax_enterprise_fees! unless order.before_payment_state? - order.update_order! - end - - def create_line_item_fees! - order.line_items.includes(variant: :product).each do |line_item| - if provided_by_order_cycle? line_item - calculator.create_line_item_adjustments_for line_item - end - end - end - - def create_order_fees! - return unless order_cycle - - calculator.create_order_adjustments_for order - end - - def tax_enterprise_fees! - Spree::TaxRate.adjust(order, order.all_adjustments.enterprise_fee) - end - - def update_line_item_fees!(line_item) - line_item.adjustments.enterprise_fee.each do |fee| - fee.update_adjustment!(line_item, force: true) - end - end - - def update_order_fees! - order.adjustments.enterprise_fee.where(adjustable_type: 'Spree::Order').each do |fee| - fee.update_adjustment!(order, force: true) - end - end - - private - - def calculator - @calculator ||= OpenFoodNetwork::EnterpriseFeeCalculator.new(distributor, order_cycle) - end - - def provided_by_order_cycle?(line_item) - @order_cycle_variant_ids ||= order_cycle&.variants&.map(&:id) || [] - @order_cycle_variant_ids.include? line_item.variant_id - end -end diff --git a/app/services/order_invoice_comparator.rb b/app/services/order_invoice_comparator.rb deleted file mode 100644 index d306a972ce..0000000000 --- a/app/services/order_invoice_comparator.rb +++ /dev/null @@ -1,86 +0,0 @@ -# frozen_string_literal: true - -class OrderInvoiceComparator - attr_reader :order - - def initialize(order) - @order = order - end - - def can_generate_new_invoice? - return true if invoices.empty? - - # We'll use a recursive BFS algorithm to find if the invoice is outdated - # the root will be the order - # On each node, we'll a list of relevant attributes that will be used on the comparison - different?(current_state_invoice, latest_invoice, invoice_generation_selector) - end - - def can_update_latest_invoice? - return false if invoices.empty? - - different?(current_state_invoice, latest_invoice, invoice_update_selector) - end - - private - - def different?(node1, node2, attributes_selector) - simple_values1, presenters1 = attributes_selector.call(node1) - simple_values2, presenters2 = attributes_selector.call(node2) - return true if simple_values1 != simple_values2 - - return true if presenters1.size != presenters2.size - - presenters1.zip(presenters2).any? do |presenter1, presenter2| - different?(presenter1, presenter2, attributes_selector) - end - end - - def invoice_generation_selector - values_selector(:invoice_generation_values) - end - - def invoice_update_selector - values_selector(:invoice_update_values) - end - - def values_selector(attribute) - proc do |node| - return [[], []] unless node.respond_to?(attribute) - - grouped = node.public_send(attribute).group_by(&grouper) - [grouped[:simple] || [], grouped[:presenters]&.flatten || []] - end - end - - def grouper - proc do |value| - if value.is_a?(Array) || value.class.to_s.starts_with?("Invoice::DataPresenter") - :presenters - else - :simple - end - end - end - - def current_state_invoice - @current_state_invoice ||= Invoice.new( - order:, - data: serialize_for_invoice, - date: Time.zone.today, - number: invoices.count + 1 - ).presenter - end - - def invoices - order.invoices - end - - def latest_invoice - @latest_invoice ||= invoices.first.presenter - end - - def serialize_for_invoice - InvoiceDataGenerator.new(order).serialize_for_invoice - end -end diff --git a/app/services/order_invoice_generator.rb b/app/services/order_invoice_generator.rb deleted file mode 100644 index 1d91fec8da..0000000000 --- a/app/services/order_invoice_generator.rb +++ /dev/null @@ -1,38 +0,0 @@ -# frozen_string_literal: true - -class OrderInvoiceGenerator - def initialize(order) - @order = order - end - - def generate_or_update_latest_invoice - if comparator.can_generate_new_invoice? - order.invoices.create!( - date: Time.zone.today, - number: total_invoices_created_by_distributor + 1, - data: invoice_data - ) - elsif comparator.can_update_latest_invoice? - order.invoices.latest.update!( - date: Time.zone.today, - data: invoice_data - ) - end - end - - private - - attr_reader :order - - def comparator - @comparator ||= OrderInvoiceComparator.new(order) - end - - def invoice_data - @invoice_data ||= InvoiceDataGenerator.new(order).generate - end - - def total_invoices_created_by_distributor - Invoice.joins(:order).where(order: { distributor: order.distributor }).count - end -end diff --git a/app/services/order_payment_finder.rb b/app/services/order_payment_finder.rb deleted file mode 100644 index 54b19654a3..0000000000 --- a/app/services/order_payment_finder.rb +++ /dev/null @@ -1,28 +0,0 @@ -# frozen_string_literal: true - -class OrderPaymentFinder - def initialize(order) - @order = order - end - - def last_payment - last(@order.payments) - end - - def last_pending_payment - last(@order.pending_payments) - end - - private - - # `max_by` avoids additional database queries when payments are loaded - # already. There is usually only one payment and this shouldn't cause - # any overhead compared to `order(:created_at).last`. Using `last` - # without order is not deterministic. - # - # We are not using `updated_at` because all payments are touched when the - # order is updated and then all payments have the same `updated_at` value. - def last(payments) - payments.max_by(&:created_at) - end -end diff --git a/app/services/order_syncer.rb b/app/services/order_syncer.rb deleted file mode 100644 index 83ed767426..0000000000 --- a/app/services/order_syncer.rb +++ /dev/null @@ -1,138 +0,0 @@ -# frozen_string_literal: true - -# Responsible for ensuring that any updates to a Subscription are propagated to any -# orders belonging to that Subscription which have been instantiated -class OrderSyncer - attr_reader :order_update_issues - - def initialize(subscription) - @subscription = subscription - @order_update_issues = OrderUpdateIssues.new - @line_item_syncer = LineItemSyncer.new(subscription, order_update_issues) - end - - def sync! - orders_in_order_cycles_not_closed.all? do |order| - order.assign_attributes(customer_id:, email: customer&.email, - distributor_id: shop_id) - update_associations_for(order) - line_item_syncer.sync!(order) - order.update_order! - order.save - end - end - - private - - attr_reader :subscription, :line_item_syncer - - delegate :orders, :bill_address, :ship_address, :subscription_line_items, to: :subscription - delegate :shop_id, :customer, :customer_id, to: :subscription - delegate :shipping_method, :shipping_method_id, - :payment_method, :payment_method_id, to: :subscription - delegate :shipping_method_id_changed?, :shipping_method_id_was, to: :subscription - delegate :payment_method_id_changed?, :payment_method_id_was, to: :subscription - - def update_associations_for(order) - update_bill_address_for(order) if (bill_address.changes.keys & relevant_address_attrs).any? - update_shipment_for(order) if shipping_method_id_changed? - update_ship_address_for(order) - update_payment_for(order) if payment_method_id_changed? - end - - def orders_in_order_cycles_not_closed - return @orders_in_order_cycles_not_closed unless @orders_in_order_cycles_not_closed.nil? - - @orders_in_order_cycles_not_closed = orders.joins(:order_cycle). - merge(OrderCycle.not_closed).readonly(false) - end - - def update_bill_address_for(order) - unless addresses_match?(order.bill_address, bill_address) - return order_update_issues.add(order, I18n.t('bill_address')) - end - - order.bill_address.update(bill_address.attributes.slice(*relevant_address_attrs)) - end - - def update_payment_for(order) - payment = order.payments. - with_state('checkout').where(payment_method_id: payment_method_id_was).last - if payment - payment&.void_transaction! - order.payments.create(payment_method_id:, amount: order.reload.total) - else - unless order.payments.with_state('checkout').where(payment_method_id:).any? - order_update_issues.add(order, I18n.t('admin.payment_method')) - end - end - end - - def update_shipment_for(order) - return if pending_shipment_with?(order, shipping_method_id) # No need to do anything. - - if pending_shipment_with?(order, shipping_method_id_was) - order.select_shipping_method(shipping_method_id) - else - order_update_issues.add(order, I18n.t('admin.shipping_method')) - end - end - - def update_ship_address_for(order) - # The conditions here are to achieve the same behaviour in earlier versions of Spree, where - # switching from pick-up to delivery affects whether simultaneous changes to shipping address - # are ignored or not. - pickup_to_delivery = force_ship_address_required?(order) - if (!pickup_to_delivery || order.shipment.present?) && - (ship_address.changes.keys & relevant_address_attrs).any? - save_ship_address_in_order(order) - end - return unless !pickup_to_delivery || order.shipment.blank? - - order.updater.shipping_address_from_distributor - end - - def relevant_address_attrs - ["firstname", "lastname", "address1", "zipcode", "city", "state_id", "country_id", "phone"] - end - - def addresses_match?(order_address, subscription_address) - relevant_address_attrs.all? do |attr| - order_address[attr] == subscription_address.public_send("#{attr}_was") || - order_address[attr] == subscription_address[attr] - end - end - - def ship_address_updatable?(order) - return true if force_ship_address_required?(order) - return false unless order.shipping_method.require_ship_address? - return true if addresses_match?(order.ship_address, ship_address) - - order_update_issues.add(order, I18n.t('ship_address')) - false - end - - # This returns true when the shipping method on the subscription has changed - # to a delivery (ie. a shipping address is required) AND the existing shipping - # address on the order matches the shop's address - def force_ship_address_required?(order) - return false unless shipping_method.require_ship_address? - - distributor_address = order.address_from_distributor - relevant_address_attrs.all? do |attr| - order.ship_address[attr] == distributor_address[attr] - end - end - - def save_ship_address_in_order(order) - return unless ship_address_updatable?(order) - - order.ship_address.update(ship_address.attributes.slice(*relevant_address_attrs)) - end - - def pending_shipment_with?(order, shipping_method_id) - return false unless order.shipment.present? && order.shipment.state == "pending" - - order.shipping_method.id == shipping_method_id - end -end diff --git a/app/services/order_tax_adjustments_fetcher.rb b/app/services/order_tax_adjustments_fetcher.rb deleted file mode 100644 index 72a20a2257..0000000000 --- a/app/services/order_tax_adjustments_fetcher.rb +++ /dev/null @@ -1,20 +0,0 @@ -# frozen_string_literal: true - -# Collects Tax Adjustments related to an order, and returns a hash with a total for each rate. - -class OrderTaxAdjustmentsFetcher - def initialize(order) - @order = order - end - - def totals(tax_adjustments = order.all_adjustments.tax) - tax_adjustments.each_with_object({}) do |adjustment, hash| - tax_rate = adjustment.originator - hash[tax_rate] = hash[tax_rate].to_f + adjustment.amount - end - end - - private - - attr_reader :order -end diff --git a/app/services/order_update_issues.rb b/app/services/order_update_issues.rb deleted file mode 100644 index bcdf3c644e..0000000000 --- a/app/services/order_update_issues.rb +++ /dev/null @@ -1,21 +0,0 @@ -# frozen_string_literal: true - -# Wrapper for a hash of issues encountered by instances of OrderSyncer and LineItemSyncer -# Used to report issues to the user when they attempt to update a subscription - -class OrderUpdateIssues - def initialize - @issues = {} - end - - delegate :[], :keys, to: :issues - - def add(order, issue) - @issues[order.id] ||= [] - @issues[order.id] << issue - end - - private - - attr_reader :issues -end diff --git a/app/services/order_workflow.rb b/app/services/order_workflow.rb deleted file mode 100644 index 815f3e1ee4..0000000000 --- a/app/services/order_workflow.rb +++ /dev/null @@ -1,95 +0,0 @@ -# frozen_string_literal: true - -class OrderWorkflow - attr_reader :order - - def initialize(order) - @order = order - end - - def complete - advance_to_state("complete", advance_order_options) - end - - def complete! - advance_order!(advance_order_options) - end - - def next(options = {}) - result = advance_order_one_step - - after_transition_hook(options) - - result - end - - def advance_to_payment - return unless order.before_payment_state? - - advance_to_state("payment", advance_order_options) - end - - def advance_checkout(options = {}) - advance_to = order.before_payment_state? ? "payment" : "confirmation" - - advance_to_state(advance_to, advance_order_options.merge(options)) - end - - private - - def advance_order_options - shipping_method_id = order.shipping_method.id if order.shipping_method.present? - { "shipping_method_id" => shipping_method_id } - end - - def advance_to_state(target_state, options = {}) - until order.state == target_state - break unless order.next - - after_transition_hook(options) - end - - order.state == target_state - end - - def advance_order!(options) - until order.completed? - order.next! - after_transition_hook(options) - end - end - - def advance_order_one_step - tries ||= 3 - order.next - rescue ActiveRecord::StaleObjectError - retry unless (tries -= 1).zero? - false - end - - def after_transition_hook(options) - if order.state == "delivery" - order.select_shipping_method(options["shipping_method_id"]) - end - - persist_all_payments if order.state == "payment" - end - - # When a payment fails, the order state machine stays in 'payment' and rollbacks all transactions - # This rollback also reverts the payment state from 'failed', 'void' or 'invalid' to 'pending' - # Despite the rollback, the in-memory payment still has the correct state, so we persist it - def persist_all_payments - order.payments.each do |payment| - in_memory_payment_state = payment.state - if different_from_db_payment_state?(in_memory_payment_state, payment.id) - payment.reload.update(state: in_memory_payment_state) - end - end - end - - # Verifies if the in-memory payment state is different from the one stored in the database - # This is be done without reloading the payment so that in-memory data is not changed - def different_from_db_payment_state?(in_memory_payment_state, payment_id) - in_memory_payment_state != Spree::Payment.find(payment_id).state - end -end diff --git a/app/services/orders/available_payment_methods_service.rb b/app/services/orders/available_payment_methods_service.rb new file mode 100644 index 0000000000..86b58ffc14 --- /dev/null +++ b/app/services/orders/available_payment_methods_service.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +require 'open_food_network/tag_rule_applicator' + +module Orders + class AvailablePaymentMethodsService + attr_reader :order, :customer + + delegate :distributor, + :order_cycle, + to: :order + + def initialize(order, customer = nil) + @order, @customer = order, customer + end + + def to_a + return [] if distributor.blank? + + payment_methods = payment_methods_before_tag_rules_applied + + applicator = OpenFoodNetwork::TagRuleApplicator + .new(distributor, "FilterPaymentMethods", customer&.tag_list) + applicator.filter(payment_methods) + end + + private + + def payment_methods_before_tag_rules_applied + if order_cycle.nil? || order_cycle.simple? + distributor.payment_methods + else + distributor.payment_methods.where( + id: available_distributor_payment_methods_ids + ) + end.available.select(&:configured?).uniq + end + + def available_distributor_payment_methods_ids + order_cycle.distributor_payment_methods + .where(distributor_id: distributor.id) + .select(:payment_method_id) + end + end +end diff --git a/app/services/orders/available_shipping_methods_service.rb b/app/services/orders/available_shipping_methods_service.rb new file mode 100644 index 0000000000..f264c2cca6 --- /dev/null +++ b/app/services/orders/available_shipping_methods_service.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +require 'open_food_network/tag_rule_applicator' + +module Orders + class AvailableShippingMethodsService + attr_reader :order, :customer + + delegate :distributor, :order_cycle, to: :order + + def initialize(order, customer = nil) + @order, @customer = order, customer + end + + def to_a + return [] if distributor.blank? + + filter_by_category(tag_rules.filter(shipping_methods)) + end + + private + + def filter_by_category(methods) + return methods unless OpenFoodNetwork::FeatureToggle.enabled?(:match_shipping_categories, + distributor&.owner) + + required_category_ids = order.variants.pluck(:shipping_category_id).to_set + return methods if required_category_ids.empty? + + methods.select do |method| + provided_category_ids = method.shipping_categories.pluck(:id).to_set + required_category_ids.subset?(provided_category_ids) + end + end + + def shipping_methods + if order_cycle.nil? || order_cycle.simple? + distributor.shipping_methods + else + distributor.shipping_methods.where( + id: available_distributor_shipping_methods_ids + ) + end.frontend.to_a.uniq + end + + def available_distributor_shipping_methods_ids + order_cycle.distributor_shipping_methods + .where(distributor_id: distributor.id) + .select(:shipping_method_id) + end + + def tag_rules + OpenFoodNetwork::TagRuleApplicator.new( + distributor, "FilterShippingMethods", customer&.tag_list + ) + end + end +end diff --git a/app/services/orders/bulk_cancel_service.rb b/app/services/orders/bulk_cancel_service.rb new file mode 100644 index 0000000000..fd2e867dcd --- /dev/null +++ b/app/services/orders/bulk_cancel_service.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module Orders + class BulkCancelService + def initialize(params, current_user) + @order_ids = params[:bulk_ids] + @current_user = current_user + @send_cancellation_email = params[:send_cancellation_email] + @restock_items = params[:restock_items] + end + + def call + editable_orders.where(id: @order_ids).each do |order| + order.send_cancellation_email = @send_cancellation_email + order.restock_items = @restock_items + order.cancel + end + end + + private + + def editable_orders + Permissions::Order.new(@current_user).editable_orders + end + end +end diff --git a/app/services/orders/capture_service.rb b/app/services/orders/capture_service.rb new file mode 100644 index 0000000000..abdcbb9f0a --- /dev/null +++ b/app/services/orders/capture_service.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +# Use `authorize! :admin order` before calling this service + +module Orders + class CaptureService + attr_reader :gateway_error + + def initialize(order) + @order = order + @gateway_error = nil + end + + def call + return false unless @order.payment_required? + return false unless (pending_payment = @order.pending_payments.first) + + pending_payment.capture! + rescue Spree::Core::GatewayError => e + @gateway_error = e + false + end + end +end diff --git a/app/services/orders/cart_reset_service.rb b/app/services/orders/cart_reset_service.rb new file mode 100644 index 0000000000..418b386aa7 --- /dev/null +++ b/app/services/orders/cart_reset_service.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: false + +# Resets an order by verifying it's state and fixing any issues + +module Orders + class CartResetService + def initialize(order, distributor_id) + @order = order + @distributor ||= Enterprise.is_distributor.find_by(permalink: distributor_id) || + Enterprise.is_distributor.find(distributor_id) + end + + def reset_distributor + if order.distributor && order.distributor != distributor + order.empty! + order.set_order_cycle! nil + end + order.distributor = distributor + end + + def reset_other!(current_user, current_customer) + reset_user_and_customer(current_user) + reset_order_cycle(current_customer) + order.save! + end + + private + + attr_reader :order, :distributor, :current_user + + def reset_user_and_customer(current_user) + return unless current_user + + order.associate_user!(current_user) if order.user.blank? || order.email.blank? + end + + def reset_order_cycle(current_customer) + listed_order_cycles = Shop::OrderCyclesList.active_for(distributor, current_customer) + + if order_cycle_not_listed?(order.order_cycle, listed_order_cycles) + order.order_cycle = nil + order.empty! + end + + select_default_order_cycle(order, listed_order_cycles) + end + + def order_cycle_not_listed?(order_cycle, listed_order_cycles) + order_cycle.present? && listed_order_cycles.exclude?(order_cycle) + end + + # If no OC is selected and there is only one in the list of OCs, selects it + def select_default_order_cycle(order, listed_order_cycles) + return unless order.order_cycle.blank? && listed_order_cycles.size == 1 + + order.order_cycle = listed_order_cycles.first + end + end +end diff --git a/app/services/orders/checkout_restart_service.rb b/app/services/orders/checkout_restart_service.rb new file mode 100644 index 0000000000..793d8a7efe --- /dev/null +++ b/app/services/orders/checkout_restart_service.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +# Resets the passed order to cart state while clearing associated payments and shipments + +module Orders + class CheckoutRestartService + def initialize(order) + @order = order + end + + def call + return if order.cart? + + reset_state_to_cart + clear_shipments + clear_payments + + order.reload.update_order! + end + + private + + attr_reader :order + + def reset_state_to_cart + order.restart_checkout! + end + + def clear_shipments + order.shipments.with_state(:pending).destroy_all + end + + def clear_payments + order.payments.with_state(:checkout).destroy_all + end + end +end diff --git a/app/services/orders/compare_invoice_service.rb b/app/services/orders/compare_invoice_service.rb new file mode 100644 index 0000000000..797506d21c --- /dev/null +++ b/app/services/orders/compare_invoice_service.rb @@ -0,0 +1,88 @@ +# frozen_string_literal: true + +module Orders + class CompareInvoiceService + attr_reader :order + + def initialize(order) + @order = order + end + + def can_generate_new_invoice? + return true if invoices.empty? + + # We'll use a recursive BFS algorithm to find if the invoice is outdated + # the root will be the order + # On each node, we'll a list of relevant attributes that will be used on the comparison + different?(current_state_invoice, latest_invoice, invoice_generation_selector) + end + + def can_update_latest_invoice? + return false if invoices.empty? + + different?(current_state_invoice, latest_invoice, invoice_update_selector) + end + + private + + def different?(node1, node2, attributes_selector) + simple_values1, presenters1 = attributes_selector.call(node1) + simple_values2, presenters2 = attributes_selector.call(node2) + return true if simple_values1 != simple_values2 + + return true if presenters1.size != presenters2.size + + presenters1.zip(presenters2).any? do |presenter1, presenter2| + different?(presenter1, presenter2, attributes_selector) + end + end + + def invoice_generation_selector + values_selector(:invoice_generation_values) + end + + def invoice_update_selector + values_selector(:invoice_update_values) + end + + def values_selector(attribute) + proc do |node| + return [[], []] unless node.respond_to?(attribute) + + grouped = node.public_send(attribute).group_by(&grouper) + [grouped[:simple] || [], grouped[:presenters]&.flatten || []] + end + end + + def grouper + proc do |value| + if value.is_a?(Array) || value.class.to_s.starts_with?("Invoice::DataPresenter") + :presenters + else + :simple + end + end + end + + def current_state_invoice + @current_state_invoice ||= Invoice.new( + order:, + data: serialize_for_invoice, + date: Time.zone.today, + number: invoices.count + 1 + ).presenter + end + + def invoices + order.invoices + end + + def latest_invoice + @latest_invoice ||= invoices.first.presenter + end + + def serialize_for_invoice + InvoiceDataGenerator.new(order).serialize_for_invoice + end + end +end diff --git a/app/services/orders/customer_cancellation_service.rb b/app/services/orders/customer_cancellation_service.rb new file mode 100644 index 0000000000..7385139db0 --- /dev/null +++ b/app/services/orders/customer_cancellation_service.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module Orders + class CustomerCancellationService + def initialize(order) + @order = order + end + + def call + return unless order.cancel + + Spree::OrderMailer.cancel_email_for_shop(order).deliver_later + end + + private + + attr_reader :order + end +end diff --git a/app/services/orders/factory_service.rb b/app/services/orders/factory_service.rb new file mode 100644 index 0000000000..eef377734b --- /dev/null +++ b/app/services/orders/factory_service.rb @@ -0,0 +1,99 @@ +# frozen_string_literal: true + +require 'open_food_network/scope_variant_to_hub' + +# Builds orders based on a set of attributes +# There are some idiosyncracies in the order creation process, +# and it is nice to have them dealt with in one place. + +module Orders + class FactoryService + def initialize(attrs, opts = {}) + @attrs = attrs.with_indifferent_access + @opts = opts.with_indifferent_access + end + + def create + create_order + set_user + build_line_items + set_addresses + create_shipment + set_shipping_method + create_payment + + @order + end + + private + + attr_reader :attrs, :opts + + def customer + @customer ||= Customer.find(attrs[:customer_id]) + end + + def shop + @shop ||= Enterprise.find(attrs[:distributor_id]) + end + + def create_order + @order = Spree::Order.create!(create_attrs) + end + + def create_attrs + create_attrs = attrs.slice(:customer_id, :order_cycle_id, :distributor_id) + create_attrs[:email] = customer.email + create_attrs + end + + def build_line_items + attrs[:line_items].each do |li| + next unless variant = Spree::Variant.find_by(id: li[:variant_id]) + + scoper.scope(variant) + li[:quantity] = stock_limited_quantity(variant.on_demand, variant.on_hand, li[:quantity]) + li[:price] = variant.price + build_item_from(li) + end + end + + def build_item_from(attrs) + @order.line_items.build( + attrs.merge(skip_stock_check: opts[:skip_stock_check]) + ) + end + + def set_user + @order.update_attribute(:user_id, customer.user_id) + end + + def set_addresses + @order.update(attrs.slice(:bill_address_attributes, :ship_address_attributes)) + end + + def create_shipment + @order.create_proposed_shipments + end + + def set_shipping_method + @order.select_shipping_method(attrs[:shipping_method_id]) + end + + def create_payment + @order.recreate_all_fees! + @order.payments.create(payment_method_id: attrs[:payment_method_id], + amount: @order.reload.total) + end + + def stock_limited_quantity(variant_on_demand, variant_on_hand, requested) + return requested if opts[:skip_stock_check] || variant_on_demand + + [variant_on_hand, requested].min + end + + def scoper + @scoper ||= OpenFoodNetwork::ScopeVariantToHub.new(shop) + end + end +end diff --git a/app/services/orders/fetch_adjustments_service.rb b/app/services/orders/fetch_adjustments_service.rb new file mode 100644 index 0000000000..8cb3d76c41 --- /dev/null +++ b/app/services/orders/fetch_adjustments_service.rb @@ -0,0 +1,81 @@ +# frozen_string_literal: true + +# This service allows orders with eager-loaded adjustment objects to calculate various adjustment +# types without triggering additional queries. +# +# For example; `order.adjustments.shipping.sum(:amount)` would normally trigger a new query +# regardless of whether or not adjustments have been preloaded, as `#shipping` is an adjustment +# scope, eg; `scope :shipping, where(originator_type: 'Spree::ShippingMethod')`. +# +# Here the adjustment scopes are moved to a shared module, and `adjustments.loaded?` is used to +# check if the objects have already been fetched and initialized. If they have, `order.adjustments` +# will be an Array, and we can select the required objects without hitting the database. If not, it +# will fetch the adjustments via their scopes as normal. + +module Orders + class FetchAdjustmentsService + include AdjustmentScopes + + def initialize(order) + @order = order + end + + def admin_and_handling_total + admin_and_handling_fees.map(&:amount).sum + end + + def payment_fee + sum_adjustments "payment_fee" + end + + def ship_total + sum_adjustments "shipping" + end + + private + + attr_reader :order + + def adjustments + order.all_adjustments + end + + def adjustments_eager_loaded? + adjustments.loaded? + end + + def sum_adjustments(scope) + collect_adjustments(scope).map(&:amount).sum + end + + def collect_adjustments(scope) + if adjustments_eager_loaded? + adjustment_scope = public_send("#{scope}_scope") + + # Adjustments are already loaded here, this block is using `Array#select` + adjustments.select do |adjustment| + match_by_scope(adjustment, adjustment_scope) && match_by_scope(adjustment, eligible_scope) + end + else + adjustments.where(nil).eligible.public_send scope + end + end + + def admin_and_handling_fees + if adjustments_eager_loaded? + adjustments.select do |adjustment| + match_by_scope(adjustment, eligible_scope) && + adjustment.originator_type == 'EnterpriseFee' && + adjustment.adjustable_type != 'Spree::LineItem' + end + else + adjustments.eligible. + where("originator_type = ? AND adjustable_type != ?", 'EnterpriseFee', 'Spree::LineItem') + end + end + + def match_by_scope(adjustment, scope) + adjustment.public_send(scope.keys.first) == scope.values.first + end + end +end diff --git a/app/services/orders/fetch_tax_adjustments_service.rb b/app/services/orders/fetch_tax_adjustments_service.rb new file mode 100644 index 0000000000..0aef4cc319 --- /dev/null +++ b/app/services/orders/fetch_tax_adjustments_service.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +# Collects Tax Adjustments related to an order, and returns a hash with a total for each rate. + +module Orders + class FetchTaxAdjustmentsService + def initialize(order) + @order = order + end + + def totals(tax_adjustments = order.all_adjustments.tax) + tax_adjustments.each_with_object({}) do |adjustment, hash| + tax_rate = adjustment.originator + hash[tax_rate] = hash[tax_rate].to_f + adjustment.amount + end + end + + private + + attr_reader :order + end +end diff --git a/app/services/orders/find_payment_service.rb b/app/services/orders/find_payment_service.rb new file mode 100644 index 0000000000..fe8eac2b5a --- /dev/null +++ b/app/services/orders/find_payment_service.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +module Orders + class FindPaymentService + def initialize(order) + @order = order + end + + def last_payment + last(@order.payments) + end + + def last_pending_payment + last(@order.pending_payments) + end + + private + + # `max_by` avoids additional database queries when payments are loaded + # already. There is usually only one payment and this shouldn't cause + # any overhead compared to `order(:created_at).last`. Using `last` + # without order is not deterministic. + # + # We are not using `updated_at` because all payments are touched when the + # order is updated and then all payments have the same `updated_at` value. + def last(payments) + payments.max_by(&:created_at) + end + end +end diff --git a/app/services/orders/generate_invoice_service.rb b/app/services/orders/generate_invoice_service.rb new file mode 100644 index 0000000000..99cf17f781 --- /dev/null +++ b/app/services/orders/generate_invoice_service.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +module Orders + class GenerateInvoiceService + def initialize(order) + @order = order + end + + def generate_or_update_latest_invoice + if comparator.can_generate_new_invoice? + order.invoices.create!( + date: Time.zone.today, + number: total_invoices_created_by_distributor + 1, + data: invoice_data + ) + elsif comparator.can_update_latest_invoice? + order.invoices.latest.update!( + date: Time.zone.today, + data: invoice_data + ) + end + end + + private + + attr_reader :order + + def comparator + @comparator ||= Orders::CompareInvoiceService.new(order) + end + + def invoice_data + @invoice_data ||= InvoiceDataGenerator.new(order).generate + end + + def total_invoices_created_by_distributor + Invoice.joins(:order).where(order: { distributor: order.distributor }).count + end + end +end diff --git a/app/services/orders/handle_fees_service.rb b/app/services/orders/handle_fees_service.rb new file mode 100644 index 0000000000..09ee04f1a2 --- /dev/null +++ b/app/services/orders/handle_fees_service.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +module Orders + class HandleFeesService + attr_reader :order + + delegate :distributor, :order_cycle, to: :order + + def initialize(order) + @order = order + end + + def recreate_all_fees! + # `with_lock` acquires an exclusive row lock on order so no other + # requests can update it until the transaction is commited. + # See https://github.com/rails/rails/blob/3-2-stable/activerecord/lib/active_record/locking/pessimistic.rb#L69 + # and https://www.postgresql.org/docs/current/static/sql-select.html#SQL-FOR-UPDATE-SHARE + order.with_lock do + EnterpriseFee.clear_all_adjustments order + + create_line_item_fees! + create_order_fees! + end + + tax_enterprise_fees! unless order.before_payment_state? + order.update_order! + end + + def create_line_item_fees! + order.line_items.includes(variant: :product).each do |line_item| + if provided_by_order_cycle? line_item + calculator.create_line_item_adjustments_for line_item + end + end + end + + def create_order_fees! + return unless order_cycle + + calculator.create_order_adjustments_for order + end + + def tax_enterprise_fees! + Spree::TaxRate.adjust(order, order.all_adjustments.enterprise_fee) + end + + def update_line_item_fees!(line_item) + line_item.adjustments.enterprise_fee.each do |fee| + fee.update_adjustment!(line_item, force: true) + end + end + + def update_order_fees! + order.adjustments.enterprise_fee.where(adjustable_type: 'Spree::Order').each do |fee| + fee.update_adjustment!(order, force: true) + end + end + + private + + def calculator + @calculator ||= OpenFoodNetwork::EnterpriseFeeCalculator.new(distributor, order_cycle) + end + + def provided_by_order_cycle?(line_item) + @order_cycle_variant_ids ||= order_cycle&.variants&.map(&:id) || [] + @order_cycle_variant_ids.include? line_item.variant_id + end + end +end diff --git a/app/services/orders/mask_data_service.rb b/app/services/orders/mask_data_service.rb new file mode 100644 index 0000000000..35cbc7482b --- /dev/null +++ b/app/services/orders/mask_data_service.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +module Orders + class MaskDataService + def initialize(order) + @order = order + end + + def call + mask_customer_names unless customer_names_allowed? + mask_contact_data + end + + private + + attr_accessor :order + + def customer_names_allowed? + order.distributor.show_customer_names_to_suppliers + end + + def mask_customer_names + order.bill_address&.assign_attributes(firstname: I18n.t('admin.reports.hidden'), + lastname: "") + order.ship_address&.assign_attributes(firstname: I18n.t('admin.reports.hidden'), + lastname: "") + end + + def mask_contact_data + order.bill_address&.assign_attributes(phone: "", address1: "", address2: "", + city: "", zipcode: "", state: nil) + order.ship_address&.assign_attributes(phone: "", address1: "", address2: "", + city: "", zipcode: "", state: nil) + order.assign_attributes(email: I18n.t('admin.reports.hidden')) + end + end +end diff --git a/app/services/orders/sync_service.rb b/app/services/orders/sync_service.rb new file mode 100644 index 0000000000..590e622209 --- /dev/null +++ b/app/services/orders/sync_service.rb @@ -0,0 +1,141 @@ +# frozen_string_literal: true + +# Responsible for ensuring that any updates to a Subscription are propagated to any +# orders belonging to that Subscription which have been instantiated + +module Orders + class SyncService + attr_reader :order_update_issues + + def initialize(subscription) + @subscription = subscription + @order_update_issues = Orders::UpdateIssuesService.new + @line_item_syncer = LineItemSyncer.new(subscription, order_update_issues) + end + + def sync! + orders_in_order_cycles_not_closed.all? do |order| + order.assign_attributes(customer_id:, email: customer&.email, + distributor_id: shop_id) + update_associations_for(order) + line_item_syncer.sync!(order) + order.update_order! + order.save + end + end + + private + + attr_reader :subscription, :line_item_syncer + + delegate :orders, :bill_address, :ship_address, :subscription_line_items, to: :subscription + delegate :shop_id, :customer, :customer_id, to: :subscription + delegate :shipping_method, :shipping_method_id, + :payment_method, :payment_method_id, to: :subscription + delegate :shipping_method_id_changed?, :shipping_method_id_was, to: :subscription + delegate :payment_method_id_changed?, :payment_method_id_was, to: :subscription + + def update_associations_for(order) + update_bill_address_for(order) if bill_address.changes.keys.intersect?(relevant_address_attrs) + update_shipment_for(order) if shipping_method_id_changed? + update_ship_address_for(order) + update_payment_for(order) if payment_method_id_changed? + end + + def orders_in_order_cycles_not_closed + return @orders_in_order_cycles_not_closed unless @orders_in_order_cycles_not_closed.nil? + + @orders_in_order_cycles_not_closed = orders.joins(:order_cycle). + merge(OrderCycle.not_closed).readonly(false) + end + + def update_bill_address_for(order) + unless addresses_match?(order.bill_address, bill_address) + return order_update_issues.add(order, I18n.t('bill_address')) + end + + order.bill_address.update(bill_address.attributes.slice(*relevant_address_attrs)) + end + + def update_payment_for(order) + payment = order.payments. + with_state('checkout').where(payment_method_id: payment_method_id_was).last + if payment + payment&.void_transaction! + order.payments.create(payment_method_id:, amount: order.reload.total) + else + unless order.payments.with_state('checkout').where(payment_method_id:).any? + order_update_issues.add(order, I18n.t('admin.payment_method')) + end + end + end + + def update_shipment_for(order) + return if pending_shipment_with?(order, shipping_method_id) # No need to do anything. + + if pending_shipment_with?(order, shipping_method_id_was) + order.select_shipping_method(shipping_method_id) + else + order_update_issues.add(order, I18n.t('admin.shipping_method')) + end + end + + def update_ship_address_for(order) + # The conditions here are to achieve the same behaviour in earlier versions of Spree, where + # switching from pick-up to delivery affects whether simultaneous changes to shipping address + # are ignored or not. + pickup_to_delivery = force_ship_address_required?(order) + if (!pickup_to_delivery || order.shipment.present?) && + ship_address.changes.keys.intersect?(relevant_address_attrs) + save_ship_address_in_order(order) + end + return unless !pickup_to_delivery || order.shipment.blank? + + order.updater.shipping_address_from_distributor + end + + def relevant_address_attrs + ["firstname", "lastname", "address1", "zipcode", "city", "state_id", "country_id", "phone"] + end + + def addresses_match?(order_address, subscription_address) + relevant_address_attrs.all? do |attr| + order_address[attr] == subscription_address.public_send("#{attr}_was") || + order_address[attr] == subscription_address[attr] + end + end + + def ship_address_updatable?(order) + return true if force_ship_address_required?(order) + return false unless order.shipping_method.require_ship_address? + return true if addresses_match?(order.ship_address, ship_address) + + order_update_issues.add(order, I18n.t('ship_address')) + false + end + + # This returns true when the shipping method on the subscription has changed + # to a delivery (ie. a shipping address is required) AND the existing shipping + # address on the order matches the shop's address + def force_ship_address_required?(order) + return false unless shipping_method.require_ship_address? + + distributor_address = order.address_from_distributor + relevant_address_attrs.all? do |attr| + order.ship_address[attr] == distributor_address[attr] + end + end + + def save_ship_address_in_order(order) + return unless ship_address_updatable?(order) + + order.ship_address.update(ship_address.attributes.slice(*relevant_address_attrs)) + end + + def pending_shipment_with?(order, shipping_method_id) + return false unless order.shipment.present? && order.shipment.state == "pending" + + order.shipping_method.id == shipping_method_id + end + end +end diff --git a/app/services/orders/update_issues_service.rb b/app/services/orders/update_issues_service.rb new file mode 100644 index 0000000000..0f0eba5277 --- /dev/null +++ b/app/services/orders/update_issues_service.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +# Wrapper for a hash of issues encountered by instances of Orders::SyncService and LineItemSyncer +# Used to report issues to the user when they attempt to update a subscription + +module Orders + class UpdateIssuesService + def initialize + @issues = {} + end + + delegate :[], :keys, to: :issues + + def add(order, issue) + @issues[order.id] ||= [] + @issues[order.id] << issue + end + + private + + attr_reader :issues + end +end diff --git a/app/services/orders/workflow_service.rb b/app/services/orders/workflow_service.rb new file mode 100644 index 0000000000..99eec1bd17 --- /dev/null +++ b/app/services/orders/workflow_service.rb @@ -0,0 +1,98 @@ +# frozen_string_literal: true + +module Orders + class WorkflowService + attr_reader :order + + def initialize(order) + @order = order + end + + def complete + advance_to_state("complete", advance_order_options) + end + + def complete! + advance_order!(advance_order_options) + end + + def next(options = {}) + result = advance_order_one_step + + after_transition_hook(options) + + result + end + + def advance_to_payment + return unless order.before_payment_state? + + advance_to_state("payment", advance_order_options) + end + + def advance_checkout(options = {}) + advance_to = order.before_payment_state? ? "payment" : "confirmation" + + advance_to_state(advance_to, advance_order_options.merge(options)) + end + + private + + def advance_order_options + shipping_method_id = order.shipping_method.id if order.shipping_method.present? + { "shipping_method_id" => shipping_method_id } + end + + def advance_to_state(target_state, options = {}) + until order.state == target_state + break unless order.next + + after_transition_hook(options) + end + + order.state == target_state + end + + def advance_order!(options) + until order.completed? + order.next! + after_transition_hook(options) + end + end + + def advance_order_one_step + tries ||= 3 + order.next + rescue ActiveRecord::StaleObjectError + retry unless (tries -= 1).zero? + false + end + + def after_transition_hook(options) + if order.state == "delivery" + order.select_shipping_method(options["shipping_method_id"]) + end + + persist_all_payments if order.state == "payment" + end + + # When a payment fails, the order state machine stays in 'payment' + # and rollbacks all transactions + # This rollback also reverts the payment state from 'failed', 'void' or 'invalid' to 'pending' + # Despite the rollback, the in-memory payment still has the correct state, so we persist it + def persist_all_payments + order.payments.each do |payment| + in_memory_payment_state = payment.state + if different_from_db_payment_state?(in_memory_payment_state, payment.id) + payment.reload.update(state: in_memory_payment_state) + end + end + end + + # Verifies if the in-memory payment state is different from the one stored in the database + # This is be done without reloading the payment so that in-memory data is not changed + def different_from_db_payment_state?(in_memory_payment_state, payment_id) + in_memory_payment_state != Spree::Payment.find(payment_id).state + end + end +end diff --git a/app/services/orders_bulk_cancel_service.rb b/app/services/orders_bulk_cancel_service.rb deleted file mode 100644 index a788183ffc..0000000000 --- a/app/services/orders_bulk_cancel_service.rb +++ /dev/null @@ -1,24 +0,0 @@ -# frozen_string_literal: true - -class OrdersBulkCancelService - def initialize(params, current_user) - @order_ids = params[:bulk_ids] - @current_user = current_user - @send_cancellation_email = params[:send_cancellation_email] - @restock_items = params[:restock_items] - end - - def call - editable_orders.where(id: @order_ids).each do |order| - order.send_cancellation_email = @send_cancellation_email - order.restock_items = @restock_items - order.cancel - end - end - - private - - def editable_orders - Permissions::Order.new(@current_user).editable_orders - end -end diff --git a/app/services/place_proxy_order.rb b/app/services/place_proxy_order.rb index aaa88f620d..03bd379d9d 100644 --- a/app/services/place_proxy_order.rb +++ b/app/services/place_proxy_order.rb @@ -87,7 +87,7 @@ class PlaceProxyOrder end def move_to_completion - OrderWorkflow.new(order).complete! + Orders::WorkflowService.new(order).complete! end def send_placement_email diff --git a/app/services/process_payment_intent.rb b/app/services/process_payment_intent.rb index be6d4f233f..eb4429edbb 100644 --- a/app/services/process_payment_intent.rb +++ b/app/services/process_payment_intent.rb @@ -58,7 +58,7 @@ class ProcessPaymentIntent def process_payment return unless order.process_payments! - OrderWorkflow.new(order).complete + Orders::WorkflowService.new(order).complete end def ready_for_capture? diff --git a/app/services/products_renderer.rb b/app/services/products_renderer.rb index 99745ca451..22db37687a 100644 --- a/app/services/products_renderer.rb +++ b/app/services/products_renderer.rb @@ -64,7 +64,7 @@ class ProductsRenderer end def distributed_products - OrderCycleDistributedProducts.new(distributor, order_cycle, customer) + OrderCycles::DistributedProductsService.new(distributor, order_cycle, customer) end def products_order diff --git a/app/services/shop/order_cycles_list.rb b/app/services/shop/order_cycles_list.rb index 5b0a6930cd..dd505c569e 100644 --- a/app/services/shop/order_cycles_list.rb +++ b/app/services/shop/order_cycles_list.rb @@ -12,8 +12,8 @@ module Shop def self.ready_for_checkout_for(distributor, customer) new(distributor, customer).call.select do |order_cycle| order = Spree::Order.new(distributor:, order_cycle:) - OrderAvailablePaymentMethods.new(order, customer).to_a.any? && - OrderAvailableShippingMethods.new(order, customer).to_a.any? + Orders::AvailablePaymentMethodsService.new(order, customer).to_a.any? && + Orders::AvailableShippingMethodsService.new(order, customer).to_a.any? end end diff --git a/engines/order_management/app/services/order_management/order/stripe_sca_payment_authorize.rb b/engines/order_management/app/services/order_management/order/stripe_sca_payment_authorize.rb index cfecbc7de9..0763a32b1a 100644 --- a/engines/order_management/app/services/order_management/order/stripe_sca_payment_authorize.rb +++ b/engines/order_management/app/services/order_management/order/stripe_sca_payment_authorize.rb @@ -12,7 +12,7 @@ module OrderManagement def initialize(order, payment: nil, off_session: false, notify_hub: false) @order = order - @payment = payment || OrderPaymentFinder.new(order).last_pending_payment + @payment = payment || Orders::FindPaymentService.new(order).last_pending_payment @off_session = off_session @notify_hub = notify_hub end diff --git a/engines/order_management/app/services/order_management/subscriptions/form.rb b/engines/order_management/app/services/order_management/subscriptions/form.rb index 53c0e615cd..74aa78d72f 100644 --- a/engines/order_management/app/services/order_management/subscriptions/form.rb +++ b/engines/order_management/app/services/order_management/subscriptions/form.rb @@ -15,7 +15,7 @@ module OrderManagement @options = options @estimator = OrderManagement::Subscriptions::Estimator.new(subscription) @validator = OrderManagement::Subscriptions::Validator.new(subscription) - @order_syncer = OrderSyncer.new(subscription) + @order_syncer = Orders::SyncService.new(subscription) end def save diff --git a/engines/order_management/app/services/order_management/subscriptions/payment_setup.rb b/engines/order_management/app/services/order_management/subscriptions/payment_setup.rb index fea4da84e5..15cab96ee2 100644 --- a/engines/order_management/app/services/order_management/subscriptions/payment_setup.rb +++ b/engines/order_management/app/services/order_management/subscriptions/payment_setup.rb @@ -18,7 +18,7 @@ module OrderManagement private def create_payment - payment = OrderPaymentFinder.new(@order).last_pending_payment + payment = Orders::FindPaymentService.new(@order).last_pending_payment return payment if payment.present? @order.payments.create( diff --git a/engines/order_management/app/services/order_management/subscriptions/proxy_order_syncer.rb b/engines/order_management/app/services/order_management/subscriptions/proxy_order_syncer.rb index 9c50e175d5..e906a0ed16 100644 --- a/engines/order_management/app/services/order_management/subscriptions/proxy_order_syncer.rb +++ b/engines/order_management/app/services/order_management/subscriptions/proxy_order_syncer.rb @@ -14,7 +14,7 @@ module OrderManagement when ActiveRecord::Relation @subscriptions = subscriptions.not_ended.not_canceled else - raise "ProxyOrderSyncer must be initialized with " \ + raise "ProxyOrders::SyncService must be initialized with " \ "an instance of Subscription or ActiveRecord::Relation" end end diff --git a/engines/order_management/app/services/order_management/subscriptions/stripe_payment_setup.rb b/engines/order_management/app/services/order_management/subscriptions/stripe_payment_setup.rb index df79b45ddd..e3d01bdfc1 100644 --- a/engines/order_management/app/services/order_management/subscriptions/stripe_payment_setup.rb +++ b/engines/order_management/app/services/order_management/subscriptions/stripe_payment_setup.rb @@ -5,7 +5,7 @@ module OrderManagement class StripePaymentSetup def initialize(order) @order = order - @payment = OrderPaymentFinder.new(@order).last_pending_payment + @payment = Orders::FindPaymentService.new(@order).last_pending_payment end def call! diff --git a/lib/reporting/line_items.rb b/lib/reporting/line_items.rb index fe56194417..233c965c2a 100644 --- a/lib/reporting/line_items.rb +++ b/lib/reporting/line_items.rb @@ -36,7 +36,7 @@ module Reporting without_editable_line_items = line_items - editable_line_items(line_items) without_editable_line_items.each do |line_item| - OrderDataMasker.new(line_item.order).call + Orders::MaskDataService.new(line_item.order).call end line_items diff --git a/lib/reporting/reports/orders_and_distributors/base.rb b/lib/reporting/reports/orders_and_distributors/base.rb index 9225096680..2f54235d5e 100644 --- a/lib/reporting/reports/orders_and_distributors/base.rb +++ b/lib/reporting/reports/orders_and_distributors/base.rb @@ -43,7 +43,7 @@ module Reporting editable_orders_ids = permissions.editable_orders.select(&:id).map(&:id) orders .filter { |order| order.in?(editable_orders_ids) } - .each { |order| OrderDataMasker.new(order).call } + .each { |order| Orders::MaskDataService.new(order).call } # Get Line Items orders.map(&:line_items).flatten end diff --git a/lib/reporting/reports/sales_tax/tax_rates.rb b/lib/reporting/reports/sales_tax/tax_rates.rb index 83bd3f2eb0..8c82d44b66 100644 --- a/lib/reporting/reports/sales_tax/tax_rates.rb +++ b/lib/reporting/reports/sales_tax/tax_rates.rb @@ -11,7 +11,7 @@ module Reporting total_excl_vat: proc { |order| order.total - order.total_tax } } add_key_for_each_rate(result, proc { |rate| - proc { |order| OrderTaxAdjustmentsFetcher.new(order).totals.fetch(rate, 0) } + proc { |order| Orders::FetchTaxAdjustmentsService.new(order).totals.fetch(rate, 0) } }) other = { total_tax: proc { |order| order.total_tax }, diff --git a/lib/tasks/sample_data/order_factory.rb b/lib/tasks/sample_data/order_factory.rb index 39cfdb2996..ef670aa5e0 100644 --- a/lib/tasks/sample_data/order_factory.rb +++ b/lib/tasks/sample_data/order_factory.rb @@ -51,7 +51,7 @@ module SampleData def create_complete_order order = create_cart_order - OrderWorkflow.new(order).complete + Orders::WorkflowService.new(order).complete order end diff --git a/spec/controllers/admin/bulk_line_items_controller_spec.rb b/spec/controllers/admin/bulk_line_items_controller_spec.rb index 9fab630c8e..15e540c97b 100644 --- a/spec/controllers/admin/bulk_line_items_controller_spec.rb +++ b/spec/controllers/admin/bulk_line_items_controller_spec.rb @@ -390,7 +390,7 @@ describe Admin::BulkLineItemsController, type: :controller do order.shipments.map(&:refresh_rates) order.select_shipping_method(shipping_method.id) - OrderWorkflow.new(order).advance_to_payment + Orders::WorkflowService.new(order).advance_to_payment order.finalize! order.recreate_all_fees! order.create_tax_charge! diff --git a/spec/controllers/admin/order_cycles_controller_spec.rb b/spec/controllers/admin/order_cycles_controller_spec.rb index 27cfbff2e8..fd154b7118 100644 --- a/spec/controllers/admin/order_cycles_controller_spec.rb +++ b/spec/controllers/admin/order_cycles_controller_spec.rb @@ -160,12 +160,12 @@ module Admin let(:shop) { create(:distributor_enterprise) } context "as a manager of a shop" do - let(:form_mock) { instance_double(OrderCycleForm) } + let(:form_mock) { instance_double(OrderCycles::FormService) } let(:params) { { as: :json, order_cycle: {} } } before do controller_login_as_enterprise_user([shop]) - allow(OrderCycleForm).to receive(:new) { form_mock } + allow(OrderCycles::FormService).to receive(:new) { form_mock } end context "when creation is successful" do @@ -203,10 +203,10 @@ module Admin describe "update" do let(:order_cycle) { create(:simple_order_cycle) } let(:coordinator) { order_cycle.coordinator } - let(:form_mock) { instance_double(OrderCycleForm) } + let(:form_mock) { instance_double(OrderCycles::FormService) } before do - allow(OrderCycleForm).to receive(:new) { form_mock } + allow(OrderCycles::FormService).to receive(:new) { form_mock } end context "as a manager of the coordinator" do @@ -275,7 +275,7 @@ module Admin end it "can update preference product_selection_from_coordinator_inventory_only" do - expect(OrderCycleForm).to receive(:new). + expect(OrderCycles::FormService).to receive(:new). with(order_cycle, { "preferred_product_selection_from_coordinator_inventory_only" => true }, anything) { form_mock } @@ -288,7 +288,7 @@ module Admin end it "can update preference automatic_notifications" do - expect(OrderCycleForm).to receive(:new). + expect(OrderCycles::FormService).to receive(:new). with(order_cycle, { "automatic_notifications" => true }, anything) { form_mock } @@ -324,7 +324,7 @@ module Admin format: :json, id: order_cycle.id, order_cycle: allowed.merge(restricted) } } - let(:form_mock) { instance_double(OrderCycleForm, save: true) } + let(:form_mock) { instance_double(OrderCycles::FormService, save: true) } before { allow(controller).to receive(:spree_current_user) { user } } @@ -333,7 +333,7 @@ module Admin let(:expected) { [order_cycle, allowed.merge(restricted), user] } it "allows me to update exchange information for exchanges, name and dates" do - expect(OrderCycleForm).to receive(:new).with(*expected) { form_mock } + expect(OrderCycles::FormService).to receive(:new).with(*expected) { form_mock } spree_put :update, params end end @@ -343,7 +343,7 @@ module Admin let(:expected) { [order_cycle, allowed, user] } it "allows me to update exchange information for exchanges, but not name or dates" do - expect(OrderCycleForm).to receive(:new).with(*expected) { form_mock } + expect(OrderCycles::FormService).to receive(:new).with(*expected) { form_mock } spree_put :update, params end end diff --git a/spec/controllers/admin/proxy_orders_controller_spec.rb b/spec/controllers/admin/proxy_orders_controller_spec.rb index a19f94a14a..6e505530b6 100644 --- a/spec/controllers/admin/proxy_orders_controller_spec.rb +++ b/spec/controllers/admin/proxy_orders_controller_spec.rb @@ -83,7 +83,7 @@ describe Admin::ProxyOrdersController, type: :controller do before do # Processing order to completion allow(Spree::OrderMailer).to receive(:cancel_email) { double(:email, deliver_later: true) } - OrderWorkflow.new(order).complete! + Orders::WorkflowService.new(order).complete! proxy_order.reload proxy_order.cancel allow(controller).to receive(:spree_current_user) { user } diff --git a/spec/controllers/checkout_controller_spec.rb b/spec/controllers/checkout_controller_spec.rb index a56d97e549..4f948cdefa 100644 --- a/spec/controllers/checkout_controller_spec.rb +++ b/spec/controllers/checkout_controller_spec.rb @@ -256,7 +256,7 @@ describe CheckoutController, type: :controller do order.bill_address = address order.ship_address = address order.select_shipping_method shipping_method.id - OrderWorkflow.new(order).advance_to_payment + Orders::WorkflowService.new(order).advance_to_payment end context "with incomplete data" do @@ -387,7 +387,7 @@ describe CheckoutController, type: :controller do order.bill_address = address order.ship_address = address order.select_shipping_method shipping_method.id - OrderWorkflow.new(order).advance_to_payment + Orders::WorkflowService.new(order).advance_to_payment order.payments << build(:payment, amount: order.total, payment_method:) order.next @@ -459,7 +459,7 @@ describe CheckoutController, type: :controller do allow(order).to receive(:distributor).and_return(distributor) order.update(order_cycle:) - allow(OrderCycleDistributedVariants).to receive(:new).and_return( + allow(OrderCycles::DistributedVariantsService).to receive(:new).and_return( order_cycle_distributed_variants ) end diff --git a/spec/controllers/payment_gateways/stripe_controller_spec.rb b/spec/controllers/payment_gateways/stripe_controller_spec.rb index 72ceef6bfe..9b2e3233d9 100644 --- a/spec/controllers/payment_gateways/stripe_controller_spec.rb +++ b/spec/controllers/payment_gateways/stripe_controller_spec.rb @@ -11,7 +11,9 @@ module PaymentGateways let!(:order) { create(:order_with_totals, distributor:, order_cycle:) } let(:exchange) { order_cycle.exchanges.to_enterprises(distributor).outgoing.first } - let(:order_cycle_distributed_variants) { instance_double(OrderCycleDistributedVariants) } + let(:order_cycle_distributed_variants) { + instance_double(OrderCycles::DistributedVariantsService) + } before do exchange.variants << order.line_items.first.variant @@ -305,11 +307,11 @@ completed due to stock issues." context "with an invalid last payment" do let(:payment_intent) { "valid" } - let(:finder) { instance_double(OrderPaymentFinder, last_payment: payment) } + let(:finder) { instance_double(Orders::FindPaymentService, last_payment: payment) } before do allow(payment).to receive(:response_code).and_return("invalid") - allow(OrderPaymentFinder).to receive(:new).with(order).and_return(finder) + allow(Orders::FindPaymentService).to receive(:new).with(order).and_return(finder) allow(Stripe::PaymentIntentValidator) .to receive_message_chain(:new, :call).and_return(payment_intent) stub_payment_intent_get_request(payment_intent_id: "valid") diff --git a/spec/factories/order_factory.rb b/spec/factories/order_factory.rb index 096753389b..b9726a3614 100644 --- a/spec/factories/order_factory.rb +++ b/spec/factories/order_factory.rb @@ -28,7 +28,7 @@ FactoryBot.define do after(:create) do |order, evaluator| order.select_shipping_method evaluator.shipping_method.id - OrderWorkflow.new(order).advance_to_payment + Orders::WorkflowService.new(order).advance_to_payment end factory :order_ready_for_confirmation do diff --git a/spec/jobs/order_cycle_opened_job_spec.rb b/spec/jobs/order_cycle_opened_job_spec.rb index e7bb800e0a..c36421480b 100644 --- a/spec/jobs/order_cycle_opened_job_spec.rb +++ b/spec/jobs/order_cycle_opened_job_spec.rb @@ -14,14 +14,14 @@ describe OrderCycleOpenedJob do } it "enqueues jobs for recently opened order cycles only" do - expect(OrderCycleWebhookService) + expect(OrderCycles::WebhookService) .to receive(:create_webhook_job).with(oc_opened_now, 'order_cycle.opened') - expect(OrderCycleWebhookService) - .not_to receive(:create_webhook_job).with(oc_opened_before, 'order_cycle.opened') + expect(OrderCycles::WebhookService) + .to_not receive(:create_webhook_job).with(oc_opened_before, 'order_cycle.opened') - expect(OrderCycleWebhookService) - .not_to receive(:create_webhook_job).with(oc_opening_soon, 'order_cycle.opened') + expect(OrderCycles::WebhookService) + .to_not receive(:create_webhook_job).with(oc_opening_soon, 'order_cycle.opened') OrderCycleOpenedJob.perform_now end @@ -41,7 +41,7 @@ describe OrderCycleOpenedJob do end ) - expect(OrderCycleWebhookService) + expect(OrderCycles::WebhookService) .to receive(:create_webhook_job).with(oc_opened_now, 'order_cycle.opened').once # Start two jobs in parallel: diff --git a/spec/jobs/subscription_confirm_job_spec.rb b/spec/jobs/subscription_confirm_job_spec.rb index 22f06c0a8d..d5cf92c40c 100644 --- a/spec/jobs/subscription_confirm_job_spec.rb +++ b/spec/jobs/subscription_confirm_job_spec.rb @@ -25,7 +25,7 @@ describe SubscriptionConfirmJob do let(:proxy_orders) { job.send(:unconfirmed_proxy_orders) } before do - OrderWorkflow.new(order).complete! + Orders::WorkflowService.new(order).complete! end it "returns proxy orders that meet all of the criteria" do @@ -140,7 +140,7 @@ describe SubscriptionConfirmJob do let(:order) { proxy_order.initialise_order! } before do - OrderWorkflow.new(order).complete! + Orders::WorkflowService.new(order).complete! allow(job).to receive(:send_confirmation_email).and_call_original allow(job).to receive(:send_payment_authorization_emails).and_call_original expect(job).to receive(:record_order) diff --git a/spec/lib/reports/enterprise_fee_summary/enterprise_fees_with_tax_report_by_producer_spec.rb b/spec/lib/reports/enterprise_fee_summary/enterprise_fees_with_tax_report_by_producer_spec.rb index 4c25519041..76bfe69459 100644 --- a/spec/lib/reports/enterprise_fee_summary/enterprise_fees_with_tax_report_by_producer_spec.rb +++ b/spec/lib/reports/enterprise_fee_summary/enterprise_fees_with_tax_report_by_producer_spec.rb @@ -34,7 +34,7 @@ describe Reporting::Reports::EnterpriseFeeSummary::EnterpriseFeesWithTaxReportBy shipping_method:, ship_address: create(:address) ).tap do |order| order.recreate_all_fees! - OrderWorkflow.new(order).complete! + Orders::WorkflowService.new(order).complete! end } diff --git a/spec/lib/reports/sales_tax_totals_by_order_spec.rb b/spec/lib/reports/sales_tax_totals_by_order_spec.rb index 9194ae3dbb..088d889bb0 100644 --- a/spec/lib/reports/sales_tax_totals_by_order_spec.rb +++ b/spec/lib/reports/sales_tax_totals_by_order_spec.rb @@ -80,7 +80,7 @@ describe "Reporting::Reports::SalesTax::SalesTaxTotalsByOrder" do end it "returns tax amount filtered by tax rate in query_row" do - OrderWorkflow.new(order).complete! + Orders::WorkflowService.new(order).complete! mock_voucher_adjustment_service filtered_tax_total = report.filtered_tax_rate_total(query_row) @@ -94,7 +94,7 @@ describe "Reporting::Reports::SalesTax::SalesTaxTotalsByOrder" do describe "#tax_rate_total" do it "returns the tax amount filtered by tax rate in the query_row" do - OrderWorkflow.new(order).complete! + Orders::WorkflowService.new(order).complete! mock_voucher_adjustment_service tax_total = report.tax_rate_total(query_row) @@ -124,7 +124,7 @@ describe "Reporting::Reports::SalesTax::SalesTaxTotalsByOrder" do describe "#total_excl_tax" do it "returns the total excluding tax specified in query_row" do - OrderWorkflow.new(order).complete! + Orders::WorkflowService.new(order).complete! mock_voucher_adjustment_service total = report.total_excl_tax(query_row) @@ -152,7 +152,7 @@ describe "Reporting::Reports::SalesTax::SalesTaxTotalsByOrder" do describe "#total_incl_tax" do it "returns the total including the tax specified in query_row" do - OrderWorkflow.new(order).complete! + Orders::WorkflowService.new(order).complete! mock_voucher_adjustment_service total = report.total_incl_tax(query_row) @@ -164,7 +164,7 @@ describe "Reporting::Reports::SalesTax::SalesTaxTotalsByOrder" do describe "#rules" do before do - OrderWorkflow.new(order).complete! + Orders::WorkflowService.new(order).complete! end it "returns rules" do @@ -274,7 +274,7 @@ describe "Reporting::Reports::SalesTax::SalesTaxTotalsByOrder" do VoucherAdjustmentsService.new(order).update order.update_totals_and_states - OrderWorkflow.new(order).complete! + Orders::WorkflowService.new(order).complete! end def mock_voucher_adjustment_service(included_tax: 0.0, excluded_tax: 0.0) diff --git a/spec/mailers/order_mailer_spec.rb b/spec/mailers/order_mailer_spec.rb index 0f2c2073e0..506a05d6b4 100644 --- a/spec/mailers/order_mailer_spec.rb +++ b/spec/mailers/order_mailer_spec.rb @@ -226,12 +226,12 @@ describe Spree::OrderMailer do data: invoice_data_generator.serialize_for_invoice) } - let(:generator){ instance_double(OrderInvoiceGenerator) } + let(:generator){ instance_double(Orders::GenerateInvoiceService) } let(:renderer){ instance_double(InvoiceRenderer) } let(:attachment_filename){ "invoice-#{order.number}.pdf" } let(:deliveries){ ActionMailer::Base.deliveries } before do - allow(OrderInvoiceGenerator).to receive(:new).with(order).and_return(generator) + allow(Orders::GenerateInvoiceService).to receive(:new).with(order).and_return(generator) allow(InvoiceRenderer).to receive(:new).and_return(renderer) end context "When invoices feature is not enabled" do diff --git a/spec/models/invoice/data_presenter_spec.rb b/spec/models/invoice/data_presenter_spec.rb index 0a0cc24676..bd35562762 100644 --- a/spec/models/invoice/data_presenter_spec.rb +++ b/spec/models/invoice/data_presenter_spec.rb @@ -25,7 +25,7 @@ describe Invoice::DataPresenter do let(:presenter){ Invoice::DataPresenter.new(invoice) } before do order.create_tax_charge! - OrderInvoiceGenerator.new(order).generate_or_update_latest_invoice + Orders::GenerateInvoiceService.new(order).generate_or_update_latest_invoice end it "displays nothing when the line item refer to a non taxable product" do @@ -53,7 +53,7 @@ describe Invoice::DataPresenter do tax_rate_clone.save! tax_rate_clone.calculator.save! order.create_tax_charge! - OrderInvoiceGenerator.new(order).generate_or_update_latest_invoice + Orders::GenerateInvoiceService.new(order).generate_or_update_latest_invoice end it "displays the tax rate when the line item refer to a taxable product" do @@ -65,7 +65,7 @@ describe Invoice::DataPresenter do before do order.line_items.last.tax_category.tax_rates.last.update!(zone: create(:zone)) order.create_tax_charge! - OrderInvoiceGenerator.new(order).generate_or_update_latest_invoice + Orders::GenerateInvoiceService.new(order).generate_or_update_latest_invoice end it "displays only the tax rates that were applied to the line items" do diff --git a/spec/models/proxy_order_spec.rb b/spec/models/proxy_order_spec.rb index 808a762486..5965521c27 100644 --- a/spec/models/proxy_order_spec.rb +++ b/spec/models/proxy_order_spec.rb @@ -186,12 +186,12 @@ describe ProxyOrder, type: :model do describe "initialise_order!" do let(:order) { create(:order) } - let(:factory) { instance_double(OrderFactory) } + let(:factory) { instance_double(Orders::FactoryService) } let!(:proxy_order) { create(:proxy_order) } context "when the order has not already been initialised" do - it "creates a new order using the OrderFactory, and returns it" do - expect(OrderFactory).to receive(:new) { factory } + it "creates a new order using the Orders::FactoryService, and returns it" do + expect(Orders::FactoryService).to receive(:new) { factory } expect(factory).to receive(:create) { order } expect(proxy_order.initialise_order!).to eq order end @@ -205,8 +205,8 @@ describe ProxyOrder, type: :model do end it "returns the existing order" do - expect(OrderFactory).not_to receive(:new) - expect(proxy_order).not_to receive(:save!) + expect(Orders::FactoryService).to_not receive(:new) + expect(proxy_order).to_not receive(:save!) expect(proxy_order.initialise_order!).to eq existing_order end end diff --git a/spec/models/spree/order_spec.rb b/spec/models/spree/order_spec.rb index c4fcc9fff5..480cef7cab 100644 --- a/spec/models/spree/order_spec.rb +++ b/spec/models/spree/order_spec.rb @@ -616,7 +616,7 @@ describe Spree::Order do describe "applying enterprise fees" do subject { create(:order) } - let(:fee_handler) { OrderFeesHandler.new(subject) } + let(:fee_handler) { Orders::HandleFeesService.new(subject) } before do allow(subject).to receive(:fee_handler) { fee_handler } @@ -628,7 +628,7 @@ describe Spree::Order do subject.recreate_all_fees! end - it "creates line item and order fee adjustments via OrderFeesHandler" do + it "creates line item and order fee adjustments via Orders::HandleFeesService" do expect(fee_handler).to receive(:create_line_item_fees!) expect(fee_handler).to receive(:create_order_fees!) subject.recreate_all_fees! diff --git a/spec/requests/checkout/failed_checkout_spec.rb b/spec/requests/checkout/failed_checkout_spec.rb index 555d93e827..fdde8cb297 100644 --- a/spec/requests/checkout/failed_checkout_spec.rb +++ b/spec/requests/checkout/failed_checkout_spec.rb @@ -39,7 +39,7 @@ describe "checking out an order that initially fails", type: :request do before do order_cycle_distributed_variants = double(:order_cycle_distributed_variants) - allow(OrderCycleDistributedVariants).to receive(:new) + allow(OrderCycles::DistributedVariantsService).to receive(:new) .and_return(order_cycle_distributed_variants) allow(order_cycle_distributed_variants) .to receive(:distributes_order_variants?).and_return(true) diff --git a/spec/requests/checkout/routes_spec.rb b/spec/requests/checkout/routes_spec.rb index 4d51386a7b..0f1b518b8d 100644 --- a/spec/requests/checkout/routes_spec.rb +++ b/spec/requests/checkout/routes_spec.rb @@ -26,7 +26,7 @@ describe 'checkout endpoints', type: :request do before do order_cycle_distributed_variants = double(:order_cycle_distributed_variants) - allow(OrderCycleDistributedVariants).to receive(:new) + allow(OrderCycles::DistributedVariantsService).to receive(:new) .and_return(order_cycle_distributed_variants) allow(order_cycle_distributed_variants).to receive(:distributes_order_variants?) .and_return(true) diff --git a/spec/requests/checkout/stripe_sca_spec.rb b/spec/requests/checkout/stripe_sca_spec.rb index d6acbc0857..8c5c48a363 100644 --- a/spec/requests/checkout/stripe_sca_spec.rb +++ b/spec/requests/checkout/stripe_sca_spec.rb @@ -84,7 +84,9 @@ describe "checking out an order with a Stripe SCA payment method", type: :reques before do order_cycle_distributed_variants = double(:order_cycle_distributed_variants) - allow(OrderCycleDistributedVariants).to receive(:new) { order_cycle_distributed_variants } + allow(OrderCycles::DistributedVariantsService).to receive(:new) { + order_cycle_distributed_variants + } allow(order_cycle_distributed_variants).to receive(:distributes_order_variants?) { true } allow(Stripe).to receive(:publishable_key).and_return("some_token") allow(Spree::Config).to receive(:stripe_connect_enabled).and_return(true) diff --git a/spec/requests/voucher_adjustments_spec.rb b/spec/requests/voucher_adjustments_spec.rb index 39d2e78545..56af4db442 100644 --- a/spec/requests/voucher_adjustments_spec.rb +++ b/spec/requests/voucher_adjustments_spec.rb @@ -25,7 +25,7 @@ describe VoucherAdjustmentsController, type: :request do order.update!(created_by: user) order.select_shipping_method shipping_method.id - OrderWorkflow.new(order).advance_to_payment + Orders::WorkflowService.new(order).advance_to_payment sign_in user end diff --git a/spec/services/cart_service_spec.rb b/spec/services/cart_service_spec.rb index 89d7432752..ea5b1dc731 100644 --- a/spec/services/cart_service_spec.rb +++ b/spec/services/cart_service_spec.rb @@ -284,12 +284,12 @@ describe CartService do let(:order_cycle_distributed_variants) { double(:order_cycle_distributed_variants) } before do - expect(OrderCycleDistributedVariants) + expect(OrderCycles::DistributedVariantsService) .to receive(:new).with(234, 123).and_return(order_cycle_distributed_variants) cart_service.instance_eval { @distributor = 123; @order_cycle = 234 } end - it "delegates to OrderCycleDistributedVariants, returning true when available" do + it "delegates to OrderCycles::DistributedVariantsService, returning true when available" do expect(order_cycle_distributed_variants).to receive(:available_variants) .and_return([variant]) @@ -297,7 +297,7 @@ describe CartService do expect(cart_service.errors).to be_empty end - it "delegates to OrderCycleDistributedVariants, returning false and erroring otherwise" do + it "delegates to OrderCycles::DistributedVariantsService, returns false - error otherwise" do expect(order_cycle_distributed_variants).to receive(:available_variants).and_return([]) expect(cart_service.send(:check_variant_available_under_distribution, variant)).to be false diff --git a/spec/services/checkout/post_checkout_actions_spec.rb b/spec/services/checkout/post_checkout_actions_spec.rb index d2859e11aa..765b84e541 100644 --- a/spec/services/checkout/post_checkout_actions_spec.rb +++ b/spec/services/checkout/post_checkout_actions_spec.rb @@ -51,10 +51,12 @@ describe Checkout::PostCheckoutActions do end describe "#failure" do - let(:restart_checkout_service) { instance_double(OrderCheckoutRestart) } + let(:restart_checkout_service) { instance_double(Orders::CheckoutRestartService) } it "restarts the checkout process" do - expect(OrderCheckoutRestart).to receive(:new).with(order).and_return(restart_checkout_service) + expect(Orders::CheckoutRestartService).to receive(:new) + .with(order) + .and_return(restart_checkout_service) expect(restart_checkout_service).to receive(:call) postCheckoutActions.failure diff --git a/spec/services/checkout/stripe_redirect_spec.rb b/spec/services/checkout/stripe_redirect_spec.rb index 164151e145..a2d547e886 100644 --- a/spec/services/checkout/stripe_redirect_spec.rb +++ b/spec/services/checkout/stripe_redirect_spec.rb @@ -25,7 +25,7 @@ describe Checkout::StripeRedirect do end it "authorizes the payment and returns the redirect path" do - expect(OrderPaymentFinder).to receive_message_chain(:new, :last_pending_payment). + expect(Orders::FindPaymentService).to receive_message_chain(:new, :last_pending_payment). and_return(stripe_payment) expect(OrderManagement::Order::StripeScaPaymentAuthorize).to receive(:new).and_call_original diff --git a/spec/services/order_cycle_clone_spec.rb b/spec/services/order_cycles/clone_service_spec.rb similarity index 97% rename from spec/services/order_cycle_clone_spec.rb rename to spec/services/order_cycles/clone_service_spec.rb index 7779b19da3..32525a5b73 100644 --- a/spec/services/order_cycle_clone_spec.rb +++ b/spec/services/order_cycles/clone_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe OrderCycleForm do +describe OrderCycles::CloneService do describe "#create" do it "clones the order cycle" do coordinator = create(:enterprise); @@ -14,7 +14,7 @@ describe OrderCycleForm do ex1 = create(:exchange, order_cycle: oc) ex2 = create(:exchange, order_cycle: oc) - occ = OrderCycleClone.new(oc).create + occ = OrderCycles::CloneService.new(oc).create expect(occ.name).to eq("COPY OF #{oc.name}") expect(occ.orders_open_at).to be_nil expect(occ.orders_close_at).to be_nil diff --git a/spec/services/order_cycle_distributed_products_spec.rb b/spec/services/order_cycles/distributed_products_service_spec.rb similarity index 98% rename from spec/services/order_cycle_distributed_products_spec.rb rename to spec/services/order_cycles/distributed_products_service_spec.rb index 37edaedbe7..76a41be2d7 100644 --- a/spec/services/order_cycle_distributed_products_spec.rb +++ b/spec/services/order_cycles/distributed_products_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe OrderCycleDistributedProducts do +describe OrderCycles::DistributedProductsService do describe "#products_relation" do let(:distributor) { create(:distributor_enterprise) } let(:product) { create(:product) } diff --git a/spec/services/order_cycle_distributed_variants_spec.rb b/spec/services/order_cycles/distributed_variants_service_spec.rb similarity index 86% rename from spec/services/order_cycle_distributed_variants_spec.rb rename to spec/services/order_cycles/distributed_variants_service_spec.rb index 672f33a3e5..6c5bde8aa1 100644 --- a/spec/services/order_cycle_distributed_variants_spec.rb +++ b/spec/services/order_cycles/distributed_variants_service_spec.rb @@ -2,11 +2,11 @@ require 'spec_helper' -describe OrderCycleDistributedVariants do +describe OrderCycles::DistributedVariantsService do let(:order) { double(:order) } let(:distributor) { double(:distributor) } let(:order_cycle) { double(:order_cycle) } - let(:subject) { OrderCycleDistributedVariants.new(order_cycle, distributor) } + let(:subject) { OrderCycles::DistributedVariantsService.new(order_cycle, distributor) } let(:product) { double(:product) } describe "checking if an order can change to a specified new distribution" do @@ -33,7 +33,7 @@ describe OrderCycleDistributedVariants do end it "returns an empty array when order cycle is nil" do - subject = OrderCycleDistributedVariants.new(nil, nil) + subject = OrderCycles::DistributedVariantsService.new(nil, nil) expect(subject.available_variants).to eq [] end end diff --git a/spec/services/order_cycle_form_spec.rb b/spec/services/order_cycles/form_service_spec.rb similarity index 95% rename from spec/services/order_cycle_form_spec.rb rename to spec/services/order_cycles/form_service_spec.rb index 6d15344e42..3f39ad5439 100644 --- a/spec/services/order_cycle_form_spec.rb +++ b/spec/services/order_cycles/form_service_spec.rb @@ -2,12 +2,12 @@ require 'spec_helper' -describe OrderCycleForm do +describe OrderCycles::FormService do describe "save" do describe "creating a new order cycle from params" do let(:shop) { create(:enterprise) } let(:order_cycle) { OrderCycle.new } - let(:form) { OrderCycleForm.new(order_cycle, params, shop.owner) } + let(:form) { OrderCycles::FormService.new(order_cycle, params, shop.owner) } context "when creation is successful" do let(:params) { { name: "Test Order Cycle", coordinator_id: shop.id } } @@ -33,7 +33,7 @@ describe OrderCycleForm do describe "updating an existing order cycle from params" do let(:shop) { create(:enterprise) } let(:order_cycle) { create(:simple_order_cycle, name: "Old Name") } - let(:form) { OrderCycleForm.new(order_cycle, params, shop.owner) } + let(:form) { OrderCycles::FormService.new(order_cycle, params, shop.owner) } context "when update is successful" do let(:params) { { name: "Test Order Cycle", coordinator_id: shop.id } } @@ -86,7 +86,7 @@ describe OrderCycleForm do let!(:uncoordinated_schedule) { create(:schedule, order_cycles: [uncoordinated_order_cycle] ) } context "where I manage the order_cycle's coordinator" do - let(:form) { OrderCycleForm.new(coordinated_order_cycle, params, user) } + let(:form) { OrderCycles::FormService.new(coordinated_order_cycle, params, user) } let(:syncer_mock) { instance_double(OrderManagement::Subscriptions::ProxyOrderSyncer, sync!: true) } @@ -140,7 +140,7 @@ describe OrderCycleForm do let(:distributor_shipping_method) { shipping_method.distributor_shipping_methods.first } let(:variant) { create(:variant, product: create(:product, supplier:)) } let(:params) { { name: 'Some new name' } } - let(:form) { OrderCycleForm.new(order_cycle, params, user) } + let(:form) { OrderCycles::FormService.new(order_cycle, params, user) } let(:outgoing_exchange_params) do { enterprise_id: distributor.id, @@ -233,7 +233,7 @@ describe OrderCycleForm do it "saves the changes" do order_cycle = create(:distributor_order_cycle, distributors: [distributor]) - form = OrderCycleForm.new( + form = OrderCycles::FormService.new( order_cycle, { selected_distributor_payment_method_ids: [distributor_payment_method] }, order_cycle.coordinator.users.first @@ -250,7 +250,7 @@ describe OrderCycleForm do order_cycle = create(:distributor_order_cycle, distributors: [distributor], suppliers: [supplier]) - form = OrderCycleForm.new( + form = OrderCycles::FormService.new( order_cycle, { selected_distributor_payment_method_ids: [distributor_payment_method] }, supplier.users.first @@ -264,7 +264,7 @@ describe OrderCycleForm do it "saves the changes" do order_cycle = create(:distributor_order_cycle, distributors: [distributor]) - form = OrderCycleForm.new( + form = OrderCycles::FormService.new( order_cycle, { selected_distributor_payment_method_ids: [distributor_payment_method2] }, create(:admin_user) @@ -281,7 +281,7 @@ describe OrderCycleForm do it "saves the changes" do order_cycle = create(:distributor_order_cycle, distributors: [distributor]) - form = OrderCycleForm.new( + form = OrderCycles::FormService.new( order_cycle, { selected_distributor_payment_method_ids: [distributor_payment_method] }, distributor.users.first @@ -300,7 +300,7 @@ describe OrderCycleForm do order_cycle = create(:distributor_order_cycle, distributors: [distributor, distributor2]) - form = OrderCycleForm.new( + form = OrderCycles::FormService.new( order_cycle, { selected_distributor_payment_method_ids: [distributor_payment_method] }, distributor2.users.first @@ -329,7 +329,7 @@ describe OrderCycleForm do order_cycle = create(:distributor_order_cycle, distributors: [distributor_i]) - form = OrderCycleForm.new( + form = OrderCycles::FormService.new( order_cycle, { selected_distributor_payment_method_ids: [distributor_payment_method_ii.id] }, order_cycle.coordinator.users.first @@ -355,7 +355,7 @@ describe OrderCycleForm do it "saves the changes" do order_cycle = create(:distributor_order_cycle, distributors: [distributor]) - form = OrderCycleForm.new( + form = OrderCycles::FormService.new( order_cycle, { selected_distributor_shipping_method_ids: [distributor_shipping_method] }, order_cycle.coordinator.users.first @@ -373,7 +373,7 @@ describe OrderCycleForm do order_cycle = create(:distributor_order_cycle, distributors: [distributor], suppliers: [supplier]) - form = OrderCycleForm.new( + form = OrderCycles::FormService.new( order_cycle, { selected_distributor_shipping_method_ids: [distributor_shipping_method] }, supplier.users.first @@ -388,7 +388,7 @@ describe OrderCycleForm do it "saves the changes" do order_cycle = create(:distributor_order_cycle, distributors: [distributor]) - form = OrderCycleForm.new( + form = OrderCycles::FormService.new( order_cycle, { selected_distributor_shipping_method_ids: [distributor_shipping_method] }, create(:admin_user) @@ -406,7 +406,7 @@ describe OrderCycleForm do it "saves the changes" do order_cycle = create(:distributor_order_cycle, distributors: [distributor]) - form = OrderCycleForm.new( + form = OrderCycles::FormService.new( order_cycle, { selected_distributor_shipping_method_ids: [distributor_shipping_method] }, distributor.users.first @@ -428,7 +428,7 @@ describe OrderCycleForm do order_cycle = create(:distributor_order_cycle, distributors: [distributor, distributor2]) - form = OrderCycleForm.new( + form = OrderCycles::FormService.new( order_cycle, { selected_distributor_shipping_method_ids: [distributor_shipping_method] }, distributor2.users.first @@ -460,7 +460,7 @@ describe OrderCycleForm do order_cycle = create(:distributor_order_cycle, distributors: [distributor_i]) - form = OrderCycleForm.new( + form = OrderCycles::FormService.new( order_cycle, { selected_distributor_shipping_method_ids: [distributor_shipping_method_ii.id] }, order_cycle.coordinator.users.first diff --git a/spec/services/order_cycle_warning_spec.rb b/spec/services/order_cycles/warning_service_spec.rb similarity index 91% rename from spec/services/order_cycle_warning_spec.rb rename to spec/services/order_cycles/warning_service_spec.rb index 3adf5e21f9..1cb7e0bb9f 100644 --- a/spec/services/order_cycle_warning_spec.rb +++ b/spec/services/order_cycles/warning_service_spec.rb @@ -2,9 +2,9 @@ require 'spec_helper' -describe OrderCycleWarning do +describe OrderCycles::WarningService do let(:user) { create(:user) } - let(:subject) { OrderCycleWarning } + let(:subject) { OrderCycles::WarningService } let!(:distributor) { create(:enterprise, owner: user) } let!(:order_cycle) { create(:simple_order_cycle, distributors: [distributor]) } diff --git a/spec/services/order_cycle_webhook_service_spec.rb b/spec/services/order_cycles/webhook_service_spec.rb similarity index 81% rename from spec/services/order_cycle_webhook_service_spec.rb rename to spec/services/order_cycles/webhook_service_spec.rb index 4ab08691db..45841f8e1b 100644 --- a/spec/services/order_cycle_webhook_service_spec.rb +++ b/spec/services/order_cycles/webhook_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe OrderCycleWebhookService do +describe OrderCycles::WebhookService do let(:order_cycle) { create( :simple_order_cycle, @@ -21,8 +21,8 @@ describe OrderCycleWebhookService do coordinator_user = create(:user, enterprises: [coordinator]) coordinator_user.webhook_endpoints.create!(url: "http://coordinator_user_url") - expect{ OrderCycleWebhookService.create_webhook_job(order_cycle, "order_cycle.opened") } - .not_to enqueue_job(WebhookDeliveryJob).with("http://coordinator_user_url", any_args) + expect{ OrderCycles::WebhookService.create_webhook_job(order_cycle, "order_cycle.opened") } + .to_not enqueue_job(WebhookDeliveryJob).with("http://coordinator_user_url", any_args) end context "coordinator owner has endpoint configured" do @@ -31,7 +31,7 @@ describe OrderCycleWebhookService do end it "creates webhook payload for order cycle coordinator" do - expect{ OrderCycleWebhookService.create_webhook_job(order_cycle, "order_cycle.opened") } + expect{ OrderCycles::WebhookService.create_webhook_job(order_cycle, "order_cycle.opened") } .to enqueue_job(WebhookDeliveryJob).with("http://coordinator_owner_url", any_args) end @@ -48,7 +48,7 @@ describe OrderCycleWebhookService do coordinator_name: "Starship Enterprise", } - expect{ OrderCycleWebhookService.create_webhook_job(order_cycle, "order_cycle.opened") } + expect{ OrderCycles::WebhookService.create_webhook_job(order_cycle, "order_cycle.opened") } .to enqueue_job(WebhookDeliveryJob).exactly(1).times .with("http://coordinator_owner_url", "order_cycle.opened", hash_including(data)) end @@ -56,7 +56,7 @@ describe OrderCycleWebhookService do context "coordinator owner doesn't have endpoint configured" do it "doesn't create webhook payload" do - expect{ OrderCycleWebhookService.create_webhook_job(order_cycle, "order_cycle.opened") } + expect{ OrderCycles::WebhookService.create_webhook_job(order_cycle, "order_cycle.opened") } .not_to enqueue_job(WebhookDeliveryJob) end end @@ -84,7 +84,9 @@ describe OrderCycleWebhookService do coordinator_name: "Starship Enterprise", } - expect{ OrderCycleWebhookService.create_webhook_job(order_cycle, "order_cycle.opened") } + expect{ + OrderCycles::WebhookService.create_webhook_job(order_cycle, "order_cycle.opened") + } .to enqueue_job(WebhookDeliveryJob).with("http://distributor1_owner_url", "order_cycle.opened", hash_including(data)) .and enqueue_job(WebhookDeliveryJob).with("http://distributor2_owner_url", @@ -105,7 +107,9 @@ describe OrderCycleWebhookService do it "creates only one webhook payload for the user's endpoint" do user.webhook_endpoints.create! url: "http://coordinator_owner_url" - expect{ OrderCycleWebhookService.create_webhook_job(order_cycle, "order_cycle.opened") } + expect{ + OrderCycles::WebhookService.create_webhook_job(order_cycle, "order_cycle.opened") + } .to enqueue_job(WebhookDeliveryJob).with("http://coordinator_owner_url", any_args) end end @@ -127,8 +131,10 @@ describe OrderCycleWebhookService do } it "doesn't create a webhook payload for supplier owner" do - expect{ OrderCycleWebhookService.create_webhook_job(order_cycle, "order_cycle.opened") } - .not_to enqueue_job(WebhookDeliveryJob).with("http://supplier_owner_url", any_args) + expect{ + OrderCycles::WebhookService.create_webhook_job(order_cycle, "order_cycle.opened") + } + .to_not enqueue_job(WebhookDeliveryJob).with("http://supplier_owner_url", any_args) end end end @@ -136,7 +142,7 @@ describe OrderCycleWebhookService do context "without webhook subscribed to enterprise" do it "doesn't create webhook payload" do - expect{ OrderCycleWebhookService.create_webhook_job(order_cycle, "order_cycle.opened") } + expect{ OrderCycles::WebhookService.create_webhook_job(order_cycle, "order_cycle.opened") } .not_to enqueue_job(WebhookDeliveryJob) end end diff --git a/spec/services/order_available_payment_methods_spec.rb b/spec/services/orders/available_payment_methods_service_spec.rb similarity index 89% rename from spec/services/order_available_payment_methods_spec.rb rename to spec/services/orders/available_payment_methods_service_spec.rb index 6d9a9e4185..b31d3af5f6 100644 --- a/spec/services/order_available_payment_methods_spec.rb +++ b/spec/services/orders/available_payment_methods_service_spec.rb @@ -2,13 +2,13 @@ require 'spec_helper' -describe OrderAvailablePaymentMethods do +describe Orders::AvailablePaymentMethodsService do context "when the order has no current_distributor" do it "returns an empty array" do order_cycle = create(:sells_own_order_cycle) order = build(:order, distributor: nil, order_cycle:) - expect(OrderAvailablePaymentMethods.new(order).to_a).to eq [] + expect(Orders::AvailablePaymentMethodsService.new(order).to_a).to eq [] end end @@ -21,7 +21,7 @@ describe OrderAvailablePaymentMethods do order_cycle = create(:sells_own_order_cycle) order = build(:order, distributor:, order_cycle:) - available_payment_methods = OrderAvailablePaymentMethods.new(order).to_a + available_payment_methods = Orders::AvailablePaymentMethodsService.new(order).to_a expect(available_payment_methods).to eq [frontend_payment_method] end @@ -35,7 +35,7 @@ describe OrderAvailablePaymentMethods do order_cycle = create(:sells_own_order_cycle) order = build(:order, distributor:, order_cycle:) - available_payment_methods = OrderAvailablePaymentMethods.new(order).to_a + available_payment_methods = Orders::AvailablePaymentMethodsService.new(order).to_a expect(available_payment_methods).to eq [frontend_payment_method] end @@ -53,7 +53,7 @@ describe OrderAvailablePaymentMethods do order_cycle = create(:sells_own_order_cycle, distributors: [distributor_i, distributor_ii]) order = build(:order, distributor: distributor_i, order_cycle:) - available_payment_methods = OrderAvailablePaymentMethods.new(order).to_a + available_payment_methods = Orders::AvailablePaymentMethodsService.new(order).to_a expect(available_payment_methods).to eq [payment_method_i] end @@ -76,7 +76,7 @@ describe OrderAvailablePaymentMethods do ] order = build(:order, distributor: distributor_i, order_cycle:) - available_payment_methods = OrderAvailablePaymentMethods.new(order).to_a + available_payment_methods = Orders::AvailablePaymentMethodsService.new(order).to_a expect(available_payment_methods).to eq [payment_method_i] end @@ -125,7 +125,7 @@ describe OrderAvailablePaymentMethods do let(:order) { build(:order, distributor:, order_cycle:) } context "when the customer is nil" do - let(:available_payment_methods) { OrderAvailablePaymentMethods.new(order).to_a } + let(:available_payment_methods) { Orders::AvailablePaymentMethodsService.new(order).to_a } it "applies default action (hide)" do expect(available_payment_methods).to include untagged_payment_method @@ -134,7 +134,9 @@ describe OrderAvailablePaymentMethods do end context "when a customer is present" do - let(:available_payment_methods) { OrderAvailablePaymentMethods.new(order, customer).to_a } + let(:available_payment_methods) { + Orders::AvailablePaymentMethodsService.new(order, customer).to_a + } context "and the customer's tags match" do before do @@ -175,7 +177,7 @@ describe OrderAvailablePaymentMethods do let(:order) { build(:order, distributor:, order_cycle:) } context "when the customer is nil" do - let(:available_payment_methods) { OrderAvailablePaymentMethods.new(order).to_a } + let(:available_payment_methods) { Orders::AvailablePaymentMethodsService.new(order).to_a } it "applies default action (show)" do expect(available_payment_methods).to include( @@ -186,7 +188,9 @@ describe OrderAvailablePaymentMethods do end context "when a customer is present" do - let(:available_payment_methods) { OrderAvailablePaymentMethods.new(order, customer).to_a } + let(:available_payment_methods) { + Orders::AvailablePaymentMethodsService.new(order, customer).to_a + } context "and the customer's tags match" do before do @@ -233,7 +237,7 @@ describe OrderAvailablePaymentMethods do } it do order = build(:order, distributor: d2, order_cycle: oc) - order_available_payment_methods = OrderAvailablePaymentMethods.new(order).to_a + order_available_payment_methods = Orders::AvailablePaymentMethodsService.new(order).to_a expect(order_available_payment_methods).to eq([d2.payment_methods.first]) end end diff --git a/spec/services/order_available_shipping_methods_spec.rb b/spec/services/orders/available_shipping_methods_service_spec.rb similarity index 90% rename from spec/services/order_available_shipping_methods_spec.rb rename to spec/services/orders/available_shipping_methods_service_spec.rb index 325a5801d2..9ee26ca804 100644 --- a/spec/services/order_available_shipping_methods_spec.rb +++ b/spec/services/orders/available_shipping_methods_service_spec.rb @@ -2,13 +2,13 @@ require 'spec_helper' -describe OrderAvailableShippingMethods do +describe Orders::AvailableShippingMethodsService do context "when the order has no current_distributor" do it "returns an empty array" do order_cycle = create(:sells_own_order_cycle) order = build(:order, distributor: nil, order_cycle:) - expect(OrderAvailableShippingMethods.new(order).to_a).to eq [] + expect(Orders::AvailableShippingMethodsService.new(order).to_a).to eq [] end end @@ -20,7 +20,7 @@ describe OrderAvailableShippingMethods do order_cycle = create(:sells_own_order_cycle) order = build(:order, distributor:, order_cycle:) - available_shipping_methods = OrderAvailableShippingMethods.new(order).to_a + available_shipping_methods = Orders::AvailableShippingMethodsService.new(order).to_a expect(available_shipping_methods).to eq [frontend_shipping_method] end @@ -38,7 +38,7 @@ describe OrderAvailableShippingMethods do order_cycle = create(:sells_own_order_cycle, distributors: [distributor_i, distributor_ii]) order = build(:order, distributor: distributor_i, order_cycle:) - available_shipping_methods = OrderAvailableShippingMethods.new(order).to_a + available_shipping_methods = Orders::AvailableShippingMethodsService.new(order).to_a expect(available_shipping_methods).to eq [shipping_method_i] end @@ -61,7 +61,7 @@ describe OrderAvailableShippingMethods do ] order = build(:order, distributor: distributor_i, order_cycle:) - available_shipping_methods = OrderAvailableShippingMethods.new(order).to_a + available_shipping_methods = Orders::AvailableShippingMethodsService.new(order).to_a expect(available_shipping_methods).to eq [shipping_method_i] end @@ -110,7 +110,7 @@ describe OrderAvailableShippingMethods do let(:order) { build(:order, distributor:, order_cycle:) } context "when the customer is nil" do - let(:available_shipping_methods) { OrderAvailableShippingMethods.new(order).to_a } + let(:available_shipping_methods) { Orders::AvailableShippingMethodsService.new(order).to_a } it "applies default action (hide)" do expect(available_shipping_methods).to include untagged_sm @@ -119,7 +119,9 @@ describe OrderAvailableShippingMethods do end context "when a customer is present" do - let(:available_shipping_methods) { OrderAvailableShippingMethods.new(order, customer).to_a } + let(:available_shipping_methods) { + Orders::AvailableShippingMethodsService.new(order, customer).to_a + } context "and the customer's tags match" do before do @@ -157,7 +159,7 @@ describe OrderAvailableShippingMethods do let(:order) { build(:order, distributor:, order_cycle:) } context "when the customer is nil" do - let(:available_shipping_methods) { OrderAvailableShippingMethods.new(order).to_a } + let(:available_shipping_methods) { Orders::AvailableShippingMethodsService.new(order).to_a } it "applies default action (show)" do expect(available_shipping_methods).to include tagged_sm, untagged_sm @@ -165,7 +167,9 @@ describe OrderAvailableShippingMethods do end context "when a customer is present" do - let(:available_shipping_methods) { OrderAvailableShippingMethods.new(order, customer).to_a } + let(:available_shipping_methods) { + Orders::AvailableShippingMethodsService.new(order, customer).to_a + } context "and the customer's tags match" do before do @@ -209,14 +213,14 @@ describe OrderAvailableShippingMethods do } it do order = build(:order, distributor: d2, order_cycle: oc) - order_available_shipping_methods = OrderAvailableShippingMethods.new(order).to_a + order_available_shipping_methods = Orders::AvailableShippingMethodsService.new(order).to_a expect(order_available_shipping_methods).to eq([d2.shipping_methods.first]) end end end context "when certain shipping categories are required", feature: :match_shipping_categories do - subject { OrderAvailableShippingMethods.new(order) } + subject { Orders::AvailableShippingMethodsService.new(order) } let(:order) { build(:order, distributor:, order_cycle: oc) } let(:oc) { create(:order_cycle) } let(:distributor) { oc.distributors.first } diff --git a/spec/services/order_cart_reset_spec.rb b/spec/services/orders/cart_reset_service_spec.rb similarity index 81% rename from spec/services/order_cart_reset_spec.rb rename to spec/services/orders/cart_reset_service_spec.rb index c8a1b4c3c8..05e2ea4387 100644 --- a/spec/services/order_cart_reset_spec.rb +++ b/spec/services/orders/cart_reset_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe OrderCartReset do +describe Orders::CartResetService do let(:distributor) { create(:distributor_enterprise) } let(:order) { create(:order, :with_line_item, distributor:) } @@ -10,7 +10,7 @@ describe OrderCartReset do let(:new_distributor) { create(:distributor_enterprise) } it "empties order" do - OrderCartReset.new(order, new_distributor.id.to_s).reset_distributor + Orders::CartResetService.new(order, new_distributor.id.to_s).reset_distributor expect(order.line_items).to be_empty end @@ -28,7 +28,7 @@ describe OrderCartReset do it "empties order and makes order cycle nil" do expect(order_cycle_list).to receive(:call).and_return([]) - OrderCartReset.new(order, distributor.id.to_s).reset_other!(nil, nil) + Orders::CartResetService.new(order, distributor.id.to_s).reset_other!(nil, nil) expect(order.line_items).to be_empty expect(order.order_cycle).to be_nil @@ -38,7 +38,7 @@ describe OrderCartReset do other_order_cycle = create(:simple_order_cycle, distributors: [distributor]) expect(order_cycle_list).to receive(:call).and_return([other_order_cycle]) - OrderCartReset.new(order, distributor.id.to_s).reset_other!(nil, nil) + Orders::CartResetService.new(order, distributor.id.to_s).reset_other!(nil, nil) expect(order.order_cycle).to eq other_order_cycle end diff --git a/spec/services/order_checkout_restart_spec.rb b/spec/services/orders/checkout_restart_service_spec.rb similarity index 86% rename from spec/services/order_checkout_restart_spec.rb rename to spec/services/orders/checkout_restart_service_spec.rb index c4f10fb5e6..f8f051c5b9 100644 --- a/spec/services/order_checkout_restart_spec.rb +++ b/spec/services/orders/checkout_restart_service_spec.rb @@ -2,14 +2,14 @@ require 'spec_helper' -describe OrderCheckoutRestart do +describe Orders::CheckoutRestartService do let(:order) { create(:order_with_distributor) } describe "#call" do context "when the order is already in the 'cart' state" do it "does nothing" do - expect(order).not_to receive(:restart_checkout!) - OrderCheckoutRestart.new(order).call + expect(order).to_not receive(:restart_checkout!) + Orders::CheckoutRestartService.new(order).call end end @@ -27,7 +27,7 @@ describe OrderCheckoutRestart do before { order.ship_address = nil } it "resets the order state, and clears incomplete shipments and payments" do - OrderCheckoutRestart.new(order).call + Orders::CheckoutRestartService.new(order).call expect_cart_state_and_reset_adjustments end @@ -37,7 +37,7 @@ describe OrderCheckoutRestart do before { order.ship_address = order.address_from_distributor } it "resets the order state, and clears incomplete shipments and payments" do - OrderCheckoutRestart.new(order).call + Orders::CheckoutRestartService.new(order).call expect_cart_state_and_reset_adjustments end @@ -48,7 +48,7 @@ describe OrderCheckoutRestart do it "does not reset the order state nor clears incomplete shipments and payments" do expect do - OrderCheckoutRestart.new(order).call + Orders::CheckoutRestartService.new(order).call end.to raise_error(StateMachines::InvalidTransition) expect(order.state).to eq 'payment' diff --git a/spec/services/order_invoice_comparator_spec.rb b/spec/services/orders/compare_invoice_service_spec.rb similarity index 98% rename from spec/services/order_invoice_comparator_spec.rb rename to spec/services/orders/compare_invoice_service_spec.rb index 870c5866e3..932e5b54b6 100644 --- a/spec/services/order_invoice_comparator_spec.rb +++ b/spec/services/orders/compare_invoice_service_spec.rb @@ -299,7 +299,7 @@ shared_examples "attribute changes - payment state" do |boolean, type| end end -describe OrderInvoiceComparator do +describe Orders::CompareInvoiceService do let!(:invoice){ create(:invoice, order:, @@ -311,7 +311,7 @@ describe OrderInvoiceComparator do let(:order) { create(:completed_order_with_fees) } let!(:invoice_data_generator){ InvoiceDataGenerator.new(order) } let(:subject) { - OrderInvoiceComparator.new(order).can_generate_new_invoice? + Orders::CompareInvoiceService.new(order).can_generate_new_invoice? } context "changes on the order object" do @@ -351,7 +351,7 @@ describe OrderInvoiceComparator do let!(:order) { create(:completed_order_with_fees) } let!(:invoice_data_generator){ InvoiceDataGenerator.new(order) } let(:subject) { - OrderInvoiceComparator.new(order).can_update_latest_invoice? + Orders::CompareInvoiceService.new(order).can_update_latest_invoice? } context "changes on the order object" do diff --git a/spec/services/customer_order_cancellation_spec.rb b/spec/services/orders/customer_cancellation_service_spec.rb similarity index 82% rename from spec/services/customer_order_cancellation_spec.rb rename to spec/services/orders/customer_cancellation_service_spec.rb index 9c8c6a8508..624ea08fd3 100644 --- a/spec/services/customer_order_cancellation_spec.rb +++ b/spec/services/orders/customer_cancellation_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe CustomerOrderCancellation do +describe Orders::CustomerCancellationService do let(:mail_mock) { double(:mailer_mock, deliver_later: true) } before do allow(Spree::OrderMailer).to receive(:cancel_email_for_shop) { mail_mock } @@ -12,7 +12,7 @@ describe CustomerOrderCancellation do it "notifies the distributor by email" do order = create(:order, completed_at: Time.now, state: 'complete') - CustomerOrderCancellation.new(order).call + Orders::CustomerCancellationService.new(order).call expect(Spree::OrderMailer).to have_received(:cancel_email_for_shop).with(order) expect(mail_mock).to have_received(:deliver_later) @@ -23,7 +23,7 @@ describe CustomerOrderCancellation do it "doesn't notify the distributor by email" do order = create(:order, state: 'canceled') - CustomerOrderCancellation.new(order).call + Orders::CustomerCancellationService.new(order).call expect(Spree::OrderMailer).not_to have_received(:cancel_email_for_shop) end diff --git a/spec/services/order_factory_spec.rb b/spec/services/orders/factory_service_spec.rb similarity index 97% rename from spec/services/order_factory_spec.rb rename to spec/services/orders/factory_service_spec.rb index 5a346ff810..26c8ec2564 100644 --- a/spec/services/order_factory_spec.rb +++ b/spec/services/orders/factory_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe OrderFactory do +describe Orders::FactoryService do let(:variant1) { create(:variant, price: 5.0) } let(:variant2) { create(:variant, price: 7.0) } let(:user) { create(:user) } @@ -16,7 +16,7 @@ describe OrderFactory do let(:ship_address) { create(:address) } let(:bill_address) { create(:address) } let(:opts) { {} } - let(:factory) { OrderFactory.new(attrs, opts) } + let(:factory) { Orders::FactoryService.new(attrs, opts) } let(:order) { factory.create } describe "create" do @@ -50,7 +50,7 @@ describe OrderFactory do end it "retains address, delivery, and payment attributes until completion of the order" do - OrderWorkflow.new(order).complete + Orders::WorkflowService.new(order).complete order.reload diff --git a/spec/services/order_payment_finder_spec.rb b/spec/services/orders/find_payment_service_spec.rb similarity index 93% rename from spec/services/order_payment_finder_spec.rb rename to spec/services/orders/find_payment_service_spec.rb index ff90369fb8..0777d5ed2c 100644 --- a/spec/services/order_payment_finder_spec.rb +++ b/spec/services/orders/find_payment_service_spec.rb @@ -2,9 +2,9 @@ require 'spec_helper' -describe OrderPaymentFinder do +describe Orders::FindPaymentService do let(:order) { create(:order_with_distributor) } - let(:finder) { OrderPaymentFinder.new(order) } + let(:finder) { Orders::FindPaymentService.new(order) } context "when order has several non pending payments" do let!(:failed_payment) { create(:payment, order:, state: 'failed') } diff --git a/spec/services/order_invoice_generator_spec.rb b/spec/services/orders/generate_invoice_service_spec.rb similarity index 95% rename from spec/services/order_invoice_generator_spec.rb rename to spec/services/orders/generate_invoice_service_spec.rb index 24b83143de..50fb5350d5 100644 --- a/spec/services/order_invoice_generator_spec.rb +++ b/spec/services/orders/generate_invoice_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe OrderInvoiceGenerator do +describe Orders::GenerateInvoiceService do let!(:order) { create(:completed_order_with_fees) } let!(:invoice_data_generator){ InvoiceDataGenerator.new(order) } let!(:latest_invoice){ @@ -12,7 +12,7 @@ describe OrderInvoiceGenerator do } let(:instance) { described_class.new(order) } - let(:comparator){ double("OrderInvoiceComparator") } + let(:comparator){ double("Orders::CompareInvoiceService") } before do allow(instance).to receive(:comparator).and_return(comparator) diff --git a/spec/services/order_fees_handler_spec.rb b/spec/services/orders/handle_fees_service_spec.rb similarity index 95% rename from spec/services/order_fees_handler_spec.rb rename to spec/services/orders/handle_fees_service_spec.rb index 29ef8428af..6b92683331 100644 --- a/spec/services/order_fees_handler_spec.rb +++ b/spec/services/orders/handle_fees_service_spec.rb @@ -2,12 +2,12 @@ require 'spec_helper' -describe OrderFeesHandler do +describe Orders::HandleFeesService do let(:order_cycle) { create(:order_cycle) } let(:order) { create(:order_with_line_items, line_items_count: 1, order_cycle:) } let(:line_item) { order.line_items.first } - let(:service) { OrderFeesHandler.new(order) } + let(:service) { Orders::HandleFeesService.new(order) } let(:calculator) { double(OpenFoodNetwork::EnterpriseFeeCalculator, create_order_adjustments_for: true) } diff --git a/spec/services/order_data_masker_spec.rb b/spec/services/orders/mask_data_service_spec.rb similarity index 98% rename from spec/services/order_data_masker_spec.rb rename to spec/services/orders/mask_data_service_spec.rb index d68e90ff86..f23141922c 100644 --- a/spec/services/order_data_masker_spec.rb +++ b/spec/services/orders/mask_data_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe OrderDataMasker do +describe Orders::MaskDataService do describe '#call' do let(:distributor) { create(:enterprise) } let(:order) { create(:order, distributor:, ship_address: create(:address)) } diff --git a/spec/services/order_tax_adjustments_fetcher_spec.rb b/spec/services/orders/order_tax_adjustments_fetcher_spec.rb similarity index 97% rename from spec/services/order_tax_adjustments_fetcher_spec.rb rename to spec/services/orders/order_tax_adjustments_fetcher_spec.rb index 31f71b80b5..f45280c27a 100644 --- a/spec/services/order_tax_adjustments_fetcher_spec.rb +++ b/spec/services/orders/order_tax_adjustments_fetcher_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" -describe OrderTaxAdjustmentsFetcher do +describe Orders::FetchTaxAdjustmentsService do describe "#totals" do let(:zone) { create(:zone_with_member) } let(:coordinator) { create(:distributor_enterprise, charges_sales_tax: true) } @@ -94,7 +94,7 @@ describe OrderTaxAdjustmentsFetcher do legacy_tax_adjustment end - subject { OrderTaxAdjustmentsFetcher.new(order).totals } + subject { Orders::FetchTaxAdjustmentsService.new(order).totals } it "returns a hash with all 5 taxes" do expect(subject.size).to eq(5) diff --git a/spec/services/order_syncer_spec.rb b/spec/services/orders/sync_service_spec.rb similarity index 97% rename from spec/services/order_syncer_spec.rb rename to spec/services/orders/sync_service_spec.rb index 4251354902..f45a009a9c 100644 --- a/spec/services/order_syncer_spec.rb +++ b/spec/services/orders/sync_service_spec.rb @@ -2,14 +2,14 @@ require "spec_helper" -describe OrderSyncer do +describe Orders::SyncService do describe "updating the shipping method" do let!(:subscription) { create(:subscription, with_items: true, with_proxy_orders: true) } let!(:order) { subscription.proxy_orders.first.initialise_order! } let!(:shipping_method) { subscription.shipping_method } let!(:new_shipping_method) { create(:shipping_method, distributors: [subscription.shop]) } - let(:syncer) { OrderSyncer.new(subscription) } + let(:syncer) { Orders::SyncService.new(subscription) } context "when the shipping method on an order is the same as the subscription" do let(:params) { { shipping_method_id: new_shipping_method.id } } @@ -88,7 +88,7 @@ describe OrderSyncer do let(:payment_method) { subscription.payment_method } let(:new_payment_method) { create(:payment_method, distributors: [subscription.shop]) } let(:invalid_payment_method) { create(:payment_method, distributors: [create(:enterprise)]) } - let(:syncer) { OrderSyncer.new(subscription) } + let(:syncer) { Orders::SyncService.new(subscription) } context "when the payment method on an order is the same as the subscription" do let(:params) { { payment_method_id: new_payment_method.id } } @@ -160,7 +160,7 @@ describe OrderSyncer do { bill_address_attributes: { id: bill_address_attrs["id"], firstname: "Bill", address1: "123 abc st", phone: "1123581321" } } } - let(:syncer) { OrderSyncer.new(subscription) } + let(:syncer) { Orders::SyncService.new(subscription) } context "when a ship address is not required" do let!(:shipping_method) do @@ -268,7 +268,7 @@ describe OrderSyncer do { ship_address_attributes: { id: ship_address_attrs["id"], firstname: "Ship", address1: "123 abc st", phone: "1123581321" } } } - let(:syncer) { OrderSyncer.new(subscription) } + let(:syncer) { Orders::SyncService.new(subscription) } context "when a ship address is not required" do let!(:shipping_method) do @@ -394,7 +394,7 @@ describe OrderSyncer do context "when quantity is within available stock" do let(:params) { { subscription_line_items_attributes: [{ id: sli.id, quantity: 2 }] } } - let(:syncer) { OrderSyncer.new(subscription) } + let(:syncer) { Orders::SyncService.new(subscription) } it "updates the line_item quantities and totals on all orders" do expect(order.reload.total.to_f).to eq 59.97 @@ -409,7 +409,7 @@ describe OrderSyncer do context "when quantity is greater than available stock" do let(:params) { { subscription_line_items_attributes: [{ id: sli.id, quantity: 3 }] } } - let(:syncer) { OrderSyncer.new(subscription) } + let(:syncer) { Orders::SyncService.new(subscription) } before do expect(order.reload.total.to_f).to eq 59.97 @@ -430,7 +430,7 @@ describe OrderSyncer do context "when order is complete" do it "does not update the line_item quantities and adds the order " \ "to order_update_issues with insufficient stock" do - OrderWorkflow.new(order).complete + Orders::WorkflowService.new(order).complete expect(syncer.sync!).to be true @@ -449,7 +449,7 @@ describe OrderSyncer do # this single item available is used when the order is completed below, # making the item out of stock variant.update_attribute(:on_hand, 1) - OrderWorkflow.new(order).complete + Orders::WorkflowService.new(order).complete expect(syncer.sync!).to be true @@ -462,7 +462,7 @@ describe OrderSyncer do context "where the quantity of the item on an initialised order has already been changed" do let(:params) { { subscription_line_items_attributes: [{ id: sli.id, quantity: 3 }] } } - let(:syncer) { OrderSyncer.new(subscription) } + let(:syncer) { Orders::SyncService.new(subscription) } let(:changed_line_item) { order.line_items.find_by(variant_id: sli.variant_id) } before { variant.update_attribute(:on_hand, 3) } @@ -510,7 +510,7 @@ describe OrderSyncer do let(:subscription) { create(:subscription, with_items: true, with_proxy_orders: true) } let(:order) { subscription.proxy_orders.first.initialise_order! } let(:variant) { create(:variant) } - let(:syncer) { OrderSyncer.new(subscription) } + let(:syncer) { Orders::SyncService.new(subscription) } before do expect(order.reload.total.to_f).to eq 59.97 @@ -547,7 +547,7 @@ describe OrderSyncer do end context "when order is complete" do - before { OrderWorkflow.new(order).complete } + before { Orders::WorkflowService.new(order).complete } it "does not add line_item and adds the order to order_update_issues" do expect(syncer.sync!).to be true @@ -593,7 +593,7 @@ describe OrderSyncer do let(:sli) { subscription.subscription_line_items.first } let(:variant) { sli.variant } let(:params) { { subscription_line_items_attributes: [{ id: sli.id, _destroy: true }] } } - let(:syncer) { OrderSyncer.new(subscription) } + let(:syncer) { Orders::SyncService.new(subscription) } it "removes the line item and updates totals on all orders" do expect(order.reload.total.to_f).to eq 59.97 diff --git a/spec/services/order_workflow_spec.rb b/spec/services/orders/workflow_service_spec.rb similarity index 98% rename from spec/services/order_workflow_spec.rb rename to spec/services/orders/workflow_service_spec.rb index 3aa715aa4f..08e48fa0cd 100644 --- a/spec/services/order_workflow_spec.rb +++ b/spec/services/orders/workflow_service_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" -describe OrderWorkflow do +describe Orders::WorkflowService do let!(:distributor) { create(:distributor_enterprise) } let!(:order) do create(:order_with_totals_and_distribution, distributor:, diff --git a/spec/services/place_proxy_order_spec.rb b/spec/services/place_proxy_order_spec.rb index ba6db17353..2fc895ec53 100644 --- a/spec/services/place_proxy_order_spec.rb +++ b/spec/services/place_proxy_order_spec.rb @@ -114,8 +114,8 @@ describe PlaceProxyOrder do order.line_items << build(:line_item) - order_workflow = instance_double(OrderWorkflow, complete!: true) - allow(OrderWorkflow).to receive(:new).with(order).and_return(order_workflow) + order_workflow = instance_double(Orders::WorkflowService, complete!: true) + allow(Orders::WorkflowService).to receive(:new).with(order).and_return(order_workflow) end context "when no changes are present" do diff --git a/spec/system/admin/invoice_print_spec.rb b/spec/system/admin/invoice_print_spec.rb index 111b1c074b..e4246a9d69 100644 --- a/spec/system/admin/invoice_print_spec.rb +++ b/spec/system/admin/invoice_print_spec.rb @@ -678,7 +678,7 @@ describe ' context "Order has previous invoices" do before do - OrderInvoiceGenerator.new(order).generate_or_update_latest_invoice + Orders::GenerateInvoiceService.new(order).generate_or_update_latest_invoice first_line_item = order.line_items.first order.line_items.first.update(quantity: first_line_item.quantity + 1) end diff --git a/spec/system/admin/payments_stripe_spec.rb b/spec/system/admin/payments_stripe_spec.rb index 13ff3a6b6f..1c6b96ae58 100644 --- a/spec/system/admin/payments_stripe_spec.rb +++ b/spec/system/admin/payments_stripe_spec.rb @@ -47,7 +47,8 @@ describe ' click_button "Update" expect(page).to have_link "StripeSCA" - expect(OrderPaymentFinder.new(order.reload).last_payment.state).to eq "completed" + last_payment_state = Orders::FindPaymentService.new(order.reload).last_payment.state + expect(last_payment_state).to eq 'completed' end end @@ -66,7 +67,7 @@ describe ' expect(page).to have_link "StripeSCA" expect(page).to have_content "FAILED" - expect(OrderPaymentFinder.new(order.reload).last_payment.state).to eq "failed" + expect(Orders::FindPaymentService.new(order.reload).last_payment.state).to eq "failed" end end end @@ -87,7 +88,7 @@ describe ' expect(page).to have_link "StripeSCA" expect(page).to have_content "AUTHORIZATION REQUIRED" - expect(OrderPaymentFinder.new(order.reload).last_payment.state) + expect(Orders::FindPaymentService.new(order.reload).last_payment.state) .to eq "requires_authorization" end end @@ -112,7 +113,7 @@ describe ' click_button "Update" expect(page).to have_link "StripeSCA" - expect(OrderPaymentFinder.new(order.reload).last_payment.state).to eq "completed" + expect(Orders::FindPaymentService.new(order.reload).last_payment.state).to eq "completed" end end end diff --git a/spec/system/admin/reports/enterprise_summary_fees/enterprise_summary_fee_with_tax_report_by_order_spec.rb b/spec/system/admin/reports/enterprise_summary_fees/enterprise_summary_fee_with_tax_report_by_order_spec.rb index 5831946361..bd833db5d8 100644 --- a/spec/system/admin/reports/enterprise_summary_fees/enterprise_summary_fee_with_tax_report_by_order_spec.rb +++ b/spec/system/admin/reports/enterprise_summary_fees/enterprise_summary_fee_with_tax_report_by_order_spec.rb @@ -110,7 +110,7 @@ describe "Enterprise Summary Fee with Tax Report By Order" do # independently of the order_cycle. # order.reload order.recreate_all_fees! - OrderWorkflow.new(order).complete! + Orders::WorkflowService.new(order).complete! order.customer.update!({ first_name: customer_first_name, @@ -188,7 +188,7 @@ describe "Enterprise Summary Fee with Tax Report By Order" do ship_address_id: ship_address.id }) order.recreate_all_fees! - OrderWorkflow.new(order).complete! + Orders::WorkflowService.new(order).complete! order.customer.update!({ first_name: customer_first_name, diff --git a/spec/system/admin/reports/sales_tax/sales_tax_totals_by_order_spec.rb b/spec/system/admin/reports/sales_tax/sales_tax_totals_by_order_spec.rb index 7678f59c02..1ff6b557b0 100644 --- a/spec/system/admin/reports/sales_tax/sales_tax_totals_by_order_spec.rb +++ b/spec/system/admin/reports/sales_tax/sales_tax_totals_by_order_spec.rb @@ -100,7 +100,7 @@ describe "Sales Tax Totals By order" do # the enterprise fees can be known only when the user selects the variants # we'll need to create them by calling recreate_all_fees! order.recreate_all_fees! - OrderWorkflow.new(order).complete! + Orders::WorkflowService.new(order).complete! end it "generates the report" do @@ -166,7 +166,7 @@ describe "Sales Tax Totals By order" do it "generates the report" do order.recreate_all_fees! - OrderWorkflow.new(order).complete! + Orders::WorkflowService.new(order).complete! visit_sales_tax_totals_by_order @@ -319,7 +319,7 @@ describe "Sales Tax Totals By order" do before do order.recreate_all_fees! - OrderWorkflow.new(order).complete! + Orders::WorkflowService.new(order).complete! customer2.update!({ first_name: 'c2fname', last_name: 'c2lname', code: 'DEF456' }) order2.line_items.create({ variant:, quantity: 1, price: 200 }) @@ -331,7 +331,7 @@ describe "Sales Tax Totals By order" do email: 'order2@example.com' }) order2.recreate_all_fees! - OrderWorkflow.new(order2).complete! + Orders::WorkflowService.new(order2).complete! visit_sales_tax_totals_by_order end From 778ed46d50ae4139cf3f43f47249257b22196bb4 Mon Sep 17 00:00:00 2001 From: Feruz Oripov Date: Sat, 16 Mar 2024 19:14:18 +0500 Subject: [PATCH 2/3] cops --- spec/jobs/order_cycle_opened_job_spec.rb | 4 ++-- spec/models/proxy_order_spec.rb | 4 ++-- spec/services/order_cycles/webhook_service_spec.rb | 4 ++-- spec/services/orders/checkout_restart_service_spec.rb | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/spec/jobs/order_cycle_opened_job_spec.rb b/spec/jobs/order_cycle_opened_job_spec.rb index c36421480b..b0ebfbe927 100644 --- a/spec/jobs/order_cycle_opened_job_spec.rb +++ b/spec/jobs/order_cycle_opened_job_spec.rb @@ -18,10 +18,10 @@ describe OrderCycleOpenedJob do .to receive(:create_webhook_job).with(oc_opened_now, 'order_cycle.opened') expect(OrderCycles::WebhookService) - .to_not receive(:create_webhook_job).with(oc_opened_before, 'order_cycle.opened') + .not_to receive(:create_webhook_job).with(oc_opened_before, 'order_cycle.opened') expect(OrderCycles::WebhookService) - .to_not receive(:create_webhook_job).with(oc_opening_soon, 'order_cycle.opened') + .not_to receive(:create_webhook_job).with(oc_opening_soon, 'order_cycle.opened') OrderCycleOpenedJob.perform_now end diff --git a/spec/models/proxy_order_spec.rb b/spec/models/proxy_order_spec.rb index 5965521c27..0061284d5b 100644 --- a/spec/models/proxy_order_spec.rb +++ b/spec/models/proxy_order_spec.rb @@ -205,8 +205,8 @@ describe ProxyOrder, type: :model do end it "returns the existing order" do - expect(Orders::FactoryService).to_not receive(:new) - expect(proxy_order).to_not receive(:save!) + expect(Orders::FactoryService).not_to receive(:new) + expect(proxy_order).not_to receive(:save!) expect(proxy_order.initialise_order!).to eq existing_order end end diff --git a/spec/services/order_cycles/webhook_service_spec.rb b/spec/services/order_cycles/webhook_service_spec.rb index 45841f8e1b..060607b8f9 100644 --- a/spec/services/order_cycles/webhook_service_spec.rb +++ b/spec/services/order_cycles/webhook_service_spec.rb @@ -22,7 +22,7 @@ describe OrderCycles::WebhookService do coordinator_user.webhook_endpoints.create!(url: "http://coordinator_user_url") expect{ OrderCycles::WebhookService.create_webhook_job(order_cycle, "order_cycle.opened") } - .to_not enqueue_job(WebhookDeliveryJob).with("http://coordinator_user_url", any_args) + .not_to enqueue_job(WebhookDeliveryJob).with("http://coordinator_user_url", any_args) end context "coordinator owner has endpoint configured" do @@ -134,7 +134,7 @@ describe OrderCycles::WebhookService do expect{ OrderCycles::WebhookService.create_webhook_job(order_cycle, "order_cycle.opened") } - .to_not enqueue_job(WebhookDeliveryJob).with("http://supplier_owner_url", any_args) + .not_to enqueue_job(WebhookDeliveryJob).with("http://supplier_owner_url", any_args) end end end diff --git a/spec/services/orders/checkout_restart_service_spec.rb b/spec/services/orders/checkout_restart_service_spec.rb index f8f051c5b9..414838e31b 100644 --- a/spec/services/orders/checkout_restart_service_spec.rb +++ b/spec/services/orders/checkout_restart_service_spec.rb @@ -8,7 +8,7 @@ describe Orders::CheckoutRestartService do describe "#call" do context "when the order is already in the 'cart' state" do it "does nothing" do - expect(order).to_not receive(:restart_checkout!) + expect(order).not_to receive(:restart_checkout!) Orders::CheckoutRestartService.new(order).call end end From bdcb0856af896ae819a78fa81b74a547b5eea0c4 Mon Sep 17 00:00:00 2001 From: Feruz Oripov Date: Sat, 16 Mar 2024 19:23:17 +0500 Subject: [PATCH 3/3] Fix failed specs --- .../sales_tax/sales_tax_totals_by_producer_spec.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/system/admin/reports/sales_tax/sales_tax_totals_by_producer_spec.rb b/spec/system/admin/reports/sales_tax/sales_tax_totals_by_producer_spec.rb index b1d319b887..da3244cef5 100644 --- a/spec/system/admin/reports/sales_tax/sales_tax_totals_by_producer_spec.rb +++ b/spec/system/admin/reports/sales_tax/sales_tax_totals_by_producer_spec.rb @@ -70,7 +70,7 @@ describe "Sales Tax Totals By Producer" do ship_address_id: ship_address.id }) - OrderWorkflow.new(order).complete! + Orders::WorkflowService.new(order).complete! end it "generates the report" do @@ -128,7 +128,7 @@ describe "Sales Tax Totals By Producer" do ship_address_id: ship_address.id }) - OrderWorkflow.new(order).complete! + Orders::WorkflowService.new(order).complete! end it 'generates the report' do @@ -177,7 +177,7 @@ describe "Sales Tax Totals By Producer" do ship_address_id: ship_address.id }) - OrderWorkflow.new(order).complete! + Orders::WorkflowService.new(order).complete! end it "generates the report" do login_as admin @@ -353,7 +353,7 @@ describe "Sales Tax Totals By Producer" do ship_address_id: customer1.bill_address_id, customer_id: customer1.id }) - OrderWorkflow.new(order).complete! + Orders::WorkflowService.new(order).complete! order2.line_items.create({ variant:, quantity: 1, price: 200 }) order2.update!({ @@ -361,7 +361,7 @@ describe "Sales Tax Totals By Producer" do ship_address_id: customer2.bill_address_id, customer_id: customer2.id }) - OrderWorkflow.new(order2).complete! + Orders::WorkflowService.new(order2).complete! login_as admin visit admin_reports_path click_on 'Sales Tax Totals By Producer'