Skip to content

Inbound and Inventory

openwcs-docs-agent edited this page Jun 11, 2026 · 13 revisions

Inbound & Inventory

Real-time stock is a projection of the append-only transaction log. Nothing writes stock.qty directly — movements are events, and the inventory service applies them.

The two working vertical slices

Goods-in → stock

POST /api/txlog/events {GoodsReceived}  ─►  outbox relay  ─►  txlog.stream (Kafka)  ─►  inventory projection  ─►  stock

Line transactions (all order types)

POST /api/orders/{id}/lines/{lineNo}/transactions
   ─► order-management appends GoodsReceived / Picked / StockAdjusted to txlog (via its outbox)
   ─► relay ─► txlog.stream ─► inventory projection moves stock.qty

INBOUND = receipts (+), OUTBOUND = picks (−), COUNT / ADJUSTMENT = signed adjustments. The actor is recorded on every transaction (authenticated when security is on).

txlog — system of record

  • POST /api/txlog/events writes the immutable event and an outbox row in one transaction; a scheduled relay publishes to txlog.stream in global position order.
  • GET /api/txlog/events?afterPosition= is the global replay feed used to (re)build read models — and to stream confirmations back to the host (see Host Integration).
  • UPDATE/DELETE on the event table are blocked by a trigger.

inventory — durable projection

  • Consumes txlog.stream; movement events (GoodsReceived, PutawayCompleted/StockMoved, Picked, StockAdjusted, StockStatusChanged) move stock.qty (per warehouse × SKU × batch × location × HU × status) and advance a projection cursor.
  • Idempotent: every applied event is recorded in a processed_event inbox keyed on eventId, so redelivery/replay is a no-op and the read model can be rebuilt from the log.
  • Serves SKU-wide and location-scoped availability/reservations (ATP) used by allocation.
  • Per-location occupancy (POST /api/inventory/locations/occupied, body { "locationIds": [...] }{ "occupiedLocationIds": [...] }): the subset of the given locations that physically hold any stock row or handling unit. Slotting put-away uses it to exclude occupied slots from its candidate set before scoring (see Slotting and Replenishment).
  • Batch/lot & serial instances are created at goods-in (ADR 0001).

Handling unit registry

Physical HU instances (barcode, type, location, status) are managed via /api/inventory/handling-units (CRUD). Type and location are set at registration and are not editable through the registry — the PUT /{id} endpoint preserves the existing huTypeId and locationId from the stored record regardless of what is sent in the request body. Changing an HU's type or moving it to a different location can only happen through a controlled process (e.g. a maintenance or QA work cycle). The registry UI enforces this by disabling the Type and Location dropdowns when editing an existing HU.

Transport lifecycle location booking (PUT /api/inventory/handling-units/{id}/location, body { locationId: uuid | null }, 404 for unknown HU): the controlled path the full PUT defers to. Flow-orchestrator calls this endpoint as a best-effort side effect at two points in the induction lifecycle:

  • RETRIEVE completion — books locationId = null: the tote has left its slot and is in transit / at a workplace; the HU transport trace is the authoritative location record while the tote is away.
  • Return-leg STORE completion — books the source locationId back: the tote is physically back in its slot.

The endpoint moves all stock rows riding in the HU to the new locationId in the same transaction, so the Stock Overview always reflects the tote's current physical position (including null while the tote is in transit). The HU row and its stock rows are never out of sync.

Implemented by InventoryClient in flow-orchestrator (OPENWCS_INVENTORY_BASE_URL, default http://localhost:8082, 2 s connect/read timeouts). A booking failure is logged as a warning and never breaks the transport pipeline.

Stock Overview screen — Mark for counting

The Stock Overview screen lists current stock rows (SKU × location × HU × status). Each row has a Mark for counting button that creates an ad-hoc BLIND count task scoped to that location and SKU without leaving the screen:

  • Calls POST /api/counting/tasks with scopeType: LOCATION, countType: BLIND, tolerance: 1, and a single cells entry { locationId, skuId }.
  • While the request is in-flight the button shows "Adding…" and is disabled for that row.
  • On success a green notice confirms the task was created (e.g. Count task created for SKU-001 at A-01-01); on failure the error is shown in the existing red alert bar.
  • Rows where locationId or skuId is missing (e.g. unallocated stock) have the button disabled.

The created task appears in the stock-counting screen immediately and follows the normal capture → variance → reconcile → StockAdjusted lifecycle (see the counting service row in Services). For ASRS-family locations the task is created with routingStatus = PENDING and the background CountRoutingScheduler routes the tote to an active GTP STOCK_COUNT station within a minute, retrying on failure (see Goods-to-Person Stations).

Host-driven adjustments

A host can post a signed stock correction via POST /api/host/inventory/adjustments (Host Integration); it is appended to the txlog as a StockAdjusted event and applied by the projection like any other movement.

Related: Outbound Flow · Architecture.

Clone this wiki locally