Order Creation
This page documents the ways a purchase order can be created in the system. The primary path for MVP2 is creation from Kanban Cards in the Order Queue. Additional creation paths (empty order, copy, header+lines) are specified here and represent MVP3 scope or future work.
Use case reference: PRO::PO::0001
Create from Kanban Cards
Section titled “Create from Kanban Cards”Use case: PRO::PO::0001::0001 and PRO::PO::0001::0002
In MVP2, the primary way to create a Purchase Order is from a set of Cards in the Order Queue.
- User selects a set of Cards from the Order Queue.
- User clicks the Order button and selects “New Purchase Order” (see Order Line Management for the alternative “Add to existing order” path).
- The system validates the selected cards for compatibility and creates a new Purchase Order.
- The system transitions the cards to the
REQUESTEDstate in the backend.
- The system transitions the cards to the
- The system opens the Purchase Order for editing, allowing the user to edit the Header properties of the Purchase Order.
Creation Logic
Section titled “Creation Logic”- All cards must belong to items that have a compatible supplier, or no supplier defined.
- If the cards have a compatible, non-null supplier, that supplier becomes the supplier of the Purchase Order.
- Cards are grouped by item and unit of measure into individual Order Lines.
- Each order line has a quantity equal to the sum of reorder quantities for the card group.
- Unit costs, line costs, and goods value are calculated from the total quantity of the card group and the item’s price from the supplier.
Postcondition: Cards transition from REQUESTING to REQUESTED. The created PO is displayed in edit mode for header review.
Sequence Diagram
Section titled “Sequence Diagram”API Routes
Section titled “API Routes”| Step | Route | Notes |
|---|---|---|
| Create Order | POST /v1/order/order/from-kanban-cards | Body is a list of Card EIds; returns the created Order Record |
| Update Header | PUT /v1/order/order/{eId} | Body is the updated Order Header as OrderHeaderInput; returns the Updated OrderHeader Record |
See the OpenAPI Specification for full route details.
Create Empty Order
Section titled “Create Empty Order”Use case: PRO::PO::0001::0003 — Priority: MVP3
The system presents a blank form so the user can fill in header information and add lines manually.
What the user can do
Section titled “What the user can do”- Edit the order header fields.
- Save the order, keeping it in
NEWstate. - Approve the order, triggering validation and placing it in the
APPROVEDstate. The order becomes read-only. - Add order lines to the order.
Implementation Entry Points
Section titled “Implementation Entry Points”OrderHelper.addEmptyOrder(header: OrderHeader, ...)atoperations/src/main/kotlin/cards/arda/operations/procurement/orders/service/OrderHelper.kt:421-436OrderHelper.addEmptyOrder(headerEid: UUID, orderNumber: String, ...)atOrderHelper.kt:442-451for flows that only supply an identifier and order number.
Preconditions
Section titled “Preconditions”- Caller must provide an
OrderMetadatapayload and author identifier. - When supplying a fully formed
OrderHeader, the caller ensures field compliance with domain rules. - When only
headerEidandorderNumberare supplied, the helper composes a header with defaults.
Scenario Overview
Section titled “Scenario Overview”- Compose (or accept) an
OrderHeader, defaulting toOrderStatus.NEW,allowPartial = true, anddeliverBy = now + 7 days(OrderHelper.kt:261-283). - Persist the header through
DataAuthorityService.add, obtaining anEntityRecordsnapshot (OrderHelper.kt:430-435). - Evaluate
OrderHelper.linesQueryto build an emptyPageResult, producing anOrderRecordwith zero lines (OrderHelper.kt:431-433). - Invoke the supplied
postProcesscallback with the freshly createdOrderRecord(OrderHelper.kt:434-435).
Postconditions
Section titled “Postconditions”- A new order header version exists in the database with no lines attached.
- The returned
OrderRecordincludes pagination metadata pointing to the header’s line universe. - No automatic notifications or workflow transitions are triggered.
Header Defaults
Section titled “Header Defaults”| Field | Default Value |
|---|---|
status | NEW |
allowPartial | true |
deliverBy | orderDate + 7 days |
goodsValue | null (no lines to aggregate) |
supplierName | whatever the caller supplied (typically null) |
Create as Copy of Existing Order
Section titled “Create as Copy of Existing Order”Use case: PRO::PO::0001::0004 — Priority: MVP3 — Not yet implemented
The user selects an order from the list and requests a copy. The system would make a complete copy with the following modifications:
- History starts fresh at the time of the copy.
- Attachments to Kanban Cards are not copied.
- Item associations on each order line are reset to the current item version. If a referenced item has been deleted, the line is marked invalid and the PO cannot be submitted until corrected or removed.
Current Status
Section titled “Current Status”There is no service in operations/src/main/kotlin/cards/arda/operations/procurement/orders/service that clones an existing order. Callers needing copy semantics must orchestrate the process manually by reading the order through OrderRecordService.getParentChild and re-submitting adjusted payloads. A dedicated copy utility must be introduced before this capability is exposed in the product UI.
Create from Header and Lines
Section titled “Create from Header and Lines”Use case: PRO::PO::0001::0005 — Priority: MVP3
The user directly provides OrderHeader and OrderLines data. The system validates and creates the full order structure. This path supports programmatic or import-driven order creation where the full order structure is known upfront.
Preconditions
Section titled “Preconditions”- The provided order lines do not reference Kanban Cards (future enhancement).
- If item references are provided in order lines, the items must exist and be current in the system as of
TimeCoordinates.now().
Scenario Overview
Section titled “Scenario Overview”- User provides the
OrderHeaderinformation and a list ofOrderLines. - System validates the information; reports errors if invalid.
- System retrieves reference information (e.g., Items) from other services as needed.
- System adds default values to
OrderHeaderandOrderLinesfrom system settings and item information where not provided. - System persists the
OrderHeaderand associatedOrderLinesand returns them to the user.
All fields take the value provided by the user if not
null. Calculations are only performed when the user-provided value isnull.
Order Line Fields
Section titled “Order Line Fields”| Field | Derivation |
|---|---|
eId | UUID.randomUUID() |
title | First non-null of: effectiveSupply.sku, item.name, or OrderLineInput.title |
description | OrderLineInput.item.description |
status | OrderLineStatus.BLANK |
item | OrderLineInput.item |
supplierSku | effectiveSupply.sku |
quantity | OrderLineInput.quantity if not null, else effectiveSupply.orderQuantity |
unitCost | OrderLineInput.unitCost if not null, else effectiveSupply.unitCost |
cost | quantity * unitCost |
received | 0.0 in same unit as quantity; null if quantity is null |
notes | null |
privateNotes | null |
Order Header Fields
Section titled “Order Header Fields”| Field | Value |
|---|---|
eId | UUID.randomUUID() |
status | OrderStatus.NEW |
orderNumber | Generated by the OrderService |
orderDate | Current datetime in user timezone (or system timezone) |
allowPartial | true |
deliverBy | Current datetime + 7 days |
deliveryAddress | null |
procurement | null |
supplierName | null |
supplierAddress | null |
orderMethod | OrderMethod.UNKNOWN |
sales | null |
goodsValue | Sum of cost fields of all associated lines (null if multiple currencies) |
taxesAndFees | Empty map |
totalCost | goodsValue + sum of taxesAndFees values (null if multiple currencies) |
termsAndConditions | null |
notes | null |
privateNotes | null |
Open Tasks
Section titled “Open Tasks”- Additions to Item and ItemSupply: GitHub #406
- Additions to OrderService and associated persistence layer.
Copyright: © Arda Systems 2025-2026, All rights reserved