# AmendOrderedPurchaseOrder

## Permission Scope

purchaseOrder

## Overview

AmendOrderedPurchaseOrder atomically amends an `ORDERED` purchase order by adding, modifying, or removing lines. For each affected line, a `PurchaseOrderLineRevision` snapshot is recorded before the change is applied. The PO's `revisionNumber` is incremented and receipt/billing statuses are recalculated.

## Business Rules

- Target purchase order must exist and be in `ORDERED` status
- Changes array must contain at least one action (empty amendments are rejected to prevent phantom revision increments)
- MODIFY: updates the existing line in-place (same ID). Quantity and unitPrice are optional — omitting either preserves the current value (supports price-only amendments). unitId cannot be changed (UOM is immutable once ordered — use REMOVE + ADD instead)
- MODIFY: quantity cannot be reduced below the line's cumulative non-cancelled received (posted + draft) or billed (matched + draft/blocked) quantity
- MODIFY: quantity must be positive, unitPrice must be non-negative
- MODIFY: receivingSiteId must exist if provided
- REMOVE: blocked if the line has any posted receipt or matched bill quantity
- REMOVE: blocked if draft or blocked downstream documents (GoodsReceipt, PurchaseBill) still reference the line
- REMOVE: physically deletes the PurchaseOrderLine row; snapshot preserved in PurchaseOrderLineRevision
- ADD: itemId and unitId are required; itemId must reference an existing item (ACTIVE check skipped — post-approval flow)
- ADD: quantity must be positive, unitPrice must be non-negative
- ADD: receivingSiteId must exist if provided
- ADD: item snapshot (name, SKU) is captured at amendment time
- After processing all changes, `revisionNumber` is incremented
- Receipt and billing statuses are recalculated from remaining PO lines

## Process Flow

```mermaid
flowchart TD
    A[Receive amend request] --> B{PO exists and ORDERED?}
    B -->|No| C[Return error]
    B -->|Yes| C2{Changes non-empty?}
    C2 -->|No| C
    C2 -->|Yes| D[Validate each change]
    D -->|Fail| E[Return validation error]
    D -->|Pass| F[Process MODIFY: snapshot then update in-place]
    F --> G[Process REMOVE: snapshot then delete]
    G --> H[Process ADD: create line and snapshot]
    H --> I[Increment revisionNumber]
    I --> J[Recalculate receiptStatus and billingStatus]
    J --> K[Return amended PO]
```

## External Dependencies

- [itemManagement::getItem](../../../item-management/docs/queries/GetItem.md) - Validates item existence for ADD actions

## Error Scenarios

- **PO_NOT_FOUND**: Target purchase order does not exist
- **PO_NOT_ORDERED**: Purchase order is not in `ORDERED` status
- **EMPTY_AMENDMENT_CHANGES**: Amendment contains no changes
- **LINE_NOT_FOUND**: Referenced line does not exist on the target order
- **MODIFY_QUANTITY_BELOW_RECEIVED**: MODIFY reduces quantity below the line's non-cancelled received quantity (posted + draft)
- **MODIFY_QUANTITY_BELOW_BILLED**: MODIFY reduces quantity below the line's non-cancelled billed quantity (matched + draft/blocked)
- **REMOVE_LINE_HAS_RECEIPTS**: REMOVE targets a line with posted receipt quantity
- **REMOVE_LINE_HAS_BILLS**: REMOVE targets a line with matched bill quantity
- **REMOVE_LINE_HAS_DOWNSTREAM_REFERENCES**: REMOVE targets a line referenced by draft or blocked downstream documents
- **ADD_INVALID_QUANTITY**: ADD action has zero or negative quantity
- **ITEM_NOT_FOUND**: Referenced item does not exist
- **INVALID_QUANTITY**: Quantity is zero or negative
- **INVALID_UNIT_PRICE**: Unit price is negative or otherwise invalid
- **RECEIVING_SITE_NOT_FOUND**: Referenced receiving site does not exist
- **RECEIVING_SITE_REQUIRED**: A physical-receipt line has no receiving site

## Test Cases

- amends a PO with a MODIFY action (line ID unchanged, values updated)
- amends a PO with a REMOVE action (line physically deleted)
- amends a PO with an ADD action (new line created, no line receivingSiteId — header is used)
- creates PurchaseOrderLineRevision snapshot for MODIFY with pre-change values
- creates PurchaseOrderLineRevision snapshot for REMOVE with pre-deletion values
- creates PurchaseOrderLineRevision snapshot for ADD with new values
- increments revisionNumber after amendment
- recalculates receiptStatus after amendment
- recalculates billingStatus after amendment
- supports price-only amendment (quantity not provided)

- returns error when changes array is empty
- returns error when PO does not exist
- returns error when PO is not ORDERED
- returns error when MODIFY references a non-existent line
- returns error when MODIFY reduces quantity below received
- returns error when MODIFY reduces quantity below billed
- returns error when MODIFY reduces quantity below posted + draft received
- returns error when MODIFY reduces quantity below matched + draft/blocked billed
- returns error when REMOVE targets a line with posted receipts
- returns error when REMOVE targets a line with matched bills
- returns error when REMOVE targets a line referenced by draft downstream documents
- returns error when ADD has zero or negative quantity
- returns error when ADD references a non-existent item
