# UpdateTransferOrder

## Permission Scope

transferOrder

## Overview

updateTransferOrder updates a DRAFT TransferOrder via `headerPatch` and revises its lines via `addLines`, `updateLines`, and `removeLineIds`.

## Business Rules

- Only DRAFT transfer orders can be updated
- Source and destination sites can be changed but must remain different
- Source and destination sites must belong to the same company; cross-company transfers are not supported
- `plannedShipmentDate` and `expectedReceiptDate` can be changed while the order is DRAFT
- `updateLines` and `removeLineIds` must target a line that exists on the order
- `updateLines` patches the existing line in place, so its id and createdAt are preserved
- At least one line must remain after the changes
- Added and updated line `unitId` values are derived from each referenced item primary unit; callers do not choose transfer-specific units
- Added lines are initialized with `shippedQuantity = 0` and `receivedQuantity = 0`
- No stock execution or ledger posting occurs
- No StockReservation or InventorySupplyPlan rows are created until openTransferOrder

## Process Flow

```mermaid
flowchart TD
    A[Receive update transfer order request] --> B[Lock TransferOrder]
    B --> C{TransferOrder exists and is DRAFT?}
    C -->|No| D[Return not found or state error]
    C -->|Yes| E{Target lines exist?}
    E -->|No| F[Return error: TRANSFER_ORDER_LINE_NOT_FOUND]
    E -->|Yes| G{Sites and lines valid?}
    G -->|No| H[Return validation error]
    G -->|Yes| I[Update TransferOrder header and lines]
    I --> J[Return transfer order and lines]
```

## External Dependencies

- [organization::Site](../../../organization/docs/model/Site.md) - Validates source and destination sites
- [item-management::Item](../../../item-management/docs/model/Item.md) - Validates referenced line items and derives each added or updated line primary unit
- [inventory::TransferOrder](../model/TransferOrder.md) - Updates the transfer order header
- [inventory::TransferOrderLine](../model/TransferOrderLine.md) - Adds, updates, and removes transfer order lines

## Error Scenarios

- **TRANSFER_ORDER_NOT_FOUND**: Transfer order does not exist
- **TRANSFER_ORDER_LINE_NOT_FOUND**: Transfer order line does not exist or does not belong to the order
- **EMPTY_TRANSFER_LINES**: No transfer lines were provided
- **INVALID_QUANTITY**: Quantity is zero or negative
- **INVALID_STATE_TRANSITION**: Transfer order lifecycle transition is not allowed
- **INVALID_TRANSFER_LOCATIONS**: Transfer location or site is invalid
- **CROSS_COMPANY_TRANSFER_NOT_SUPPORTED**: Transfer between sites of different companies is not supported
- **ITEM_NOT_FOUND**: Referenced item does not exist
- **SITE_NOT_FOUND**: Referenced site does not exist

## Test Cases

- updates header metadata on a draft transfer order
- updates a line in place so its id and createdAt survive the edit
- adds a transfer order line via addLines
- removes a transfer order line via removeLineIds
- returns error when transfer order is not DRAFT
- returns error when an update targets a missing line
- returns error when a removal would leave the transfer order without lines
- returns error when an added line ordered quantity is zero or negative
- returns error when a site change makes the transfer cross-company
