# InventorySupplyPlan

## Description

InventorySupplyPlan is a projection of future inbound supply against a (item, site) pair. Each row represents the current expected inbound supply for one source line - typically one purchase order line, one transfer order destination line, or one manufacturing order output line. Source modules write their own approval-time records here so that the inventory module can answer "what is coming, to which site, when, and how much is still open?" without each source caller having to scan its own documents.

Fields: `sourceType` (PURCHASE_ORDER, TRANSFER_ORDER, MANUFACTURING_ORDER), `sourceId` (back-pointer to the originating document such as PurchaseOrder.id), `sourceLineId` (unique back-pointer to the source supply line such as PurchaseOrderLine.id within a source type), `itemId`, `siteId` (destination site), `expectedQuantity` (committed/promised quantity for this line normalized to the item's primary unit), `receivedQuantity` (cumulative quantity already received against this line, also in the item's primary unit), `status` (OPEN or CLOSED), derived `openQuantity` (`max(expectedQuantity - receivedQuantity, 0)` for OPEN plans and 0 for CLOSED plans), `expectedDate` (expected receipt date for this line), `lotId` (optional), `serialNumberId` (optional).

InventorySupplyPlan is a projection, not a history table. Rows remain after closure so update/consume/close commands can detect missing rows. CLOSED rows do not contribute open supply to planning or availability queries.

## Domain Model Definitions

### Model type

Stateful

#### State Transitions

```mermaid
stateDiagram-v2
    [*] --> Open: createInventorySupplyPlan
    Open --> Open: updateInventorySupplyPlan
    Open --> Open: receipt consumption
    Open --> Closed: closeInventorySupplyPlan
```

| Operation | From | To | Command |
|-----------|------|----|---------|
| update | OPEN | OPEN | [updateInventorySupplyPlan](../command/UpdateInventorySupplyPlan.md) |
| consume | OPEN | OPEN | internal receipt execution |
| close | OPEN | CLOSED | [closeInventorySupplyPlan](../command/CloseInventorySupplyPlan.md) |

### Command Definitions

- `expectedDate` is required because an undated row cannot support planner or ATP views. Source modules that do not know the exact receipt date must provide their current best committed due date and amend it later via updateInventorySupplyPlan.
- `receivedQuantity` is internal to inventory consumption and is not writable through create/update. Source modules amend expected fields; inventory execution commands consume the plan internally when receipts occur.

### Query Definitions

- [getInventorySupplyPlan](../query/GetInventorySupplyPlan.md) - Retrieves one supply projection by id, including CLOSED rows
- [listInventorySupplyPlans](../query/ListInventorySupplyPlans.md) - Lists OPEN supply projections by item, site, source, and expected date range

### Models

- InventorySupplyPlan

### Invariants

- A row remains for the supply plan after closure; CLOSED rows are excluded from open supply views
- `id` is the supply projection identity
- `(sourceType, sourceLineId)` is unique; each source line owns at most one current-state supply projection
- Planned split deliveries are represented by splitting the source document line in the standard modules, not by creating multiple supply plans for one `sourceLineId`
- `expectedQuantity >= 0` and `receivedQuantity >= 0`; open quantity is derived, not stored, and never returned below zero
- `expectedQuantity` and `receivedQuantity` are always stored in `Item.unitId`; source modules must convert source-line quantities before writing the projection
- Expected fields are partially mutable to reflect amendments on the source line; omitted update fields are preserved
- `receivedQuantity` records receipt facts and is not overwritten by source-line amendments
- `status` is OPEN while the source line remains eligible for open supply planning, even when `openQuantity` is temporarily 0 after a full receipt; it becomes CLOSED when the source line no longer contributes open supply
- A supply plan row never carries cost layers or FIFO state; receipt creates `CostLayer` rows via the `InventoryLedger` path
- The destination `siteId` must reference a Site

### Relationships

- **References Item**: Each plan row pertains to an Item from the item-management module
- **References Site**: The destination site where the future supply is expected to arrive
- **References Lot (optional)**: For lot-tracked items committed at the source line level
- **References SerialNumber (optional)**: For serial-tracked items committed at the source line level
- **Back-references the source document**: `sourceType` + `sourceId` + `sourceLineId` carry the back-pointer; the source schema itself is not joined from the inventory module
