Orders Module
Status: Built — order and order-line APIs. Operations wires the procurement Order service and both endpoints. The design below is the target for the Orders with Lifecycle project; Orders: Data Model describes the implemented shape. The client-side purchase-order sheet is documented separately in Purchase Orders and Order Lifecycle; see Relationship to the current purchase order for the design relationship.
What the runtime actually holds — tables, DTOs, cross-module references and API surface as they exist today — is Orders: Data Model. Where this page describes design ahead of the build, that page is the one that says what is stored.
Purpose
Section titled “Purpose”An Order is the durable agreement document a buyer builds to obtain materials from a single supplier. It gathers approved demand items into one commitment, is sent to the supplier and — optionally — acknowledged by them, and is closed out as material arrives, possibly across several deliveries. The order is a lasting business record: every change to it is an explicit action by a named person, recorded with its full history, so the order is its own audit trail. Nothing about an order changes on its own.
The module deliberately names its central concept Order, not Purchase Order: the same structure is designed to serve other single-supplier agreement documents in future (for example, an outbound fulfillment order), so the vocabulary stays general.
Context
Section titled “Context”Orders sits near the top of the domain map: one module builds on it, and it builds on four. Clients sit to the left of the servers they depend on; every arrow is a dependency the client calls, and together they form a DAG.
What this module consumes:
- Demand — order lines service demand items from the order queue; Submit marks every serviced demand item as being in production, and the order’s received amounts maintain themselves from demand’s accrual announcements (see Notifications).
- Item — each line pins the item version it orders; the frozen pin is the line’s descriptor. From-scratch line-adds are gated on retired items.
- Business Affiliate — the supplier binding pins a vendor version; a name alone composes a draft, but Submit requires a linked, unretired vendor.
- Staff — the assignee pin, re-pinned at each draft edit and frozen at submission.
What its clients consume from it:
- Receiving — receiving lines attribute their receipts to order lines (reading the order; never writing to it).
Main entities
Section titled “Main entities”An order has a header and one or more lines. The header carries the order’s status and the chosen supplier; each line records what is being ordered, how much, the supplier’s answer, how much has been received, and which demand items the line services.
In plain terms:
- Order — the agreement document. It has an order number, a status, the supplier it commits to, and optionally an assignee — the staff member who owns it. The supplier can be a fully linked business affiliate acting as a vendor, or just a name typed in (an informal “supermarket” supplier is allowed while composing — but submitting requires a linked vendor). While the order is a draft the buyer can choose the supplier, override contact details for this order only, and reset those overrides; at submission the supplier, the header details, and the assignee are frozen.
- Order line — one thing being ordered. A line names an item and a requested quantity, and it may carry the supplier’s confirmation (their answer) and a running received quantity. A line can also be free-form — a documentary line with no item, which is not tracked for receipts. A line services zero or more demand items (demand): these tell the system which shop-floor needs this line will satisfy.
- References are version pins. The line’s item and the order’s supplier and assignee are held as version pins — references to those records as of a specific version. While the order is a draft the pins float (each edit re-pins the current version); at submission they freeze, so the order permanently shows the item, vendor, and assignee exactly as they were when the commitment was made. The line’s frozen item pin is its descriptor — nothing is copied onto the line.
- Supplier — a pin to a business affiliate’s vendor role in the Business Affiliate reference data.
Lifecycle
Section titled “Lifecycle”An order moves through four stored states. Draft is where the buyer composes it; Submitted is the standing state once it has been sent to the supplier; Closed and Canceled are final. Two further labels — Confirmed and Receiving — are computed views shown to the user, not stored states: an order reads as Confirmed once every live line has an answer from the supplier (including a waived answer), and as Receiving once any line has received material. Receiving takes precedence over Confirmed.
Cancel is deliberately available only while the order is a draft. Once an order has been sent to a supplier, canceling it would retract a commitment made to an outside party, so it is not a casually available action; if that path is ever needed it will be designed on its own against concrete requirements. Closing an order requires every open line to have been closed first — a line can be “closed short” (closed while some quantity is still outstanding), but only by a deliberate act, never automatically.
Order line
Section titled “Order line”Each line also closes on its own. Where the order header’s status tracks the whole agreement, a line’s status tracks just that one thing being ordered — whether it is still open to change and receive against, or done.
A line can also be removed outright while the order is still a draft — a step back in composing, not a closure. A removed line’s history stays on the order’s record, but it drops off the active list and any demand items it held return to the queue.
Notifications
Section titled “Notifications”Every action recorded against an order is observable to the rest of the system — see how modules stay in sync. One notification carries business meaning beyond that generic channel.
What this module announces
Nothing of its own, today. That is expected, not an oversight: the modules that would care — an upcoming receiving capability, and possibly an outbound-fulfillment counterpart down the road — do not exist yet.
What this module listens for
As material is produced against a demand item an order line services, Demand announces it, and the order adds the delivered amount to that line’s received quantity — this is what keeps “how much has been received” accurate without anyone re-entering it. This is the mechanism behind the “Receipts reconcile themselves” guarantee above: if a notification is ever missed, the order re-derives the correct received amount on its own rather than drifting out of sync. Status: designed — the emission on the Demand side is not yet wired up in the running system.
When Demand announces that a production delivery was revoked, the order posts a compensating decrement against the same line — the same delivery-id discipline as the creation listener keeps a revocation from being applied twice. Received quantity is financially binding once the order closes, so a revocation notification arriving for a closed order is refused and alarmed rather than applied; correcting it from there is a credit-note matter, handled by a person, not an automatic reversal.
Scenarios
Section titled “Scenarios”Four moments show the order and its lines working end to end.
Submitting an order is also the moment it commits its demand items to actually running.
Receiving is not something a person tells the order about directly — it reaches the order as a notification from Demand, and the order updates itself.
Canceling a draft order releases everything it was holding, with no cleanup required on the demand side.
Once submitted, an order’s structure is frozen — an attempt to change it comes back with a specific, actionable reason rather than a generic error.
These scenarios are verified against the formal model.
Operations
Section titled “Operations”The actions users (and neighboring modules) can perform on an order. Each is an explicit, recorded act; an action that is not allowed is rejected with a specific, typed reason the user can act on.
| Action | What it does | When it is allowed |
|---|---|---|
| Create | Starts a new order in Draft, with an initial supplier (a name is enough to compose). Linking a vendor pins its current version; a retired vendor is refused at the door. | Always. |
| Choose / override / reset supplier | Sets or adjusts the supplier for this order; reset discards the per-order overrides. Each choice re-pins the vendor’s current version; a retired vendor is refused. | Draft only. |
| Update details | Edits the order’s header details — including assigning the order to a staff member (which pins that member’s current version; a retired member is refused). | Draft only; frozen at submission. |
| Add line | Adds a line — from a demand item in the queue, from an item, or free-form. Adding from a bare item creates the matching demand item on the fly; adding from scratch against a retired item is refused (taking a demand item already in the queue is not re-gated — its item was vetted when the demand was created). | Draft only; the demand item must be approved, waiting in the queue, and not already held by another live line. |
| Edit line quantity | Changes a line’s requested quantity. (The item on a line is fixed; to change it, remove and re-add.) | Draft only; line still open. |
| Attach / detach demand item | Adjusts which demand items a line services. | Draft only; same eligibility rules as adding a line. |
| Remove line | Removes a line while composing; its demand items return to the queue. | Draft only. |
| Submit | Commits the order: freezes structure, supplier, header details, and assignee on their pinned versions, and marks every serviced demand item as being in production. | Draft only; at least one line; supplier linked to a vendor (a name alone is not enough) and that vendor not retired; every serviced demand item ready to start. |
| Record acknowledgment | Records the supplier’s answer on a line — accepted, changed, backordered, rejected, substituted, or waived (acknowledged without an explicit answer). | Order submitted or later; line still open. |
| Record receipt | Adds received material to a line as it arrives. Received amounts accumulate; they are never overwritten. | Order open; line still open; line is not free-form. |
| Reverse receipt | Posts a compensating decrement for a delivery that was revoked, leaving the original entry standing. Two initiators: the demand module’s listener reverses automatically when a delivery is revoked, and a manual repair route exists for correcting the record by hand. | Order open; line still open. Refuses and alarms once either the line or the order is closed — that is credit-note territory, not a receiving correction. |
| Close line | Marks a line done, by the buyer’s decree — closing it short if quantity remains. | Order open; line still open. |
| Close order | Marks the whole order done. | Order submitted; every live line closed. |
| Cancel | Abandons the order while composing. | Draft only. |
| Annotate | Adds a note to the order or a line — also how out-of-system revisions are recorded. | Any state. |
| Delete | Retires a finished order. | Order is closed or canceled. |
Guarantees
Section titled “Guarantees”The design makes these promises in plain language:
- No double-ordering. A demand item is serviced by at most one open order line at a time, so the same shop-floor need is never ordered twice at once.
- No silent edits after submission. Once an order is submitted, its lines, its supplier, its header details, and its assignee are frozen; only answers, receipts, notes, and closure can still be recorded.
- What was agreed is what the record shows — forever. The frozen pins keep serving the item, vendor, and assignee versions the order committed to, no matter what later happens to those records (renames, edits, even retirement). A submitted order survives its vendor’s retirement untouched.
- Commitments are vetted at the door, not downstream. A retired item or vendor is refused where a person actually chooses it — creating the order, linking the supplier, adding a from-scratch line, submitting. References that merely flow along with the work (a queued demand item attached to a line, a receipt against an existing order) are never re-gated.
- Received amounts are an accrual of paired entries, never a rewrite. Received quantity accumulates from actual receiving events, and a revoked delivery posts a matching decrement rather than editing what was recorded — no entry is ever overwritten; the open quantity a user sees is computed from confirmed-or-requested minus received, not stored. Over-receipt is allowed and simply shows as a negative open amount.
- Receipts reconcile themselves. As material is received against the demand items an order services, the order’s received amounts update to match. If a receipt notification is ever missed, the system repairs the figure on its own — it does not silently drift.
- Every change is accountable. Each action is an explicit act by a named party, kept with its full history; the order record is the audit trail.
- Refusals are specific. An action that is not currently allowed is rejected with a specific, typed reason (for example, “the order is frozen” or “that demand item is already held”), not a generic error.
How Orders relates to its neighbors
Section titled “How Orders relates to its neighbors”Orders sit at the top of a short chain (drawn in Context). An order services demand items (the Demand module), which in turn collate signals from the kanban replenishment loop (Kanban Cards). Each module depends only on the one below it, and each is ignorant of the ones above: demand knows nothing about orders, and kanban knows nothing about demand. Orders also reference items (Item), the supplier (Business Affiliate), and the assignee (Staff). Receiving depends on Orders — never the other way around.
Scope and non-goals
Section titled “Scope and non-goals”This design covers the behavior of an order — its structure, its lifecycle, and the rules that govern it. Several things today’s purchase order carries are intentionally outside that scope: some are parked for later, and some are handled at runtime rather than by the design.
Deliberately left out (retained as data or parked for future design):
- Money and costing. Unit costs, line costs, order totals, taxes, and currency are not part of this design. Prices and totals are runtime data; how the order moves through its lifecycle does not depend on them.
- Rich header details. Delivery address, procurement and sales contacts, payment and shipping terms, terms and conditions, and accounting references are kept as order data but are not part of the behavioral design — they travel with the order and its supplier snapshot without changing its lifecycle.
- Scheduling. Per-line delivery dates and expedite flags are not modeled; a need for several delivery dates is expressed as several lines.
- How the order reaches the supplier. The transmission channel — online, e-mail, or phone — is a runtime concern, not part of the design.
- Creation shortcuts. Building an order from a selection of cards, from a list of items, from a copy of another order, or from an imported file are conveniences layered on the basic “create an order, add lines” actions, not separate concepts in the design.
- Request-for-quote, kits, blanket/release agreements, and vendor-managed inventory. All parked for future design.
A few behaviors of today’s purchase order are deliberately changed or dropped (each is a decision for team review):
- Canceling is limited to drafts. Today an order can be canceled after submission; this design allows cancel only while the order is a draft (see Lifecycle). Canceling a commitment already sent to a supplier is left for explicit future design.
- Partial and over-receipt are always allowed. Today an order carries an “allow partial” switch; this design always permits receiving more or less than ordered, showing the difference as a computed open amount.
- Supplier compatibility is not enforced while composing. Today, ordering a set of cards requires them to share a compatible supplier; this design chooses the supplier at the order level and does not restrict which approved demand items a line may service.
Relationship to the current purchase order
Section titled “Relationship to the current purchase order”The live system today has a client-side purchase-order sheet, documented in Purchase Orders and Order Lifecycle. The redesigned Order described on this page supersedes that model where the two disagree:
- Fewer stored states, with computed views. The current sheet uses a longer status list (
NEW,SUBMITTED,IN_PROCESS,PARTIALLY_RECEIVED,RECEIVED,CLOSED,ARCHIVED,CANCELLED). The redesign stores only Draft / Submitted / Closed / Canceled and derives Confirmed and Receiving as views rather than storing them. - Received amounts are event-driven, not header fields. Today the sheet tracks receiving state on the order; the redesign accrues received quantity on each line from actual receiving events and computes the open amount.
- Cancel is draft-only. The current sheet allows canceling a submitted order; the redesign restricts cancel to drafts and parks post-submission cancellation for explicit future design.
- The order becomes a durable server-side entity. The current sheet is client-side only; the redesign makes the order a lasting record, which is net-new frontend and backend work with no data to migrate.
Those legacy pages remain the accurate description of what ships today until the Orders with Lifecycle project is built.
Copyright: © Arda Systems 2025-2026, All rights reserved