Basket-order states (order state machine)
Since version 5.11.0, the shop extension has included an order state machine. This allows you to define the following for each Payment Type / Order Type:
- which states exist,
- which state changes are allowed,
- which changes/states are visible in the backend,
- under which conditions a change is offered.
All flows have in common:
They start with prepared and end with processed.
stateDiagram-v2
[*] --> prepared: Order is being prepared (FE customer / BE operator)
prepared --> customSteps: Order placed (order + invoice no. assigned)
customSteps --> processed: Order is finished
processed --> [*]
Payment-Type × Order-State Matrix
| Payment-Type | prepared | ordered | paid | shipped | requested | answered | credited | refunded | canceled | canceled_unpaid | processed |
|---|---|---|---|---|---|---|---|---|---|---|---|
| request (Produkt-Anfrage) | ✔ | – | – | – | ✔ | ✔ | – | – | – | – | ✔ |
| onInvoice (Rechnung) | ✔ | ✔ | ✔ | ✔ | – | – | – | – | – | ✔ | ✔ |
| prePayment (Vorkasse) | ✔ | ✔ | ✔ | ✔ | – | – | – | – | – | ✔ | ✔ |
| sepa (SEPA-Lastschrift) | ✔ | ✔ | ✔ | ✔ | – | – | – | – | – | ✔ | ✔ |
| payPal (PayPal-Wallet) | ✔ | ✔ | ✔ | ✔ | – | – | – | – | ✔ | ✔ | ✔ |
| payPalCheckout | ✔ | ✔ | ✔ | ✔ | – | – | – | – | – | ✔ | ✔ |
| stripe (Kreditkarte etc.) | ✔ | ✔ | ✔ | ✔ | – | – | – | – | – | ✔ | ✔ |
| klarna | ✔ | ✔ | ✔ | ✔ | – | – | – | – | – | ✔ | ✔ |
| manual (manuelle Bestellung) | ✔ | ✔ | ✔ | ✔ | – | – | – | – | – | ✔ | ✔ |
| Return (Retoure) | ✔ | – | – | – | – | – | ✔ | ✔ | – | – | ✔ |
| Storno | ✔ | – | – | – | – | – | – | ✔ | – | – | ✔ |
Note: The matrix describes typical flows. The actually allowed states are determined via the state machine configuration (see below).
Notes on the Statuses
prepared→ Order is in creation status. No order or invoice number has been assigned yet. Only status in which an order can be deleted in the TYPO3 backend (unless it's a basket-order of typerequest).ordered→ Order has been placed; order and invoice numbers have been assigned.paid→ Payment has been recorded/marked.shipped→ Shipment has been recorded (e.g., shipping date set).requested→ Request has been submitted (request workflow).answered→ Request has been answered/closed (request workflow).credited→ Return/credit note order has been created (negative items) and documented.refunded→ Refund/cancellation document has been created or the refund has been documented (depending on the type).canceled→ The order is unpaid and unshipped and should be canceled. This typically results in a new order of typecancellation(counter-statement/cancellation document).canceled_unpaid→ Cancellation of an order (possible depending on the payment method; often linked to a refund).processed→ The order process is complete (final state for the respective flow).
Bestell-Zustandsautomat (order state machine)
Seit Version 5.11.0 hat die Shop-Erweiterung einen Bestell-Zustandsautomaten („state-machine“). Damit definierst Du pro Payment-Type / Order-Type:
- welche States es gibt,
- welche State-Wechsel erlaubt sind,
- welche Wechsel/States im Backend sichtbar sind,
- unter welchen Bedingungen ein Wechsel angeboten wird (Conditions).
Gemeinsamkeit aller Flows:
Sie starten mit prepared und enden mit processed.
stateDiagram-v2
[*] --> prepared : Order is being prepared (FE customer / BE operator)
prepared --> customSteps : Order placed (order + invoice no. assigned)
customSteps --> processed : Order is finished
processed --> [*]
Basic Principle
A state defines the possible subsequent states (transitions). A transition can optionally have a condition. Additionally, a state can be hidden in the backend using a hidden condition.
- allowed: Which target states are reachable from this state?
- condition: When is an allowed transition available?
- hidden: When is a state (or optionally a transition) hidden in the backend?
Important:
- If a state has been reached, only its
allowedtransitions apply. - The state
processedis a final state – however,allowedmust still be defined (empty).
Configuration structure (TypoScript)
The configuration happens in TypoScript:
plugin.tx_shop.settings.basketOrder.orderOptions.<orderType>.status.<state> {
allowed { ... }
hidden { ... }
}
<orderType>is, for example,prePayment,onInvoice,payPal,request,return,storno, …<state>is, for example,prepared,ordered,paid,shipped,processed, …
Example for pre-payment basket-order flow
plugin.tx_shop.settings.basketOrder.orderOptions.prePayment {
status {
prepared {
# In the "prepared" status, the order can only change to "ordered".
allowed {
ordered =
}
}
ordered {
# In the "ordered" status, the order can change to "paid" or "canceled".
allowed {
paid =
canceled =
}
}
paid {
# In the "paid" status, the order can change to "shipped" or "processed".
# The possible states are defined by a condition.
# If multiple conditions are present, they must all be true (AND).
allowed {
shipped {
# Show marked-as-shipped when not "only digital products" are in basket-order
condition {
basket = NotContainsDigitalProductsOnly
}
}
processed {
# Skip shipping step for digital-only orders
condition {
basket = ContainsDigitalProductsOnly
}
}
}
}
shipped {
# Hide whole shipped state when "only digital products" are in basket-order
hidden {
condition {
basket = ContainsDigitalProductsOnly
}
}
# In the status "shipped" the order can only change to "processed".
allowed {
processed =
}
}
canceled {
# In the status "canceled" the order can only change to "processed".
allowed {
processed =
}
}
processed {
# Final state - allowed must exist, but remains empty
allowed =
}
}
}
Reading rule (from the example):
prepared → ordered → paid → shipped → processed
Or (for digital products): paid → processed (without shipping)
Conditions
Conditions control whether a transition (or a complete state) is offered in the backend.
Convention:
- Conditions are structured as "Condition Key → Condition Class" (or resolver).
- A condition is met if the class/logic for the current order evaluates to
true. - Multiple conditions in a block are interpreted as AND.
Conditions:
ContainsDigitalProductsOnlyNotContainsDigitalProductsOnlyNotEmptyEmpty
Typical conditions:
basket = ContainsDigitalProductsOnly: Basket contains only digital productsbasket = NotContainsDigitalProductsOnly: Basket not contains only digital productsbasket = NotEmpty: Basket has itemspaid_date = Empty: Paid date must be emptyordered_date = NotEmpty: Order date must be set
Hide States
A state can be completely hidden in the backend – for example, if a step in the flow is irrelevant for certain orders.
shipped {
hidden {
condition {
basket = ContainsDigitalProductsOnly
}
}
allowed {
processed =
}
}
Result:
- The
shippedstate does not appear for digital-only orders. - The flow can still proceed directly to
processed(via a transition frompaid).
Best Practice: Always Define the End State
Even if processed has no subsequent states, it must exist in the state tree:
processed {
allowed =
}
This ensures the flow is "closed" and the state machine can clearly validate that no further transitions are planned.
Example flows as diagrams
Pre payment basket-order (simplified)
stateDiagram-v2
[*] --> prepared
prepared --> ordered
ordered --> paid
paid --> shipped : physical goods
paid --> processed : digital-only
shipped --> processed
processed --> [*]
Request a basket-order
stateDiagram-v2
[*] --> prepared
prepared --> requested
requested --> answered
answered --> processed
processed --> [*]
Extending the Configuration
You can extend the state machine as needed for each orderOptions.<type>:
- Add new states: Create a state block under
status { ... }. - Add/remove transitions: Adjust
allowed { ... }. - Enforce business rules: Protect transitions with
condition { ... }. - Simplify the UI: Hide irrelevant states using
hidden.condition.
It is important that:
preparedexists as a start state,processedexists as an end state,- Every state has an
allowedblock (even if empty), - No "dead" states exist (states that can never be reached), unless this is intentional.
Typical Pitfalls
- Discounts/Shipping/Taxes do not directly affect the state machine – but your conditions can react to them (e.g., shopping cart contains only digital products).
- State change without a condition means: The change is always available (provided the current state is suitable).
hiddenhides the state, but does not necessarily prevent its existence in the system – it is primarily a UI/backend control.- New order types always require a complete
statusdefinition; otherwise, the flow is unclear.