# Supply Planning

## Overview

Supply Planning tracks future inbound supply at the site level using InventorySupplyPlan. Each OPEN plan row represents one current-state projection for a source line that contributes open supply, such as a purchase order line, transfer order destination line, or manufacturing order output. The row answers what item is expected, which site it will arrive at, when this line is expected, and how much remains open.

InventorySupplyPlan is separate from StockLevel. StockLevel describes current location-level stock availability, while InventorySupplyPlan describes future site-level supply. Future supply is therefore visible to planning and ATP workflows without treating expected receipts as available stock.

Source modules own their document lifecycle and write supply projections into inventory:

| Source Event | Inventory Command |
|---|---|
| Source line creates expected inbound supply | `createInventorySupplyPlan` |
| Source line amends expected inbound supply | `updateInventorySupplyPlan` |
| Goods are received against the supply plan | Internal consumption inside inventory receipt execution |
| Source line is cancelled, closed, or no longer creates supply | `closeInventorySupplyPlan` |

The open quantity is derived as `max(expectedQuantity - receivedQuantity, 0)` for OPEN rows. CLOSED rows stay available for command consistency checks but do not contribute open supply to planning or ATP workflows.

## Business Purpose

- Gives planners a single inventory-owned view of future inbound supply across purchase, transfer, and manufacturing sources
- Keeps future supply out of current StockLevel availability so ATP checks do not promise stock before receipt
- Lets source modules publish supply projections without inventory joining each source document schema
- Keeps one deterministic supply projection per source line so source modules can update or close the plan without schedule-line reconciliation
- Preserves receipt history through source documents and InventoryLedger while keeping closed projection rows for source-line consistency checks
- Provides queryable open supply by item, site, source document, source line, source type, and expected date range

## Process Flow

```mermaid
flowchart TD
    A[Source module creates inbound line] --> B[Normalize quantity to Item.unitId]
    B --> C[createInventorySupplyPlan]
    C --> E[Insert OPEN plan with receivedQuantity 0]
    A2[Source module amends inbound line] --> B2[Normalize quantity to Item.unitId]
    B2 --> F[updateInventorySupplyPlan]
    F --> G[Update expected fields and keep OPEN]
    E --> Q[Planning queries read openQuantity]
    G --> Q
    J[Goods receipt against source line] --> K[Internal supply plan consumption]
    K --> M[Increment receivedQuantity and keep OPEN]
    O[Source line cancelled or closed] --> P[closeInventorySupplyPlan]
    P --> N[Set CLOSED]
```

## Scenario Patterns

- **Purchase order planning**: A purchase order line is approved, so the purchasing module creates one supply projection for the destination site and expected receipt date.
- **Transfer inbound planning**: A transfer order destination line creates future supply at the receiving site before stock is physically received into a storage location.
- **Manufacturing output planning**: A manufacturing order output line publishes expected finished goods supply for the production site.
- **Amendment**: A source line changes quantity, item, site, or expected date. The source module calls update by supply plan id with the changed fields, preserving omitted fields and already received quantity.
- **Partial receipt**: A receipt consumes part of the plan, increasing `receivedQuantity` while the remaining open quantity stays queryable.
- **Full receipt**: A receipt consumes all remaining open quantity and keeps the plan OPEN. The source module closes the plan row when the source line is also complete.
- **Cancellation or closure**: A source line is cancelled, closed, or changed so it no longer creates inbound supply. The source module closes the plan row by id.
- **ATP with future supply**: Planning queries combine current availability from StockLevel with future open supply from InventorySupplyPlan without merging the two concepts.

## Test Cases

- Create creates a new supply plan with `receivedQuantity = 0` and `status = OPEN`
- Create keeps `(sourceType, sourceLineId)` unique; split delivery is represented by splitting source lines in standard modules
- Update partially updates an existing OPEN plan and preserves omitted fields and `receivedQuantity`
- Update accepts amendments that leave no open quantity; source modules call closeInventorySupplyPlan for source closure
- Create and update reject missing or inactive items
- Create and update reject quantities not normalized to the item's unit
- Create and update reject missing sites
- Receipt execution increments `receivedQuantity` for partial receipts
- Receipt execution keeps the plan OPEN; source modules call close when their source line reaches a terminal state
- Receipt execution rejects quantities that are zero, negative, or greater than open quantity
- Close closes a plan by id
- Get returns one plan, including CLOSED rows, with computed `openQuantity`
- List returns OPEN plans with computed `openQuantity` by item, site, source, and expected date range

## Reference Links

- [InventorySupplyPlan](../model/InventorySupplyPlan.md) - future inbound supply projection
- [CreateInventorySupplyPlan](../command/CreateInventorySupplyPlan.md) - creates source-line supply
- [UpdateInventorySupplyPlan](../command/UpdateInventorySupplyPlan.md) - amends source-line supply
- [CloseInventorySupplyPlan](../command/CloseInventorySupplyPlan.md) - closes cancelled or closed supply
- [GetInventorySupplyPlan](../query/GetInventorySupplyPlan.md) - retrieves one supply plan
- [ListInventorySupplyPlans](../query/ListInventorySupplyPlans.md) - lists OPEN supply plans for planning and ATP
- [Stock Tracking](./stock-tracking.md) - current location-level stock availability
