Order State Machine

An order in an online shop is not just a row in a table; it moves through a lifecycle. It is created, waits for payment, gets packed and shipped, and may be cancelled, returned or refunded. This UML state machine diagram lists every state an order can be in and every legal move between them.

Anything not drawn is not allowed. That is the point: you cannot ship an unpaid order or refund one twice.


1. The Diagram

Order lifecycle Created AwaitingPayment Paid Fulfilment Picking Packed Shipped packed dispatched submit authorized paymentFailed [attempts < 3] allocate Cancelled after(30 min) / releaseStock() cancel [not shipped] / refund() Delivered delivered ReturnRequested returnRequested [≤ 30 days] Refunded received / refund()
  1. The filled dot is the start. A new order is Created; when the customer submits checkout it moves to AwaitingPayment.
  2. A declined card loops back to the same state (yellow self transition) while the guard [attempts < 3] holds.
  3. If no payment arrives within 30 minutes, the time event after(30 min) fires, reserved stock is released, and the order is Cancelled.
  4. A successful authorization moves the order to Paid. It can still be cancelled while the guard [not shipped] is true, and the effect / refund() runs on the way.
  5. Fulfilment is a composite state with its own small machine: Picking, Packed, Shipped. Composite states keep the top level readable.
  6. When the carrier confirms delivery the order is Delivered and may end there. Within 30 days the customer can request a return; once the item is received the refund runs and the order ends as Refunded.

2. How to Read It

Notation used initial state final state StateName state (rounded box) event [guard] / effect transition self transition Composite Sub composite state with substates after(30 min) = time event; [x] = guard; / f() = effect run on the transition

Transition labels follow one pattern: event [guard] / effect. All three parts are optional. Colours here are only emphasis: green for the happy path, yellow for retries and returns, red for cancellation.

3. Variant: Orthogonal Regions

Variant: payment and shipping in parallel Active payment region shipping region Unpaid Paid authorized NotShipped Shipped Delivered dispatched signed Closed Both regions run at the same time; Active completes when each reaches its final state.

Some shops ship before payment clears, for example on invoice terms. Then payment and shipping are independent. UML handles this with orthogonal regions: one composite state split by a dashed line, each region with its own start and end. The order is in one state of each region at once, such as Paid and NotShipped. This avoids drawing every combination as a separate state.

4. Pros and Cons

Pros

Cons

5. When to Use It

Use it when

Skip it when

6. As Diagrams-as-Code

The main diagram written for Mermaid:

stateDiagram-v2
    [*] --> Created
    Created --> AwaitingPayment : submit
    AwaitingPayment --> AwaitingPayment : paymentFailed [attempts < 3]
    AwaitingPayment --> Paid : authorized
    AwaitingPayment --> Cancelled : after(30 min) / releaseStock()
    Paid --> Fulfilment : allocate
    Paid --> Cancelled : cancel [not shipped] / refund()
    state Fulfilment {
        [*] --> Picking
        Picking --> Packed : packed
        Packed --> Shipped : dispatched
    }
    Fulfilment --> Delivered : delivered
    Delivered --> ReturnRequested : returnRequested [<= 30 days]
    ReturnRequested --> Refunded : received / refund()
    Delivered --> [*]
    Cancelled --> [*]
    Refunded --> [*]

PlantUML accepts nearly the same text between @startuml and @enduml. Keep the file next to the code that owns the status enum.