# 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 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
- `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`. 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
    Draft --> Draft: updateGoodsReceipt / updateGoodsIssue
    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) |
| 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
- [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
- [postGoodsIssue](../command/PostGoodsIssue.md) - Posts a DRAFT goods issue 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 or POSTED
- DRAFT 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
