GuidesGuides

How orders work

An order's life in Era: its statuses, which actions move it, how payment and stock follow it, and the settings that steer it.

From cart to order

An order in Era (sales_order, the orders resource) is born either from a basket at checkout or from a draft someone builds by hand. It then waits to be sent, goes out in one or more despatches, and may come back as a return — or is cancelled or expires on the way. Payment and stock are not fields you set: they follow the order through the actions below.

Statuses (sales_order.status)
                       complete_draft_order
   draft ─────────────────────────────────────┐
     │  (automatically_confirm_orders = off)  │ (on)
     ▼                                        ▼
 unconfirmed ──── confirm_order ──────────► unfulfilled ◄──── complete_checkout / site_place_order
     │                                        │
     └── expire_order ──► expired             │ fulfil_order (part)        fulfil_order (rest)
                                              ├──────────► partially fulfilled ──────────► fulfilled
     cancel_order (from any open status) ──► canceled                                       │
                                                                     return_products / receive_return
                                                                                            ▼
                                                                         partially_returned · returned

The statuses

StatusMeansLines can change
draftBeing built by hand. Not an order yet: no number on the customer's side, no stock held. Can be deleted.yes
unconfirmedPlaced from a draft, waiting for someone to confirm it. Stock is already held.yes
unfulfilledConfirmed and waiting to be sent. Every order from a checkout starts here.no
partially fulfilledSome lines have gone out. (Written with a space — kept from the original shop data on purpose.)no
fulfilledEverything has gone out.no
partially_returned / returnedSome or all of what went out has come back.no
canceledCancelled. Stock it held is released; finance is asked to refund what was paid.no
expiredAn unconfirmed order nobody confirmed in time.no

An order also has an origin: checkout (from a basket) or draft (built by hand); marketplace imports add marketplace.

The actions that move it

Each action is in the shop reference; its section lists every precondition code.

ActionFromToWhat else happens
retail.create_draft_order—draftTakes the next order number. Refused on a closed channel.
retail.set_order_linesdraft, unconfirmedsameReplaces all lines, re-prices, re-applies discounts and tax; freezes draft prices for draft_order_price_freeze_hours.
retail.complete_draft_orderdraftunfulfilled or unconfirmedAllocates stock for every line — all or none (insufficient_stock). Checks shipping address and coupon.
retail.complete_checkouta basketunfulfilledTurns the basket's 15-minute stock reservations into allocations and deletes the basket. Refuses stale prices (prices_stale) and, unless allowed, unpaid baskets (order_not_paid).
retail.site_place_ordera site basketunfulfilledThe website's checkout: places the order first and takes payment right after, so a failed payment leaves an unpaid order rather than a lost one.
retail.confirm_orderunconfirmedunfulfilledNeeds retail:approve.
retail.fulfil_orderunfulfilled, partially fulfilledpartially fulfilled or fulfilledCreates a despatch from named warehouses; lowers shelf stock and writes a stock movement. Never sends more than was ordered (over_fulfilment); a preorder line waits (preorder_not_fulfillable).
retail.cancel_fulfilmenta despatchrecalculatedPuts the stock back on the shelf.
retail.cancel_orderany open statuscanceledNeeds retail:manage. Releases held stock, gives back gift cards and the coupon use. Live despatches must be cancelled first (order_has_fulfilments).
retail.expire_orderunconfirmedexpiredReleases held stock and the coupon. Run every 15 minutes for orders older than expire_orders_after_minutes.
retail.request_returnanything that went outunchangedOpens a return (requested → received → inspected → closed, or rejected). When it is received, the order becomes partially_returned or returned; on inspection resellable goods go back into stock.
retail.return_productsanything that went outpartially_returned or returnedRecords the return directly, without the return workflow and without restocking.
retail.delete_draft_orderdraftremovedPlaced orders are cancelled, never deleted (not_a_draft).

Lines, delivery method and customer can be changed by retail.update_order only while the order is still draft or unconfirmed (the customer also while nothing has gone out).

Payment: charge_status

Payments are not stored on the order. When an order is placed, finance opens an agreement for it; payments recorded against that agreement (by a payment app, a bank transfer, a person in Finance → Collections) are what the order has collected. After every payment, allocation, refund or provider event, Era recomputes the order's charge_status:

charge_statusWhen
noneNothing collected.
partialLess than the amount due.
fullExactly the amount due.
overchargedMore than the amount due.

The amount due is the total plus gift cards, minus refunds already granted. All amounts are whole minor units (kuruş, cents) — total_amount: 125000 is 1,250.00.

Things to know:

  • Sending does not wait for payment. fulfil_order does not check charge_status; if you only ship paid orders, filter for them: GET /api/v1/orders?status=unfulfilled&charge_status=full.
  • Cancelling refunds. When an order is cancelled, finance is asked to refund what was collected for it.
  • Partial refunds are granted with retail.grant_refund (needs retail:manage; never more than the order was sold for). Finance then refunds it from the payment that can cover it — or, if no single payment can, leaves it for a person to send.
  • authorize_status exists on the model but is not used yet: Era does not hold card authorisations separately from charges.

Stock

MomentWhat happens to stock
Item in a basketA reservation for 15 minutes, so two shoppers cannot buy the last one.
Order placed (checkout or draft)Reservations become allocations: the goods are held for this order (quantity_allocated rises). All lines or none.
DespatchShelf count and allocation go down; a stock movement with reason fulfilment is written.
Despatch cancelledGoods go back on the shelf (fulfilment_canceled).
Order cancelled or expiredAllocations are released. Shelf counts do not change — the goods never left.
Return inspectedResellable goods go back on the shelf (returned).

The settings that steer it

In Settings → Shop (/settings/shop):

SettingDefaultEffect
Confirm new orders automatically (automatically_confirm_orders)onA completed draft goes straight to unfulfilled; off, it waits as unconfirmed for confirm_order. Checkout orders always start unfulfilled.
Allow unpaid orders (allow_unpaid_orders)offOff, complete_checkout refuses a basket with nothing paid (order_not_paid). The website's own checkout places the order first and takes payment next, whatever this says.
Approve shipments automatically (fulfilment_auto_approve)onOff, a despatch is created waiting_for_approval (stock already moved) until someone approves it.
Expire unconfirmed orders after (minutes) (expire_orders_after_minutes)0 (never)Unconfirmed orders older than this expire and release their stock.
Allow overselling (allow_oversell)offOn, a line with too little stock is allocated as a backorder instead of refusing insufficient_stock.
Allocation strategy (allocation_strategy)warehouse orderWhich warehouse is held first: the channel's warehouse order, or the one with the most free stock (prioritize-high-stock).
Draft price freeze (hours) (draft_order_price_freeze_hours)24How long a draft's prices are fixed after its lines change.
Low stock at (low_stock_threshold)5When free stock falls to this, retail.stock_low is published.

Reacting to orders

Every step publishes an event — retail.order_placed, retail.order_confirmed, retail.fulfilment_created, retail.order_canceled, retail.order_expired, retail.order_returned, retail.order_charge_status_changed, retail.stock_low and more (the full list). Point a webhook or a workflow at them.

Ship every paid order
era orders list --status unfulfilled --charge-status full --json
era orders fulfil_order ORDER_ID --data '{"lines":[{"orderLineId":"LINE_ID","warehouseId":"WAREHOUSE_ID","quantity":1}],"notifyCustomer":true}'
Was this page helpful?