# UpdateGoodsReceipt

## Permission Scope

inventoryOperation

## Overview

updateGoodsReceipt updates a DRAFT goods receipt InventoryExecution and can replace its inbound InventoryExecutionLine set.

For purchase receipts, prefer `purchase.commands.updateGoodsReceipt` instead of calling `inventory.commands.updateGoodsReceipt` directly. The purchase command is the public purchase-facing entrypoint and keeps callers aligned with the purchase module boundary.

## Business Rules

- The target InventoryExecution must exist, have `executionType=GOODS_RECEIPT`, and be in DRAFT status
- Posted goods receipts cannot be updated
- effectiveDate can be updated independently
- sourceDocumentType and sourceDocumentId are immutable after creation
- When lines are provided, the complete existing line set is replaced
- Replacement lines follow the same validation rules as createGoodsReceipt
- Replacement lines must provide both source-unit quantity/unitId and converted primaryQuantity/unitConversionRate snapshots
- Replacement line primaryUnitId must equal Item.unitId
- Replacement line unitCost must be zero or greater when provided
- No stock or ledger changes occur during update

## Process Flow

```mermaid
flowchart TD
    A[Update goods receipt request] --> B[Lock InventoryExecution]
    B --> C{GOODS_RECEIPT and DRAFT?}
    C -->|No| D[Return error: INVALID_STATUS]
    C -->|Yes| E[Apply header updates]
    E --> F{Lines provided?}
    F -->|No| G[Return updated execution]
    F -->|Yes| H{At least one line?}
    H -->|No| I[Return error: EMPTY_RECEIPT_LINES]
    H -->|Yes| J[Validate replacement lines]
    J --> K[Delete existing execution lines]
    K --> L[Insert replacement execution lines]
    L --> M[Return execution and lines]
```

## External Dependencies

- [item-management::Item](../../../item-management/docs/model/Item.md) - Validates referenced items
- [inventory::InventoryExecution](../model/InventoryExecution.md) - Updates the goods receipt execution header and replaces inbound execution lines

## Error Scenarios

- **INVALID_STATUS**: Target entity is not in a valid status for this operation
- **EMPTY_RECEIPT_LINES**: No goods receipt lines were provided
- **INVALID_QUANTITY**: Quantity is zero or negative
- **PRIMARY_UNIT_MISMATCH**: primaryUnitId differs from Item.unitId
- **INVALID_UNIT_CONVERSION_RATE**: Unit conversion rate is zero or negative
- **INVALID_UNIT_COST**: Unit cost is negative
- **ITEM_NOT_FOUND**: Referenced item does not exist
- **STORAGE_LOCATION_NOT_FOUND**: Referenced storage location does not exist
- **LOT_NOT_FOUND**: Referenced lot does not exist
- **SERIAL_NOT_FOUND**: Referenced serial number does not exist

## Test Cases

- updates header fields without replacing lines
- replaces lines for a DRAFT goods receipt
- returns error when replacement line unit cost is negative
- returns error when replacement line primary quantity is zero or negative
- returns error when replacement line unit conversion rate is zero or negative
- returns error when replacement line primary unit differs from item primary unit
