Guide / for designers

Order management system design — the model that matters

One state machine, one movement history, one deliberate handoff to accounting. The design decisions that make an OMS trustworthy — written for builders, useful to buyers.

The key facts

  • The design centres on a state machine: placed → checked → picked → packed → invoiced → paid, with every transition a recorded fact.
  • Orders are headers plus lines over one movement history — the same stock truth that inventory and purchasing use; no shadow quantities.
  • The hard problems are the quiet ones: stock-check timing, idempotent intake (webhooks retry), partial fulfilment, and the accounting handoff.
  • For buyers: these decisions are what a trial reveals — the OMS concept is the prose companion; BSimple is commercial and not open source.
  • The full picture: the full order flow is the hub page for the order side.
Diagram — index of this pageThe ground this page covers
  1. 01The key facts
  2. 02The state machine at the centre
  3. 03The model: headers, lines, movements, parties
  4. 04The hard problems tutorials skip

The state machine at the centre

Design the states first, because everything else hangs off them: placed → checked → picking → packed → invoiced → paid, with cancellation and return as first-class paths, not afterthoughts. Rules to hold: an order is in exactly one state at a time; every transition is a recorded fact (actor, timestamp); and the states are the only answer to "where is this order?" — no side spreadsheets, no tribal memory. Wholesale adds per-line states (partial shipments), which is why lines carry their own progress and the header aggregates.

The life-cycle page explains the stages in business terms; the design view adds the constraint that makes them real — transitions are transactions, and two people moving the same order cannot both win.

Genuine BSimple screenThe customer ordering page: each customer sees their own product list and pricing.
The customer ordering page: each customer sees their own product list and pricing.

The model: headers, lines, movements, parties

Order + OrderLine. Header carries party, dates, pricing context and state; lines carry product, quantity, price and per-line state. Prices snapshot at order time — a later price change must not rewrite history.

Movement history. Stock deduction is an append-only movement referencing the order line — not an update to a quantity column. This single choice buys audit (why did stock change?), concurrency (two pickers cannot both sell the last unit) and traceability (the class-diagram reasoning covers the full model).

Stock-check service. The check at intake compares demand against available — on hand minus open promises — not raw on-hand. Whether the check blocks or warns is a business rule; that it is structural is a design requirement.

Party abstraction. Customers and suppliers as one party with roles, so a trade customer with a portal account and an invoice account is one record, not three.

DiagramDiagram: an online store syncing orders into stock.
Diagram: an online store syncing orders into stock.

The hard problems tutorials skip

Idempotent intake. Orders arrive from portals, webhooks and CSV — webhooks retry, so the same order will arrive twice. Design intake to deduplicate on source identifiers, or you will ship phantom orders. BSimple's Shopify webhook import lives this daily.

The deduction moment. Pick a moment and keep it deliberate — in BSimple's design, stock deducts at invoice approval, so assembly-phase quantities stay sellable and the deduction is one clean fact. Ambiguity here ("deduct at order? at pack? sometimes?") is the root of most overselling.

Partial fulfilment. Lines ship in parts; invoices follow deliveries; returns reverse specific quantities against specific lots. The model that cannot express "two of three shipped, invoiced separately" will be replaced within a year.

The accounting handoff. Approved invoices cross once, with tax treatment intact; payment status mirrors back; nothing is typed twice. The boundary design is part of the OMS, not an integration afterthought. We build BSimple, so weigh that — it is commercial software (not on GitHub), and the trial is how a buyer tests this whole design without reading a line of code.

DiagramOrder placedPicked and packedInvoice createdStock updated
Diagram: Order placed → Picked and packed → Invoice created → Stock updated — how this work moves through BSimple.

Frequently Asked Questions

How do you design an order management system?

Start with the state machine, build orders as headers plus lines over an append-only movement history, make the stock check structural at intake, design intake for retries, and treat the accounting handoff as a one-way reviewed flow. The states and the movements are the system; the screens are finishing.

When should stock deduct in the design?

Where commitment is honest — commonly at invoice approval, as BSimple does it, so assembly stays sellable and the deduction is a single deliberate fact. What breaks designs is deducting at several inconsistent moments.

What is idempotency and why does an OMS need it?

Intake sources retry — a webhook delivered twice must not create two orders. Deduplicate on the source's identifier so repeated arrivals update one record. Skip this and the phantom orders appear within the first week.

How does an OMS relate to inventory design?

They share one movement history: orders consume it, purchasing fills it, counts correct it. An OMS with its own quantity table is two systems pretending — the combined-model reasoning applies to both.

For a business, how do we test a vendor's design?

Push the hard cases in a trial: the partial shipment, the retried webhook, the last unit sold twice simultaneously, the voided invoice. The trial exists for exactly these — vendors who dodge them are describing a design they have not built.

BSimple

Get started with BSimple