# InventoryExecution

## Description

InventoryExecution is the inventory-owned execution aggregate for stock movement intent and posting state. Goods receipt, goods issue, and stock adjustment effects share the header through `executionType`, while document context such as transfer order shipment or receipt is identified by `sourceDocumentType` and `sourceDocumentId`. InventoryExecutionLine records the line-level stock effects owned by that header.

For purchase goods receipt, one goods receipt is represented as one InventoryExecution record with `executionType=GOODS_RECEIPT`; each received purchase order line can be represented by an InventoryExecutionLine with `direction=IN` and `sourceLineId=PurchaseOrderLine.id`. For goods issue, one issue is represented as one InventoryExecution record with `executionType=GOODS_ISSUE`; each outbound source line can be represented by an InventoryExecutionLine with `direction=OUT`.

InventoryExecution has a deliberately small posting lifecycle:

- `DRAFT`: created but not posted to stock, ledger, balances, lot/serial, or valuation
- `CANCELLED`: draft execution was discarded before posting; no stock facts were created
- `POSTED`: posted to stock and represented by InventoryLedger entries

InventoryLedger references InventoryExecution by `inventoryExecutionId`. Ledger rows do not duplicate source document fields; source document context is owned by InventoryExecution.

`effectiveDate` is the user/business date used for inventory reporting and period controls. `postedAt` is the system timestamp when the execution transitions to POSTED.

InventoryExecutionLine is the unit-conversion boundary. It keeps both the business/input quantity and the normalized inventory quantity:

- `quantity` + `unitId`: the quantity and unit provided by the source document or user
- `primaryQuantity` + `primaryUnitId`: the quantity converted to the item's primary unit at execution creation time
- `unitConversionRate`: the multiplier used to convert `quantity` into `primaryQuantity`

InventoryLedger stores only primary-unit quantities derived from `primaryQuantity`.

Goods receipt commands create one InventoryExecution header and one or more InventoryExecutionLine rows with `direction=IN`. Goods issue commands create one InventoryExecution header and one or more InventoryExecutionLine rows with `direction=OUT`. Transfer shipment and transfer receipt commands create paired OUT and IN execution lines for each transfer line. Stock adjustment flows can create line rows with the direction required by each stock effect.

For goods receipt execution lines, `unitCost` can be stored as an optional valuation snapshot because posting may occur after the source document command returns.

## Domain Model Definitions

### Model type

Stateful

#### State Transitions

```mermaid
stateDiagram-v2
    [*] --> Draft: createGoodsReceipt / createGoodsIssue / submitStockAdjustment
    [*] --> Posted: shipTransferOrder / receiveTransferOrder
    Draft --> Draft: updateGoodsReceipt / updateGoodsIssue
    Draft --> Cancelled: cancelGoodsReceipt / cancelGoodsIssue
    Draft --> Posted: postGoodsReceipt / postGoodsIssue / confirmStockAdjustment
```

Creation is represented as the initial state transition into `DRAFT`. The transition table below lists operations on existing InventoryExecution records that are generated into `inventoryExecutionLifecycle`.

| Operation | From | To | Command |
|-----------|------|----|---------|
| update | DRAFT | DRAFT | [updateGoodsReceipt](../command/UpdateGoodsReceipt.md) / [updateGoodsIssue](../command/UpdateGoodsIssue.md) |
| cancel | DRAFT | CANCELLED | [cancelGoodsReceipt](../command/CancelGoodsReceipt.md) / [cancelGoodsIssue](../command/CancelGoodsIssue.md) |
| post | DRAFT | POSTED | [postGoodsReceipt](../command/PostGoodsReceipt.md) / [postGoodsIssue](../command/PostGoodsIssue.md) / [confirmStockAdjustment](../command/ConfirmStockAdjustment.md) |

### Command Definitions

- [createGoodsReceipt](../command/CreateGoodsReceipt.md) - Creates a DRAFT goods receipt execution
- [updateGoodsReceipt](../command/UpdateGoodsReceipt.md) - Updates a DRAFT goods receipt execution
- [cancelGoodsReceipt](../command/CancelGoodsReceipt.md) - Cancels a DRAFT goods receipt execution without deleting it
- [postGoodsReceipt](../command/PostGoodsReceipt.md) - Posts a DRAFT goods receipt execution
- [createGoodsIssue](../command/CreateGoodsIssue.md) - Creates a DRAFT goods issue execution
- [updateGoodsIssue](../command/UpdateGoodsIssue.md) - Updates a DRAFT goods issue execution
- [cancelGoodsIssue](../command/CancelGoodsIssue.md) - Cancels a DRAFT goods issue execution without deleting it
- [postGoodsIssue](../command/PostGoodsIssue.md) - Posts a DRAFT goods issue execution
- [shipTransferOrder](../command/ShipTransferOrder.md) - Posts a transfer shipment execution
- [receiveTransferOrder](../command/ReceiveTransferOrder.md) - Posts a transfer receipt execution
- [confirmStockAdjustment](../command/ConfirmStockAdjustment.md) - Posts adjustment execution lines and links ledger rows through InventoryExecution

### Query Definitions

- [getGoodsReceipt](../query/GetGoodsReceipt.md) - Retrieves one goods receipt InventoryExecution with its execution lines
- [listGoodsReceipts](../query/ListGoodsReceipts.md) - Lists goods receipt InventoryExecution records with their execution lines
- [listPurchaseReceiptEvidenceForMatching](../query/ListPurchaseReceiptEvidenceForMatching.md) - Lists posted purchase goods-receipt evidence for supplier bill matching
- [getGoodsIssue](../query/GetGoodsIssue.md) - Retrieves one goods issue InventoryExecution with its execution lines
- [listGoodsIssues](../query/ListGoodsIssues.md) - Lists goods issue InventoryExecution records with their execution lines
- Traceability queries can join InventoryLedger to InventoryExecution through `inventoryExecutionId` after posting flows populate the linkage.

### Models

- InventoryExecution
- InventoryExecutionLine

### Invariants

- executionType must be GOODS_RECEIPT, GOODS_ISSUE, or STOCK_ADJUSTMENT
- status must be DRAFT, CANCELLED, or POSTED
- DRAFT executions must not affect InventoryLedger, StockLevel, LotStockLevel, SerialNumber, or valuation
- CANCELLED executions must not affect InventoryLedger, StockLevel, LotStockLevel, SerialNumber, or valuation
- POSTED executions are immutable stock execution facts; reversal is modeled as a separate execution when introduced
- effectiveDate is required and represents the business effective date
- postedAt is set when status becomes POSTED
- sourceDocumentType and sourceDocumentId are optional generic source references and are not cross-module foreign keys
- Purchase goods receipt uses `sourceDocumentType=PURCHASE_ORDER` and `sourceDocumentId=PurchaseOrder.id`
- Every InventoryExecutionLine references its InventoryExecution header
- InventoryExecutionLine direction must be IN or OUT
- InventoryExecutionLine itemId, quantity, unitId, primaryQuantity, primaryUnitId, unitConversionRate, storageLocationId, and stockType are required
- InventoryExecutionLine quantity, primaryQuantity, and unitConversionRate must be positive
- InventoryExecutionLine unitCost is optional and must be non-negative when present
- InventoryExecutionLine primaryUnitId is a snapshot of Item.unitId when the execution line is created
- InventoryExecutionLine primaryQuantity equals quantity multiplied by unitConversionRate after inventory rounding rules
- InventoryExecutionLine sourceLineId is an optional generic source line reference and is not a cross-module foreign key
- Purchase goods receipt lines use `sourceLineId=PurchaseOrderLine.id`

### Relationships

- **Has InventoryExecutionLine**: Each execution owns one or more line-level stock effects
- **Referenced by InventoryLedger**: Ledger rows can point to the execution that produced the stock posting
- **InventoryExecutionLine references Item**: Each line affects one Item from item-management
- **InventoryExecutionLine references StorageLocation**: Each line affects one inventory location
- **InventoryExecutionLine references Lot (optional)**: For lot-tracked items, the line can identify the lot
- **InventoryExecutionLine references SerialNumber (optional)**: For serial-tracked items, the line can identify the serial number
