Skip to content

Outbound Flow

theGreenGuy edited this page Jun 15, 2026 · 9 revisions

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)

Order

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).

Release → allocation + cubing

On release, order-management delegates to allocation, which:

  1. 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 returns FULFILLABLE_SHORT; the order is then raised to PARTIALLY_ALLOCATED.
  2. 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 stable shipperUnitId, and its contents carry the order lineNo — so a line split across cartons (and a carton holding several lines) is fully traceable.
  3. 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.

Cubing failure

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.

Short allocate and release

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 SHORT with allocatedQty carrying what was actually reserved.
  • Lines with zero stock: no reservation is made (allocatedQty 0).
  • If nothing at all is available across every line, the order stays NOT_FULFILLABLE and 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.

Batch (cluster) picking

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.

Picking execution (guided operator console)

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.

The /picking screen

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.

Observability

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.

Clone this wiki locally