Skip to content

Commit

Permalink
Rewrite split order state machine article
Browse files Browse the repository at this point in the history
  • Loading branch information
benjaminwil committed Feb 14, 2018
1 parent 310a9c6 commit 76c7529
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 32 deletions.
72 changes: 72 additions & 0 deletions guides/orders/order-state-machine.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Order state machine

Orders flow through a state machine, which is defined in the
`Spree::Order::Checkout` module. It begins with a `cart` state and ends with
at a `complete` state.

There are six order states by default:

1. `cart`
2. `address`
3. `delivery`
4. `payment`
5. `confirm`
6. `complete`

If you go through the checkout provided in the `solidus_frontend` gem, you can
see that there is a clearly defined step for each of these states during checkout.

In some circumstances, the `payment` and `confirm` states are optional:

- The `payment` state is only triggered if `payment_required?` returns `true`.
- The `confirm` state is only triggered if `confirmation_required?` returns
`true`.

The `complete` state is triggered in one of two ways:

1. No payment is required on the order. (The `total` equals `0`.)
2. Payment is required on the order, and at least the order total has been
received as payment.

## State criteria

Each order state has criteria that must be met before the state can change. For
example, before the state can change from `cart` to `address`, line items must be
present on the order. Then, to change from `address` to `delivery`, the user
must have a default address assigned.

Once an order meets the criteria to go to the next state, you can call `next` on
the order object to transition into the next state. For example, in the
`solidus_frontend` gem, the [`Spree::CheckoutController`][checkout-controller]
defines a `transition_forward` method that always calls `next` unless the order
can be completed:

```ruby
# /frontend/app/controllers/spree/checkout_controller.rb
def transition_forward
if @order.can_complete?
@order.complete
else
@order.next
end
end
```

If `next` returns `false`, then the order does not meet the criteria and does
not transition to the next state.

[checkout-controller]: https://github.com/solidusio/solidus/blob/master/frontend/app/controllers/spree/checkout_controller.rb

## Payments and shipments have their own state machines

Note that a `Spree::Order` with the state `complete` does not mean that the
payment has been processed or the order shipments have been shipped. See also the
values of the `payment_state` and `shipment_state` attributes.

<!-- TODO:
Once it's merged, link to documentation about checkout. This section only
attempts to summarize some of what happens during the checkout flow.
It may be useful to link to the payments documentation once it's merged, too.
-->

32 changes: 0 additions & 32 deletions guides/orders/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,38 +74,6 @@ information, see the [Display totals methods][display-total-methods] article.
[special-instructions]: ../shipments/user-interface-for-shipments.md#shipping-instructions
[update-orders]: update-orders.md

## The Order State Machine

Orders flow through a state machine, beginning at a `cart` state and ending up
at a `complete` state. The intermediary states can be configured using the
[Checkout Flow API](checkout).

The default states are as follows:

* `cart`
* `address`
* `delivery`
* `payment`
* `confirm`
* `complete`

The `payment` state will only be triggered if `payment_required?` returns
`true`.

The `confirm` state will only be triggered if `confirmation_required?` returns
`true`.

The `complete` state can only be reached in one of two ways:

1. No payment is required on the order.
2. Payment is required on the order, and at least the order total has been
received as payment.

Assuming that an order meets the criteria for the next state, you will be able
to transition it to the next state by calling `next` on that object. If this
returns `false`, then the order does *not* meet the criteria. To work out why it
cannot transition, check the result of an `errors` method call.

## Related models

The `Spree::Order` model touches many other models. This section highlights
Expand Down

0 comments on commit 76c7529

Please sign in to comment.