diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index b4ef66b1821..5bd856f79d9 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -512,7 +512,6 @@ Style/AccessorGrouping:
     - "core/app/models/spree/order.rb"
     - "core/lib/generators/spree/dummy/dummy_generator.rb"
     - "core/lib/spree/core/search/base.rb"
-    - "core/lib/spree/core/state_machines/order.rb"
     - "core/lib/spree/core/stock_configuration.rb"
 
 # Offense count: 1
diff --git a/core/app/models/spree/core/state_machines/inventory_unit.rb b/core/app/models/spree/core/state_machines/inventory_unit.rb
new file mode 100644
index 00000000000..4bc743a4427
--- /dev/null
+++ b/core/app/models/spree/core/state_machines/inventory_unit.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+module Spree
+  module Core
+    class StateMachines
+      # Inventory Units' state machine
+      #
+      # for each event the following instance methods are dynamically implemented:
+      #   #<event_name>
+      #   #<event_name>!
+      #   #can_<event_name>?
+      #
+      # for each state the following instance methods are implemented:
+      #   #<state_name>?
+      #
+      module InventoryUnit
+        extend ActiveSupport::Concern
+
+        included do
+          state_machine initial: :on_hand do
+            event :fill_backorder do
+              transition to: :on_hand, from: :backordered
+            end
+            after_transition on: :fill_backorder, do: :fulfill_order
+
+            event :ship do
+              transition to: :shipped, if: :allow_ship?
+            end
+
+            event :return do
+              transition to: :returned, from: :shipped
+            end
+
+            event :cancel do
+              transition to: :canceled, from: ::Spree::InventoryUnit::CANCELABLE_STATES.map(&:to_sym)
+            end
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/core/app/models/spree/core/state_machines/order.rb b/core/app/models/spree/core/state_machines/order.rb
new file mode 100644
index 00000000000..691b20e212a
--- /dev/null
+++ b/core/app/models/spree/core/state_machines/order.rb
@@ -0,0 +1,250 @@
+# frozen_string_literal: true
+
+module Spree
+  module Core
+    class StateMachines
+      module Order
+        def self.included(klass)
+          klass.extend ClassMethods
+        end
+
+        module ClassMethods
+          attr_accessor :previous_states
+          attr_writer :next_event_transitions, :checkout_steps, :removed_transitions
+
+          def checkout_flow(&block)
+            if block_given?
+              @checkout_flow = block
+              define_state_machine!
+            else
+              @checkout_flow
+            end
+          end
+
+          def define_state_machine!
+            self.checkout_steps = {}
+            self.next_event_transitions = []
+            self.previous_states = [:cart]
+            self.removed_transitions = []
+
+            # Build the checkout flow using the checkout_flow defined either
+            # within the Order class, or a decorator for that class.
+            #
+            # This method may be called multiple times depending on if the
+            # checkout_flow is re-defined in a decorator or not.
+            instance_eval(&checkout_flow)
+
+            klass = self
+
+            # To avoid multiple occurrences of the same transition being defined
+            # On first definition, state_machines will not be defined
+            state_machines.clear if respond_to?(:state_machines)
+            state_machine :state, initial: :cart, use_transactions: false do
+              klass.next_event_transitions.each { |state| transition(state.merge(on: :next)) }
+
+              # Persist the state on the order
+              after_transition do |order, transition|
+                # Hard to say if this is really necessary, it was introduced in this commit:
+                # https://github.com/mamhoff/solidus/commit/fa1d66c42e4c04ee7cd1c20d87e4cdb74a226d3d
+                # But it seems to be harmless, so we'll keep it for now.
+                order.state = order.state # rubocop:disable Lint/SelfAssignment
+
+                order.state_changes.create(
+                  previous_state: transition.from,
+                  next_state:     transition.to,
+                  name:           'order',
+                  user_id:        order.user_id
+                )
+                order.save
+              end
+
+              event :cancel do
+                transition to: :canceled, if: :allow_cancel?, from: :complete
+              end
+
+              event :return do
+                transition to: :returned, from: [:complete, :awaiting_return], if: :all_inventory_units_returned?
+              end
+
+              event :resume do
+                transition to: :resumed, from: :canceled, if: :canceled?
+              end
+
+              event :authorize_return do
+                transition to: :awaiting_return, from: :complete
+              end
+
+              event :complete do
+                transition to: :complete, from: klass.checkout_steps.keys.last
+              end
+
+              if states[:payment]
+                event :payment_failed do
+                  transition to: :payment, from: :confirm
+                end
+
+                after_transition to: :complete, do: :add_payment_sources_to_wallet
+                before_transition to: :payment, do: :add_default_payment_from_wallet
+                before_transition to: :payment, do: :ensure_billing_address
+
+                before_transition to: :confirm, do: :add_store_credit_payments
+
+                # see also process_payments_before_complete below which needs to
+                # be added in the correct sequence.
+              end
+
+              before_transition from: :cart, do: :ensure_line_items_present
+
+              if states[:address]
+                before_transition to: :address, do: :assign_default_user_addresses
+                before_transition from: :address, do: :persist_user_address!
+              end
+
+              if states[:delivery]
+                before_transition to: :delivery, do: :ensure_shipping_address
+                before_transition to: :delivery, do: :create_proposed_shipments
+                before_transition to: :delivery, do: :ensure_available_shipping_rates
+              end
+
+              before_transition to: :resumed, do: :ensure_line_item_variants_are_not_deleted
+              before_transition to: :resumed, do: :validate_line_item_availability
+
+              # Sequence of before_transition to: :complete
+              # calls matter so that we do not process payments
+              # until validations have passed
+              before_transition to: :complete, do: :validate_line_item_availability
+              before_transition to: :complete, do: :ensure_promotions_eligible
+              before_transition to: :complete, do: :ensure_line_item_variants_are_not_deleted
+              before_transition to: :complete, do: :ensure_inventory_units
+              if states[:payment]
+                before_transition to: :complete, do: :process_payments_before_complete
+              end
+
+              after_transition to: :complete, do: :finalize
+              after_transition to: :resumed,  do: :after_resume
+              after_transition to: :canceled, do: :after_cancel
+
+              after_transition from: any - :cart, to: any - [:confirm, :complete] do |order|
+                order.recalculate
+              end
+
+              after_transition do |order, transition|
+                order.logger.debug "Order #{order.number} transitioned from #{transition.from} to #{transition.to} via #{transition.event}"
+              end
+
+              after_failure do |order, transition|
+                order.logger.debug "Order #{order.number} halted transition on event #{transition.event} state #{transition.from}: #{order.errors.full_messages.join}"
+              end
+            end
+          end
+
+          def go_to_state(name, options = {})
+            checkout_steps[name] = options
+            previous_states.each do |state|
+              add_transition({ from: state, to: name }.merge(options))
+            end
+            if options[:if]
+              previous_states << name
+            else
+              self.previous_states = [name]
+            end
+          end
+
+          def insert_checkout_step(name, options = {})
+            before = options.delete(:before)
+            after = options.delete(:after) unless before
+            after = checkout_steps.keys.last unless before || after
+
+            cloned_steps = checkout_steps.clone
+            cloned_removed_transitions = removed_transitions.clone
+            checkout_flow do
+              cloned_steps.each_pair do |key, value|
+                go_to_state(name, options) if key == before
+                go_to_state(key, value)
+                go_to_state(name, options) if key == after
+              end
+              cloned_removed_transitions.each do |transition|
+                remove_transition(transition)
+              end
+            end
+          end
+
+          def remove_checkout_step(name)
+            cloned_steps = checkout_steps.clone
+            cloned_removed_transitions = removed_transitions.clone
+            checkout_flow do
+              cloned_steps.each_pair do |key, value|
+                go_to_state(key, value) unless key == name
+              end
+              cloned_removed_transitions.each do |transition|
+                remove_transition(transition)
+              end
+            end
+          end
+
+          def remove_transition(options = {})
+            removed_transitions << options
+            next_event_transitions.delete(find_transition(options))
+          end
+
+          def find_transition(options = {})
+            return nil if options.nil? || !options.include?(:from) || !options.include?(:to)
+
+            next_event_transitions.detect do |transition|
+              transition[options[:from].to_sym] == options[:to].to_sym
+            end
+          end
+
+          def next_event_transitions
+            @next_event_transitions ||= []
+          end
+
+          def checkout_steps
+            @checkout_steps ||= {}
+          end
+
+          def checkout_step_names
+            checkout_steps.keys
+          end
+
+          def add_transition(options)
+            next_event_transitions << { options.delete(:from) => options.delete(:to) }.merge(options)
+          end
+
+          def removed_transitions
+            @removed_transitions ||= []
+          end
+        end
+
+        def checkout_steps
+          steps = self.class.checkout_steps.each_with_object([]) { |(step, options), checkout_steps|
+            next if options.include?(:if) && !options[:if].call(self)
+
+            checkout_steps << step
+          }.map(&:to_s)
+          # Ensure there is always a complete step
+          steps << "complete" unless steps.include?("complete")
+          steps
+        end
+
+        def has_checkout_step?(step)
+          step.present? && checkout_steps.include?(step)
+        end
+
+        def passed_checkout_step?(step)
+          has_checkout_step?(step) && checkout_step_index(step) < checkout_step_index(state)
+        end
+
+        def checkout_step_index(step)
+          checkout_steps.index(step).to_i
+        end
+
+        def can_go_to_state?(state)
+          return false unless has_checkout_step?(self.state) && has_checkout_step?(state)
+
+          checkout_step_index(state) > checkout_step_index(self.state)
+        end
+      end
+    end
+  end
+end
diff --git a/core/app/models/spree/core/state_machines/payment.rb b/core/app/models/spree/core/state_machines/payment.rb
new file mode 100644
index 00000000000..9c0ba3cdd97
--- /dev/null
+++ b/core/app/models/spree/core/state_machines/payment.rb
@@ -0,0 +1,61 @@
+# frozen_string_literal: true
+
+module Spree
+  module Core
+    class StateMachines
+      # Payments' state machine
+      #
+      # for each event the following instance methods are dynamically implemented:
+      #   #<event_name>
+      #   #<event_name>!
+      #   #can_<event_name>?
+      #
+      # for each state the following instance methods are implemented:
+      #   #<state_name>?
+      #
+      module Payment
+        extend ActiveSupport::Concern
+
+        included do
+          state_machine initial: :checkout do
+            # With card payments, happens before purchase or authorization happens
+            #
+            # Setting it after creating a profile and authorizing a full amount will
+            # prevent the payment from being authorized again once Order transitions
+            # to complete
+            event :started_processing do
+              transition from: [:checkout, :pending, :completed, :processing], to: :processing
+            end
+            # When processing during checkout fails
+            event :failure do
+              transition from: [:pending, :processing], to: :failed
+            end
+            # With card payments this represents authorizing the payment
+            event :pend do
+              transition from: [:checkout, :processing], to: :pending
+            end
+            # With card payments this represents completing a purchase or capture transaction
+            event :complete do
+              transition from: [:processing, :pending, :checkout], to: :completed
+            end
+            event :void do
+              transition from: [:pending, :processing, :completed, :checkout], to: :void
+            end
+            # when the card brand isnt supported
+            event :invalidate do
+              transition from: [:checkout], to: :invalid
+            end
+
+            after_transition do |payment, transition|
+              payment.state_changes.create!(
+                previous_state: transition.from,
+                next_state:     transition.to,
+                name:           'payment'
+              )
+            end
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/core/app/models/spree/core/state_machines/reimbursement.rb b/core/app/models/spree/core/state_machines/reimbursement.rb
new file mode 100644
index 00000000000..ecb449a5351
--- /dev/null
+++ b/core/app/models/spree/core/state_machines/reimbursement.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+module Spree
+  module Core
+    class StateMachines
+      # Reimbursement' state machine
+      #
+      # for each event the following instance methods are dynamically implemented:
+      #   #<event_name>
+      #   #<event_name>!
+      #   #can_<event_name>?
+      #
+      # for each state the following instance methods are implemented:
+      #   #<state_name>?
+      #
+      module Reimbursement
+        extend ActiveSupport::Concern
+
+        included do
+          state_machine :reimbursement_status, initial: :pending do
+            event :errored do
+              transition to: :errored, from: [:pending, :errored]
+            end
+
+            event :reimbursed do
+              transition to: :reimbursed, from: [:pending, :errored]
+            end
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/core/app/models/spree/core/state_machines/return_authorization.rb b/core/app/models/spree/core/state_machines/return_authorization.rb
new file mode 100644
index 00000000000..1ecb27da86b
--- /dev/null
+++ b/core/app/models/spree/core/state_machines/return_authorization.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+module Spree
+  module Core
+    class StateMachines
+      # Return Authorizations' state machine
+      #
+      # for each event the following instance methods are dynamically implemented:
+      #   #<event_name>
+      #   #<event_name>!
+      #   #can_<event_name>?
+      #
+      # for each state the following instance methods are implemented:
+      #   #<state_name>?
+      #
+      module ReturnAuthorization
+        extend ActiveSupport::Concern
+
+        included do
+          state_machine initial: :authorized do
+            before_transition to: :canceled, do: :cancel_return_items
+
+            event :cancel do
+              transition to: :canceled, from: :authorized,
+                if: lambda { |return_authorization| return_authorization.can_cancel_return_items? }
+            end
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/core/app/models/spree/core/state_machines/return_item/acceptance_status.rb b/core/app/models/spree/core/state_machines/return_item/acceptance_status.rb
new file mode 100644
index 00000000000..1009fbd747c
--- /dev/null
+++ b/core/app/models/spree/core/state_machines/return_item/acceptance_status.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+module Spree
+  module Core
+    class StateMachines
+      module ReturnItem
+        # Return Items' acceptance status state machine
+        #
+        # for each event the following instance methods are dynamically implemented:
+        #   #<event_name>
+        #   #<event_name>!
+        #   #can_<event_name>?
+        #
+        # for each state the following instance methods are implemented:
+        #   #<state_name>?
+        #
+        module AcceptanceStatus
+          extend ActiveSupport::Concern
+
+          included do
+            state_machine :acceptance_status, initial: :pending do
+              event :attempt_accept do
+                transition to: :accepted, from: :accepted
+                transition to: :accepted, from: :pending, if: ->(return_item) { return_item.eligible_for_return? }
+                transition to: :manual_intervention_required, from: :pending, if: ->(return_item) { return_item.requires_manual_intervention? }
+                transition to: :rejected, from: :pending
+              end
+
+              # bypasses eligibility checks
+              event :accept do
+                transition to: :accepted, from: [:accepted, :pending, :manual_intervention_required]
+              end
+
+              # bypasses eligibility checks
+              event :reject do
+                transition to: :rejected, from: [:accepted, :pending, :manual_intervention_required]
+              end
+
+              # bypasses eligibility checks
+              event :require_manual_intervention do
+                transition to: :manual_intervention_required, from: [:accepted, :pending, :manual_intervention_required]
+              end
+
+              after_transition any => any, do: :persist_acceptance_status_errors
+            end
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/core/app/models/spree/core/state_machines/return_item/reception_status.rb b/core/app/models/spree/core/state_machines/return_item/reception_status.rb
new file mode 100644
index 00000000000..fa71fe83c6c
--- /dev/null
+++ b/core/app/models/spree/core/state_machines/return_item/reception_status.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+module Spree
+  module Core
+    class StateMachines
+      module ReturnItem
+        # Return Items' reception status state machine
+        #
+        # for each event the following instance methods are dynamically implemented:
+        #   #<event_name>
+        #   #<event_name>!
+        #   #can_<event_name>?
+        #
+        # for each state the following instance methods are implemented:
+        #   #<state_name>?
+        #
+        module ReceptionStatus
+          extend ActiveSupport::Concern
+
+          included do
+            state_machine :reception_status, initial: :awaiting do
+              after_transition to: ::Spree::ReturnItem::COMPLETED_RECEPTION_STATUSES, do: :attempt_accept, if: :can_attempt_accept?
+              after_transition to: ::Spree::ReturnItem::COMPLETED_RECEPTION_STATUSES, do: :check_unexchange
+              after_transition to: :received, do: :process_inventory_unit!
+
+              event(:cancel) { transition to: :cancelled, from: :awaiting }
+
+              event(:receive) { transition to: :received, from: ::Spree::ReturnItem::INTERMEDIATE_RECEPTION_STATUSES + [:awaiting] }
+              event(:unexchange) { transition to: :unexchanged, from: [:awaiting] }
+              event(:give) { transition to: :given_to_customer, from: :awaiting }
+              event(:lost) { transition to: :lost_in_transit, from: :awaiting }
+              event(:wrong_item_shipped) { transition to: :shipped_wrong_item, from: :awaiting }
+              event(:short_shipped) { transition to: :short_shipped, from: :awaiting }
+              event(:in_transit) { transition to: :in_transit, from: :awaiting }
+              event(:expired) { transition to: :expired, from: :awaiting }
+            end
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/core/app/models/spree/core/state_machines/shipment.rb b/core/app/models/spree/core/state_machines/shipment.rb
new file mode 100644
index 00000000000..33ced9b991e
--- /dev/null
+++ b/core/app/models/spree/core/state_machines/shipment.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+module Spree
+  module Core
+    class StateMachines
+      # Shipments' state machine
+      #
+      # for each event the following instance methods are dynamically implemented:
+      #   #<event_name>
+      #   #<event_name>!
+      #   #can_<event_name>?
+      #
+      # for each state the following instance methods are implemented:
+      #   #<state_name>?
+      #
+      module Shipment
+        extend ActiveSupport::Concern
+
+        included do
+          state_machine initial: :pending, use_transactions: false do
+            event :ready do
+              transition from: :pending, to: :shipped, if: :can_transition_from_pending_to_shipped?
+              transition from: :pending, to: :ready, if: :can_transition_from_pending_to_ready?
+            end
+
+            event :pend do
+              transition from: :ready, to: :pending
+            end
+
+            event :ship do
+              transition from: [:ready, :canceled], to: :shipped
+            end
+            after_transition to: :shipped, do: :after_ship
+
+            event :cancel do
+              transition to: :canceled, from: [:pending, :ready]
+            end
+            after_transition to: :canceled, do: :after_cancel
+
+            event :resume do
+              transition from: :canceled, to: :ready, if: :can_transition_from_canceled_to_ready?
+              transition from: :canceled, to: :pending
+            end
+            after_transition from: :canceled, to: [:pending, :ready, :shipped], do: :after_resume
+
+            after_transition do |shipment, transition|
+              shipment.state_changes.create!(
+                previous_state: transition.from,
+                next_state:     transition.to,
+                name:           'shipment'
+              )
+            end
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/core/lib/spree/core/state_machines.rb b/core/lib/spree/core/state_machines.rb
index f8e629b37db..7bb9d373543 100644
--- a/core/lib/spree/core/state_machines.rb
+++ b/core/lib/spree/core/state_machines.rb
@@ -2,87 +2,54 @@
 
 module Spree
   module Core
-    class StateMachines
-      attr_writer :reimbursement,
-                  :return_authorization,
-                  :return_item_acceptance,
-                  :return_item_reception,
-                  :payment,
-                  :inventory_unit,
-                  :shipment,
-                  :order
-
-      def return_authorization
-        @return_authorization ||= begin
-          require 'spree/core/state_machines/return_authorization'
-          'Spree::Core::StateMachines::ReturnAuthorization'
-        end
-
-        @return_authorization.constantize
-      end
-
-      def return_item_reception
-        @return_item_reception_status ||= begin
-          require 'spree/core/state_machines/return_item/reception_status'
-          'Spree::Core::StateMachines::ReturnItem::ReceptionStatus'
-        end
-
-        @return_item_reception_status.constantize
-      end
-
-      def return_item_acceptance
-        @return_item_acceptance_status ||= begin
-          require 'spree/core/state_machines/return_item/acceptance_status'
-          'Spree::Core::StateMachines::ReturnItem::AcceptanceStatus'
-        end
-
-        @return_item_acceptance_status.constantize
-      end
-
-      def payment
-        @payment ||= begin
-          require 'spree/core/state_machines/payment'
-          'Spree::Core::StateMachines::Payment'
-        end
-
-        @payment.constantize
-      end
-
-      def inventory_unit
-        @inventory_unit ||= begin
-          require 'spree/core/state_machines/inventory_unit'
-          'Spree::Core::StateMachines::InventoryUnit'
-        end
-
-        @inventory_unit.constantize
-      end
-
-      def shipment
-        @shipment ||= begin
-          require 'spree/core/state_machines/shipment'
-          'Spree::Core::StateMachines::Shipment'
-        end
-
-        @shipment.constantize
-      end
-
-      def order
-        @order ||= begin
-          require 'spree/core/state_machines/order'
-          'Spree::Core::StateMachines::Order'
-        end
-
-        @order.constantize
-      end
-
-      def reimbursement
-        @reimbursement ||= begin
-          require 'spree/core/state_machines/reimbursement'
-          'Spree::Core::StateMachines::Reimbursement'
-        end
-
-        @reimbursement.constantize
-      end
+    class StateMachines < Spree::Preferences::Configuration
+      # State Machine module for Reimbursements
+      #
+      # @!attribute [rw] reimbursement
+      # @return [Module] a module that implements the state machine for the `Spree::Reimbursement` model.
+      class_name_attribute :reimbursement, default: "Spree::Core::StateMachines::Reimbursement"
+
+      # State Machine module for Return Authorizations
+      #
+      # @!attribute [rw] return_authorization
+      # @return [Module] a module that implements the state machine for the `Spree::ReturnAuthorization` model.
+      class_name_attribute :return_authorization, default: "Spree::Core::StateMachines::ReturnAuthorization"
+
+      # State Machine module for Return Item Acceptances
+      #
+      # @!attribute [rw] return_item_acceptance
+      # @return [Module] a module that implements the acceptance part of the state machine for the `Spree::ReturnItem` model.
+      class_name_attribute :return_item_acceptance, default: "Spree::Core::StateMachines::ReturnItem::AcceptanceStatus"
+
+      # State Machine module for Return Item Receptions
+      #
+      # @!attribute [rw] return_item_reception
+      # @return [Module] a module that implements the reception part of the state machine for the `Spree::ReturnItem` model.
+      class_name_attribute :return_item_reception, default: "Spree::Core::StateMachines::ReturnItem::ReceptionStatus"
+
+      # State Machine module for Payments
+      #
+      # @!attribute [rw] payment
+      # @return [Module] a module that implements the state machine for the `Spree::Payment` model.
+      class_name_attribute :payment, default: "Spree::Core::StateMachines::Payment"
+
+      # State Machine module for Inventory Units
+      #
+      # @!attribute [rw] inventory_unit
+      # @return [Module] a module that implements the state machine for the `Spree::InventoryUnit` model.
+      class_name_attribute :inventory_unit, default: "Spree::Core::StateMachines::InventoryUnit"
+
+      # State Machine module for Shipments
+      #
+      # @!attribute [rw] shipment
+      # @return [Module] a module that implements the state machine for the `Spree::Shipment` model.
+      class_name_attribute :shipment, default: "Spree::Core::StateMachines::Shipment"
+
+      # State Machine module for Orders
+      #
+      # @!attribute [rw] order
+      # @return [Module] a module that implements the state machine for the `Spree::Order` model.
+      class_name_attribute :order, default: "Spree::Core::StateMachines::Order"
     end
   end
 end
diff --git a/core/lib/spree/core/state_machines/inventory_unit.rb b/core/lib/spree/core/state_machines/inventory_unit.rb
index 4bc743a4427..72f6898b795 100644
--- a/core/lib/spree/core/state_machines/inventory_unit.rb
+++ b/core/lib/spree/core/state_machines/inventory_unit.rb
@@ -1,42 +1,7 @@
 # frozen_string_literal: true
 
-module Spree
-  module Core
-    class StateMachines
-      # Inventory Units' state machine
-      #
-      # for each event the following instance methods are dynamically implemented:
-      #   #<event_name>
-      #   #<event_name>!
-      #   #can_<event_name>?
-      #
-      # for each state the following instance methods are implemented:
-      #   #<state_name>?
-      #
-      module InventoryUnit
-        extend ActiveSupport::Concern
-
-        included do
-          state_machine initial: :on_hand do
-            event :fill_backorder do
-              transition to: :on_hand, from: :backordered
-            end
-            after_transition on: :fill_backorder, do: :fulfill_order
-
-            event :ship do
-              transition to: :shipped, if: :allow_ship?
-            end
-
-            event :return do
-              transition to: :returned, from: :shipped
-            end
-
-            event :cancel do
-              transition to: :canceled, from: ::Spree::InventoryUnit::CANCELABLE_STATES.map(&:to_sym)
-            end
-          end
-        end
-      end
-    end
-  end
-end
+Spree.deprecator.warn(
+  <<~MSG
+    The file "#{__FILE__}" does not need to be `require`d any longer, it is now autoloaded.
+  MSG
+)
diff --git a/core/lib/spree/core/state_machines/order.rb b/core/lib/spree/core/state_machines/order.rb
index c52e107fe52..72f6898b795 100644
--- a/core/lib/spree/core/state_machines/order.rb
+++ b/core/lib/spree/core/state_machines/order.rb
@@ -1,252 +1,7 @@
 # frozen_string_literal: true
 
-module Spree
-  module Core
-    class StateMachines
-      module Order
-        def self.included(klass)
-          klass.extend ClassMethods
-        end
-
-        module ClassMethods
-          attr_accessor :previous_states
-          attr_writer :next_event_transitions
-          attr_writer :checkout_steps
-          attr_writer :removed_transitions
-
-          def checkout_flow(&block)
-            if block_given?
-              @checkout_flow = block
-              define_state_machine!
-            else
-              @checkout_flow
-            end
-          end
-
-          def define_state_machine!
-            self.checkout_steps = {}
-            self.next_event_transitions = []
-            self.previous_states = [:cart]
-            self.removed_transitions = []
-
-            # Build the checkout flow using the checkout_flow defined either
-            # within the Order class, or a decorator for that class.
-            #
-            # This method may be called multiple times depending on if the
-            # checkout_flow is re-defined in a decorator or not.
-            instance_eval(&checkout_flow)
-
-            klass = self
-
-            # To avoid multiple occurrences of the same transition being defined
-            # On first definition, state_machines will not be defined
-            state_machines.clear if respond_to?(:state_machines)
-            state_machine :state, initial: :cart, use_transactions: false do
-              klass.next_event_transitions.each { |state| transition(state.merge(on: :next)) }
-
-              # Persist the state on the order
-              after_transition do |order, transition|
-                # Hard to say if this is really necessary, it was introduced in this commit:
-                # https://github.com/mamhoff/solidus/commit/fa1d66c42e4c04ee7cd1c20d87e4cdb74a226d3d
-                # But it seems to be harmless, so we'll keep it for now.
-                order.state = order.state # rubocop:disable Lint/SelfAssignment
-
-                order.state_changes.create(
-                  previous_state: transition.from,
-                  next_state:     transition.to,
-                  name:           'order',
-                  user_id:        order.user_id
-                )
-                order.save
-              end
-
-              event :cancel do
-                transition to: :canceled, if: :allow_cancel?, from: :complete
-              end
-
-              event :return do
-                transition to: :returned, from: [:complete, :awaiting_return], if: :all_inventory_units_returned?
-              end
-
-              event :resume do
-                transition to: :resumed, from: :canceled, if: :canceled?
-              end
-
-              event :authorize_return do
-                transition to: :awaiting_return, from: :complete
-              end
-
-              event :complete do
-                transition to: :complete, from: klass.checkout_steps.keys.last
-              end
-
-              if states[:payment]
-                event :payment_failed do
-                  transition to: :payment, from: :confirm
-                end
-
-                after_transition to: :complete, do: :add_payment_sources_to_wallet
-                before_transition to: :payment, do: :add_default_payment_from_wallet
-                before_transition to: :payment, do: :ensure_billing_address
-
-                before_transition to: :confirm, do: :add_store_credit_payments
-
-                # see also process_payments_before_complete below which needs to
-                # be added in the correct sequence.
-              end
-
-              before_transition from: :cart, do: :ensure_line_items_present
-
-              if states[:address]
-                before_transition to: :address, do: :assign_default_user_addresses
-                before_transition from: :address, do: :persist_user_address!
-              end
-
-              if states[:delivery]
-                before_transition to: :delivery, do: :ensure_shipping_address
-                before_transition to: :delivery, do: :create_proposed_shipments
-                before_transition to: :delivery, do: :ensure_available_shipping_rates
-              end
-
-              before_transition to: :resumed, do: :ensure_line_item_variants_are_not_deleted
-              before_transition to: :resumed, do: :validate_line_item_availability
-
-              # Sequence of before_transition to: :complete
-              # calls matter so that we do not process payments
-              # until validations have passed
-              before_transition to: :complete, do: :validate_line_item_availability
-              before_transition to: :complete, do: :ensure_promotions_eligible
-              before_transition to: :complete, do: :ensure_line_item_variants_are_not_deleted
-              before_transition to: :complete, do: :ensure_inventory_units
-              if states[:payment]
-                before_transition to: :complete, do: :process_payments_before_complete
-              end
-
-              after_transition to: :complete, do: :finalize
-              after_transition to: :resumed,  do: :after_resume
-              after_transition to: :canceled, do: :after_cancel
-
-              after_transition from: any - :cart, to: any - [:confirm, :complete] do |order|
-                order.recalculate
-              end
-
-              after_transition do |order, transition|
-                order.logger.debug "Order #{order.number} transitioned from #{transition.from} to #{transition.to} via #{transition.event}"
-              end
-
-              after_failure do |order, transition|
-                order.logger.debug "Order #{order.number} halted transition on event #{transition.event} state #{transition.from}: #{order.errors.full_messages.join}"
-              end
-            end
-          end
-
-          def go_to_state(name, options = {})
-            checkout_steps[name] = options
-            previous_states.each do |state|
-              add_transition({ from: state, to: name }.merge(options))
-            end
-            if options[:if]
-              previous_states << name
-            else
-              self.previous_states = [name]
-            end
-          end
-
-          def insert_checkout_step(name, options = {})
-            before = options.delete(:before)
-            after = options.delete(:after) unless before
-            after = checkout_steps.keys.last unless before || after
-
-            cloned_steps = checkout_steps.clone
-            cloned_removed_transitions = removed_transitions.clone
-            checkout_flow do
-              cloned_steps.each_pair do |key, value|
-                go_to_state(name, options) if key == before
-                go_to_state(key, value)
-                go_to_state(name, options) if key == after
-              end
-              cloned_removed_transitions.each do |transition|
-                remove_transition(transition)
-              end
-            end
-          end
-
-          def remove_checkout_step(name)
-            cloned_steps = checkout_steps.clone
-            cloned_removed_transitions = removed_transitions.clone
-            checkout_flow do
-              cloned_steps.each_pair do |key, value|
-                go_to_state(key, value) unless key == name
-              end
-              cloned_removed_transitions.each do |transition|
-                remove_transition(transition)
-              end
-            end
-          end
-
-          def remove_transition(options = {})
-            removed_transitions << options
-            next_event_transitions.delete(find_transition(options))
-          end
-
-          def find_transition(options = {})
-            return nil if options.nil? || !options.include?(:from) || !options.include?(:to)
-
-            next_event_transitions.detect do |transition|
-              transition[options[:from].to_sym] == options[:to].to_sym
-            end
-          end
-
-          def next_event_transitions
-            @next_event_transitions ||= []
-          end
-
-          def checkout_steps
-            @checkout_steps ||= {}
-          end
-
-          def checkout_step_names
-            checkout_steps.keys
-          end
-
-          def add_transition(options)
-            next_event_transitions << { options.delete(:from) => options.delete(:to) }.merge(options)
-          end
-
-          def removed_transitions
-            @removed_transitions ||= []
-          end
-        end
-
-        def checkout_steps
-          steps = self.class.checkout_steps.each_with_object([]) { |(step, options), checkout_steps|
-            next if options.include?(:if) && !options[:if].call(self)
-
-            checkout_steps << step
-          }.map(&:to_s)
-          # Ensure there is always a complete step
-          steps << "complete" unless steps.include?("complete")
-          steps
-        end
-
-        def has_checkout_step?(step)
-          step.present? && checkout_steps.include?(step)
-        end
-
-        def passed_checkout_step?(step)
-          has_checkout_step?(step) && checkout_step_index(step) < checkout_step_index(state)
-        end
-
-        def checkout_step_index(step)
-          checkout_steps.index(step).to_i
-        end
-
-        def can_go_to_state?(state)
-          return false unless has_checkout_step?(self.state) && has_checkout_step?(state)
-
-          checkout_step_index(state) > checkout_step_index(self.state)
-        end
-      end
-    end
-  end
-end
+Spree.deprecator.warn(
+  <<~MSG
+    The file "#{__FILE__}" does not need to be `require`d any longer, it is now autoloaded.
+  MSG
+)
diff --git a/core/lib/spree/core/state_machines/payment.rb b/core/lib/spree/core/state_machines/payment.rb
index 9c0ba3cdd97..72f6898b795 100644
--- a/core/lib/spree/core/state_machines/payment.rb
+++ b/core/lib/spree/core/state_machines/payment.rb
@@ -1,61 +1,7 @@
 # frozen_string_literal: true
 
-module Spree
-  module Core
-    class StateMachines
-      # Payments' state machine
-      #
-      # for each event the following instance methods are dynamically implemented:
-      #   #<event_name>
-      #   #<event_name>!
-      #   #can_<event_name>?
-      #
-      # for each state the following instance methods are implemented:
-      #   #<state_name>?
-      #
-      module Payment
-        extend ActiveSupport::Concern
-
-        included do
-          state_machine initial: :checkout do
-            # With card payments, happens before purchase or authorization happens
-            #
-            # Setting it after creating a profile and authorizing a full amount will
-            # prevent the payment from being authorized again once Order transitions
-            # to complete
-            event :started_processing do
-              transition from: [:checkout, :pending, :completed, :processing], to: :processing
-            end
-            # When processing during checkout fails
-            event :failure do
-              transition from: [:pending, :processing], to: :failed
-            end
-            # With card payments this represents authorizing the payment
-            event :pend do
-              transition from: [:checkout, :processing], to: :pending
-            end
-            # With card payments this represents completing a purchase or capture transaction
-            event :complete do
-              transition from: [:processing, :pending, :checkout], to: :completed
-            end
-            event :void do
-              transition from: [:pending, :processing, :completed, :checkout], to: :void
-            end
-            # when the card brand isnt supported
-            event :invalidate do
-              transition from: [:checkout], to: :invalid
-            end
-
-            after_transition do |payment, transition|
-              payment.state_changes.create!(
-                previous_state: transition.from,
-                next_state:     transition.to,
-                name:           'payment'
-              )
-            end
-          end
-        end
-      end
-    end
-  end
-end
+Spree.deprecator.warn(
+  <<~MSG
+    The file "#{__FILE__}" does not need to be `require`d any longer, it is now autoloaded.
+  MSG
+)
diff --git a/core/lib/spree/core/state_machines/reimbursement.rb b/core/lib/spree/core/state_machines/reimbursement.rb
index ecb449a5351..72f6898b795 100644
--- a/core/lib/spree/core/state_machines/reimbursement.rb
+++ b/core/lib/spree/core/state_machines/reimbursement.rb
@@ -1,33 +1,7 @@
 # frozen_string_literal: true
 
-module Spree
-  module Core
-    class StateMachines
-      # Reimbursement' state machine
-      #
-      # for each event the following instance methods are dynamically implemented:
-      #   #<event_name>
-      #   #<event_name>!
-      #   #can_<event_name>?
-      #
-      # for each state the following instance methods are implemented:
-      #   #<state_name>?
-      #
-      module Reimbursement
-        extend ActiveSupport::Concern
-
-        included do
-          state_machine :reimbursement_status, initial: :pending do
-            event :errored do
-              transition to: :errored, from: [:pending, :errored]
-            end
-
-            event :reimbursed do
-              transition to: :reimbursed, from: [:pending, :errored]
-            end
-          end
-        end
-      end
-    end
-  end
-end
+Spree.deprecator.warn(
+  <<~MSG
+    The file "#{__FILE__}" does not need to be `require`d any longer, it is now autoloaded.
+  MSG
+)
diff --git a/core/lib/spree/core/state_machines/return_authorization.rb b/core/lib/spree/core/state_machines/return_authorization.rb
index 1ecb27da86b..72f6898b795 100644
--- a/core/lib/spree/core/state_machines/return_authorization.rb
+++ b/core/lib/spree/core/state_machines/return_authorization.rb
@@ -1,32 +1,7 @@
 # frozen_string_literal: true
 
-module Spree
-  module Core
-    class StateMachines
-      # Return Authorizations' state machine
-      #
-      # for each event the following instance methods are dynamically implemented:
-      #   #<event_name>
-      #   #<event_name>!
-      #   #can_<event_name>?
-      #
-      # for each state the following instance methods are implemented:
-      #   #<state_name>?
-      #
-      module ReturnAuthorization
-        extend ActiveSupport::Concern
-
-        included do
-          state_machine initial: :authorized do
-            before_transition to: :canceled, do: :cancel_return_items
-
-            event :cancel do
-              transition to: :canceled, from: :authorized,
-                if: lambda { |return_authorization| return_authorization.can_cancel_return_items? }
-            end
-          end
-        end
-      end
-    end
-  end
-end
+Spree.deprecator.warn(
+  <<~MSG
+    The file "#{__FILE__}" does not need to be `require`d any longer, it is now autoloaded.
+  MSG
+)
diff --git a/core/lib/spree/core/state_machines/return_item/acceptance_status.rb b/core/lib/spree/core/state_machines/return_item/acceptance_status.rb
index 1009fbd747c..72f6898b795 100644
--- a/core/lib/spree/core/state_machines/return_item/acceptance_status.rb
+++ b/core/lib/spree/core/state_machines/return_item/acceptance_status.rb
@@ -1,51 +1,7 @@
 # frozen_string_literal: true
 
-module Spree
-  module Core
-    class StateMachines
-      module ReturnItem
-        # Return Items' acceptance status state machine
-        #
-        # for each event the following instance methods are dynamically implemented:
-        #   #<event_name>
-        #   #<event_name>!
-        #   #can_<event_name>?
-        #
-        # for each state the following instance methods are implemented:
-        #   #<state_name>?
-        #
-        module AcceptanceStatus
-          extend ActiveSupport::Concern
-
-          included do
-            state_machine :acceptance_status, initial: :pending do
-              event :attempt_accept do
-                transition to: :accepted, from: :accepted
-                transition to: :accepted, from: :pending, if: ->(return_item) { return_item.eligible_for_return? }
-                transition to: :manual_intervention_required, from: :pending, if: ->(return_item) { return_item.requires_manual_intervention? }
-                transition to: :rejected, from: :pending
-              end
-
-              # bypasses eligibility checks
-              event :accept do
-                transition to: :accepted, from: [:accepted, :pending, :manual_intervention_required]
-              end
-
-              # bypasses eligibility checks
-              event :reject do
-                transition to: :rejected, from: [:accepted, :pending, :manual_intervention_required]
-              end
-
-              # bypasses eligibility checks
-              event :require_manual_intervention do
-                transition to: :manual_intervention_required, from: [:accepted, :pending, :manual_intervention_required]
-              end
-
-              after_transition any => any, do: :persist_acceptance_status_errors
-            end
-          end
-        end
-      end
-    end
-  end
-end
+Spree.deprecator.warn(
+  <<~MSG
+    The file "#{__FILE__}" does not need to be `require`d any longer, it is now autoloaded.
+  MSG
+)
diff --git a/core/lib/spree/core/state_machines/return_item/reception_status.rb b/core/lib/spree/core/state_machines/return_item/reception_status.rb
index fa71fe83c6c..72f6898b795 100644
--- a/core/lib/spree/core/state_machines/return_item/reception_status.rb
+++ b/core/lib/spree/core/state_machines/return_item/reception_status.rb
@@ -1,42 +1,7 @@
 # frozen_string_literal: true
 
-module Spree
-  module Core
-    class StateMachines
-      module ReturnItem
-        # Return Items' reception status state machine
-        #
-        # for each event the following instance methods are dynamically implemented:
-        #   #<event_name>
-        #   #<event_name>!
-        #   #can_<event_name>?
-        #
-        # for each state the following instance methods are implemented:
-        #   #<state_name>?
-        #
-        module ReceptionStatus
-          extend ActiveSupport::Concern
-
-          included do
-            state_machine :reception_status, initial: :awaiting do
-              after_transition to: ::Spree::ReturnItem::COMPLETED_RECEPTION_STATUSES, do: :attempt_accept, if: :can_attempt_accept?
-              after_transition to: ::Spree::ReturnItem::COMPLETED_RECEPTION_STATUSES, do: :check_unexchange
-              after_transition to: :received, do: :process_inventory_unit!
-
-              event(:cancel) { transition to: :cancelled, from: :awaiting }
-
-              event(:receive) { transition to: :received, from: ::Spree::ReturnItem::INTERMEDIATE_RECEPTION_STATUSES + [:awaiting] }
-              event(:unexchange) { transition to: :unexchanged, from: [:awaiting] }
-              event(:give) { transition to: :given_to_customer, from: :awaiting }
-              event(:lost) { transition to: :lost_in_transit, from: :awaiting }
-              event(:wrong_item_shipped) { transition to: :shipped_wrong_item, from: :awaiting }
-              event(:short_shipped) { transition to: :short_shipped, from: :awaiting }
-              event(:in_transit) { transition to: :in_transit, from: :awaiting }
-              event(:expired) { transition to: :expired, from: :awaiting }
-            end
-          end
-        end
-      end
-    end
-  end
-end
+Spree.deprecator.warn(
+  <<~MSG
+    The file "#{__FILE__}" does not need to be `require`d any longer, it is now autoloaded.
+  MSG
+)
diff --git a/core/lib/spree/core/state_machines/shipment.rb b/core/lib/spree/core/state_machines/shipment.rb
index 33ced9b991e..72f6898b795 100644
--- a/core/lib/spree/core/state_machines/shipment.rb
+++ b/core/lib/spree/core/state_machines/shipment.rb
@@ -1,58 +1,7 @@
 # frozen_string_literal: true
 
-module Spree
-  module Core
-    class StateMachines
-      # Shipments' state machine
-      #
-      # for each event the following instance methods are dynamically implemented:
-      #   #<event_name>
-      #   #<event_name>!
-      #   #can_<event_name>?
-      #
-      # for each state the following instance methods are implemented:
-      #   #<state_name>?
-      #
-      module Shipment
-        extend ActiveSupport::Concern
-
-        included do
-          state_machine initial: :pending, use_transactions: false do
-            event :ready do
-              transition from: :pending, to: :shipped, if: :can_transition_from_pending_to_shipped?
-              transition from: :pending, to: :ready, if: :can_transition_from_pending_to_ready?
-            end
-
-            event :pend do
-              transition from: :ready, to: :pending
-            end
-
-            event :ship do
-              transition from: [:ready, :canceled], to: :shipped
-            end
-            after_transition to: :shipped, do: :after_ship
-
-            event :cancel do
-              transition to: :canceled, from: [:pending, :ready]
-            end
-            after_transition to: :canceled, do: :after_cancel
-
-            event :resume do
-              transition from: :canceled, to: :ready, if: :can_transition_from_canceled_to_ready?
-              transition from: :canceled, to: :pending
-            end
-            after_transition from: :canceled, to: [:pending, :ready, :shipped], do: :after_resume
-
-            after_transition do |shipment, transition|
-              shipment.state_changes.create!(
-                previous_state: transition.from,
-                next_state:     transition.to,
-                name:           'shipment'
-              )
-            end
-          end
-        end
-      end
-    end
-  end
-end
+Spree.deprecator.warn(
+  <<~MSG
+    The file "#{__FILE__}" does not need to be `require`d any longer, it is now autoloaded.
+  MSG
+)
diff --git a/core/spec/lib/spree/core/state_machines_spec.rb b/core/spec/lib/spree/core/state_machines_spec.rb
new file mode 100644
index 00000000000..cce9ebde4b3
--- /dev/null
+++ b/core/spec/lib/spree/core/state_machines_spec.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+require "rails_helper"
+
+RSpec.describe "require 'spree/core/state_machines" do
+  %w(
+    inventory_unit
+    order
+    payment
+    reimbursement
+    return_authorization
+    shipment
+    return_item/acceptance_status
+    return_item/reception_status
+  ).each do |helper_name|
+    describe "require 'spree/core/state_machines/#{helper_name}" do
+      it "exists but will print a deprecation warning" do
+        expect(Spree.deprecator).to receive(:warn).with(
+          "The file \"#{Spree::Core::Engine.root}/lib/spree/core/state_machines/#{helper_name}.rb\" does not need to be `require`d any longer, it is now autoloaded.\n"
+        )
+        require "spree/core/state_machines/#{helper_name}"
+      end
+    end
+  end
+end