-
-
Notifications
You must be signed in to change notification settings - Fork 0
Outbound Flow
How an outbound order becomes picked, cubed cartons with dispatch labels. Design: ADR 0002.
create order ─► release ─► allocation: reserve at PICK locations + cube into shippers ─► (pick) ─► ship
(order-management) (allocation) (order-management)
POST /api/orders creates an order with an orderType (INBOUND/OUTBOUND/COUNT/ADJUSTMENT).
An outbound order may also carry serviceCode, routeCode, a shipTo address, and an optional
labelTemplateCode (validated against the master-data catalogs). Orders carry priority and
dispatch time; release management surfaces a most-urgent-first queue
(/release-queue, /release-due).
On release, order-management delegates to allocation, which:
-
Allocates each line against PICK-purpose locations (inventory location-scoped ATP) until
met, with a pick-type UoM breakdown (cases/eaches, per the warehouse's allowed pick
types). If every line is reserved →
ALLOCATED/FULFILLABLE; otherwise all reservations are released →NOT_FULFILLABLE. With allow-short mode (allowShort: true) a short order instead keeps what it could reserve, cubes only the allocated quantities, and returnsFULFILLABLE_SHORT; the order is then raised toPARTIALLY_ALLOCATED. -
Cubes the order into shippers:
- APP — greedy volume+weight across the warehouse's active shipper sizes: packs the largest carton that fits while a lot remains, then downsizes the final carton to the remainder. A single order line can be split across cartons.
- ONE_TO_ONE — the host already cubed; the request's cube instructions map 1:1 to cartons.
- Each carton (
ShipperAssignment) has a stableshipperUnitId, and its contents carry the orderlineNo— so a line split across cartons (and a carton holding several lines) is fully traceable.
-
Dispatch label per carton: the resolved label template (order override → service →
warehouse default) + fields (ship-to, service, route,
carton seq/total) + a barcode requested from the host per shipper (the barcode is only knowable once cubing produced the cartons). See Host Integration.
If a SKU is larger than the biggest available carton, the order can't be cubed: no shippers
are produced, any held stock is released, and the order is parked in CUBING_FAILED with a
reason (the offending line/SKU) for an operator to resolve. It can be re-released after the
carton/SKU master data is fixed.
POST /api/orders/{id}/release-short (permission ORDER_RELEASE = SUPERVISOR/ADMIN) is the
explicit supervisor decision to work a NOT_FULFILLABLE order with whatever stock is currently
available. Allocation re-runs in allow-short mode:
- Lines with stock: the available quantity is reserved; line status becomes
SHORTwithallocatedQtycarrying what was actually reserved. - Lines with zero stock: no reservation is made (
allocatedQty0). - If nothing at all is available across every line, the order stays
NOT_FULFILLABLEand the call is rejected with 409.
On FULFILLABLE_SHORT the order becomes PARTIALLY_ALLOCATED with a statusDetail
naming the deciding user (also logged at INFO). Ship (POST /api/orders/{id}/ship) accepts
both ALLOCATED and PARTIALLY_ALLOCATED; it stages an OrderShipped outbox event with
per-line orderedQty / shippedQty / shortQty + shortShipped flag, so the host
confirmation feed receives the actual shipped quantities per line.
The outbound BPMN sample handles this: the allocation gateway accepts both FULFILLABLE and
FULFILLABLE_SHORT and routes the order down the normal pick/dispatch path. A new process
instance started with allowShort=true passes the allow-short flag through to allocation,
bypassing the NOT_FULFILLABLE end event.
POST /api/allocation/batches groups eligible small orders (FULFILLABLE or
FULFILLABLE_SHORT, pieces ≤ batchMaxPieces) into pick totes (≤ batchMaxOrders), merges
their picks into one combined list, and records the per-order separation plan.
The (pick) step in the flow above is now an executable operator workflow, owned by
order-management:
| Endpoint | RBAC | What it does |
|---|---|---|
GET /api/orders/pick-tasks?warehouseId= |
ORDER_VIEW (read) |
The operator pick queue: released/allocated outbound lines still needing picking, ordered for a sensible pick walk. Each entry carries the real pick locationId (resolved in order: the line's persisted pick location → the latest PICK transaction → null). |
POST /api/orders/pick-tasks/{lineId}/confirm {pickedQty, short?} |
ORDER_POST_TRANSACTION (write) |
Posts a Picked line transaction via the existing outbox → txlog, decrements stock, advances the line's pickedQty, and marks it SHORT when short is set. |
A guided RF-style Picking operator screen lives in the Operations section at /picking:
- A big next-pick card: location code, SKU code + name + image, and the qty to pick.
- Confirm / Short actions; the queue advances to the next pick automatically.
- All identifiers are shown as codes via
useCatalog(no raw UUIDs). - Keyboard-first: Enter = confirm.
Pick-by-light, voice, and RF-gun hardware are device-adapter seams layered on this same screen and endpoints (the screen is the reference operator surface).
Pick location on the line: allocation now returns the primary allocated pick pickLocationId
per line, order-management persists it on the order line (pick_location_id), and the pick
queue surfaces it as the entry's locationId (fallback: line pick location → latest PICK txn →
null). So the Picking screen shows a real location code instead of a blank.
Every material decision in the order-management and allocation services is logged at INFO
(warnings for degraded paths) so an engineer can follow a fault through the outbound chain from
the per-service daily logs alone without enabling DEBUG.
Order lifecycle (order-management):
| Event | Level | Key fields |
|---|---|---|
| Order received | INFO | order ref, type, line count, priority, dispatch-by |
| Released → ALLOCATED | INFO | order ref, line count |
| Release → CUBING_FAILED | WARN | order ref, failure detail, consequence (operator must resolve shipper sizes) |
| Release → NOT_FULFILLABLE | WARN | order ref, failure detail, consequence (eligible for re-release once stock arrives) |
| Short allocate and release → PARTIALLY_ALLOCATED | INFO | order ref, deciding user, per-line allocatedQty, shortfall |
| Short release rejected (not NOT_FULFILLABLE or nothing available) | WARN | order ref, current status, consequence |
| Order dispatched (ALLOCATED or PARTIALLY_ALLOCATED → SHIPPED) | INFO | order ref, shipped vs ordered per line |
| Order cancelled | INFO | order ref, previous status, whether reservations were released |
| Line transaction posted | INFO | order ref, line no, transaction type, actor, SKU, qty, location, HU |
| Outbox relay halted | WARN | message id, event type, stream, attempt count, published vs total this pass, consequence (ordering preserved) |
| Release-due pass summary | INFO | warehouse, order count processed, cutoff instant |
| Demo clear | INFO | warehouse, orders deleted, outbox rows drained |
| Demo seed | INFO | warehouse, order count, type, demo SKU catalog size |
Allocation (allocation):
| Event | Level | Key fields |
|---|---|---|
| Order allocated — FULFILLABLE | INFO | order ref, line count, pick count, cubing mode, shipper codes (seq:code, largest-first) |
| Order allocated — FULFILLABLE_SHORT (allow-short mode) | INFO | order ref, short-line count, per-line shortfall summary in statusDetail |
| Per-line short | WARN | order ref, line no, SKU, requested qty, allocated qty, unfulfilled qty |
| Order NOT_FULFILLABLE | WARN | order ref, short-line count, total lines, reservation count released |
| Allocation cancelled | INFO | order ref, previous status, reservation count released, line count |
| Idempotent retry (existing FULFILLABLE plan returned) | DEBUG | order ref |
| Re-allocation (discarding prior plan) | DEBUG | order ref, prior plan status |
| Per-pick reservation | DEBUG | order ref, line no, SKU, reserved qty, pick location, ATP at time of pick |
| Cubing failed | WARN | order ref, failure detail, consequence (all reservations released, parked CUBING_FAILED) |
Batch building (allocation):
| Event | Level | Key fields |
|---|---|---|
| Batch built | INFO | batch id, warehouse, order count, order refs, merged pick-line count, tote-close reason |
| Order skipped — no allocation found | WARN | order ref, consequence |
| Order skipped — wrong allocation status | WARN | order ref, actual status |
| Order skipped — over batchMaxPieces | WARN | order ref, piece count, limit |
Related: Inbound and Inventory · Equipment Integration · Services.
openWCS — open-source Warehouse Control System · summarized from build.md & docs/AS-BUILT.md (the repo docs are authoritative).
Design
Flows
- Areas
- Inbound and Inventory
- Slotting and Replenishment
- Goods-to-Person Stations
- Outbound Flow
- Equipment Integration
- Transport Overview
- Process Designer
- Mobile Process Designer
- Hardware Visualisation
- Host Integration
Reporting & Dashboards
Operations