03 — Integration

Inventory is a member of the R9 Work & Supply network (message protocol v1). Its contract is written in schema/inventory.integration.dsl (authoring spec: docs/implementation/integration_authoring_spec.md) and turned into code by python -m codegen.cli integration inventory --network work_supply; the business logic for each message is hand-written in integration/handlers.py.

The whole network — every message with its publisher, subscribers and implementation status, generated from the contracts — is in networks/work_supply/NETWORK_MAP.md (python -m codegen.cli network-docs work_supply).

What it owns

Network entity Model Business reference
inventory.stock_location StockLocation location_code
inventory.reservation InventoryReservation reservation_number (RES-…)
inventory.goods_receipt GoodsReceipt receipt_number (GR-…)
inventory.goods_receipt_line GoodsReceiptLine —

Messages

Kind Message When / what Status
publishes inventory.item_reserved a reservation becomes (or is created) reserved ✅ automatic
publishes inventory.item_unavailable a reservation becomes (or is created) unavailable ✅ automatic
publishes inventory.item_issued reserved stock was issued to its work order: quantity, the stock's average cost and the value ✅ automatic
publishes inventory.goods_arrived / receipt_accepted / receipt_quarantined / receipt_rejected receiving ✅ automatic
consumes work.material_requirement_created reserve stock for the requirement (all or nothing) ✅
consumes work.material_requirement_changed a cancelled requirement releases its reservation ✅
consumes purchasing.shipment_dispatched / delivery_commitment_changed expected inbound stock ⏳ R10
accepts inventory.reserve_for_work same as the consumed event, by command (from Work or the orchestrator) ✅
accepts inventory.issue_to_work issue the reserved stock to its work order: on hand and reserved fall, the issue is costed at the item's average cost (a moving average of the purchase price of accepted stock; a receipt line takes its purchase order line's price) ✅
accepts inventory.release_reservation release unissued stock (rejects already_issued) ✅
accepts inventory.record_goods_arrival, inspect_receipt, reverse_receipt_acceptance ⏳ R10 (answers handler not found)
answers inventory.availability on hand / reserved / available per item, candidate locations ✅
answers inventory.reservation_status one reservation ✅
answers inventory.receipt_status ⏳ R10

Events are written in the same transaction as the stock change and delivered afterwards; inbound messages are de-duplicated by message id and commands by idempotency key, so nothing is reserved twice even when a message is delivered twice.

References to other applications

Points at Owner Fields
work.work_order work_management work_order_cid / work_order_ref — linked ↗
work.material_requirement work_management material_requirement_cid / material_requirement_ref — linked ↗
catalogue.item catalogue (R10) catalogue_item_cid / catalogue_item_ref
purchasing.purchase_order / purchase_order_line / shipment purchasing (R10) purchase_order_cid / purchase_order_ref …
supplier.supplier supplier (R10) supplier_cid / supplier_ref
asset.component asset register physical_component_cid / physical_component_ref

Endpoints

Endpoint For Protection
PUT /integration/messages/<id> the orchestrator delivering messages service token
GET /resolve/<cid> people following a ↗ link from another app normal login

Settings (applications.yaml env:)

INTEGRATION_PUBLISHER=1, ORCHESTRATOR_URL=http://localhost:5089 (the R9 orchestrator); ORCHESTRATOR_SERVICE_TOKEN from .env. The publisher starts on the app's first request.