# PostGoodsReceipt

## Permission Scope

inventoryOperation

## Overview

postGoodsReceipt posts a DRAFT goods receipt InventoryExecution. It consumes matching open InventorySupplyPlan quantities, creates GOODS_RECEIPT InventoryLedger rows, increases AVAILABLE StockLevel balances, updates lot stock when a lot is present, applies valuation, and marks the execution POSTED.

For purchase receipts, prefer `purchase.commands.postGoodsReceipt` instead of calling `inventory.commands.postGoodsReceipt` directly. The purchase command is the public purchase-facing entrypoint and also applies purchase-side synchronization after posting.

## Business Rules

- The target InventoryExecution must exist, have `executionType=GOODS_RECEIPT`, and be in DRAFT status
- Posting is based on the InventoryExecutionLine snapshot
- At least one execution line must exist before posting
- Each line posts a GOODS_RECEIPT / DR ledger row linked by inventoryExecutionId
- Ledger quantity uses primaryQuantity
- If the receipt line has source linkage that matches open supply plans for the item and site, posting consumes supply-plan open quantity before creating ledger rows
- If source linkage is missing or no supply plan matches, posting continues without supply-plan consumption
- Unit cost defaults to zero when omitted
- The execution is marked POSTED with postedAt after all stock effects are applied

## Process Flow

```mermaid
flowchart TD
    A[Post goods receipt request] --> B[Lock InventoryExecution]
    B --> C{GOODS_RECEIPT and DRAFT?}
    C -->|No| D[Return error: INVALID_STATUS]
    C -->|Yes| E[Load InventoryExecutionLine rows]
    E --> F[Validate item, location, lot, and serial references]
    F --> G[Consume matching supply plans]
    G --> H[Create GOODS_RECEIPT ledger rows]
    H --> I[Increase StockLevel and LotStockLevel]
    I --> J[Apply valuation]
    J --> K[Mark InventoryExecution POSTED]
    K --> L[Return posted execution and ledger entries]
```

## External Dependencies

- [item-management::Item](../../../item-management/docs/model/Item.md) - Validates referenced items
- [inventory::InventoryExecution](../model/InventoryExecution.md) - Reads and posts the execution header, applying inbound execution lines
- [inventory::InventoryLedger](../model/InventoryLedger.md) - Records immutable stock ledger rows
- [inventory::InventorySupplyPlan](../model/InventorySupplyPlan.md) - Consumes matching open supply quantities for linked receipt lines
- [inventory::StockLevel](../model/StockLevel.md) - Increases available stock

## Error Scenarios

- **INVALID_STATUS**: Target entity is not in a valid status for this operation
- **EMPTY_RECEIPT_LINES**: No goods receipt lines were provided
- **ITEM_NOT_FOUND**: Referenced item does not exist
- **STORAGE_LOCATION_NOT_FOUND**: Referenced storage location does not exist
- **INVALID_UNIT_COST**: Unit cost is negative
- **LOT_NOT_FOUND**: Referenced lot does not exist
- **SERIAL_NOT_FOUND**: Referenced serial number does not exist

## Test Cases

- returns error when execution is missing
- returns error when execution has no lines
- posts execution lines into ledger and stock
- consumes matching supply plans when posting
- posts receipt without supply matching when source linkage is missing
- posts receipt without supply matching when no supply plan matches
- posts receipt and consumes available supply when receipt quantity exceeds supply
