# ClosePurchaseOrder

## Permission Scope

purchaseOrder

## Overview

ClosePurchaseOrder sets `orderStatus` to `CLOSED` on a purchase order that has progressed beyond the initial ordering phase, and prevents further receipt or billing activity on the remaining open quantity. The `receiptStatus` and `billingStatus` values are preserved as-is for audit.

## Business Rules

- Target purchase order must exist
- Only orders with `orderStatus` = `ORDERED` can be closed (i.e., the order must have been approved and not already cancelled or closed)
- Remaining open quantity must already be fully received, fully billed, or explicitly written off with a close reason
- Closing preserves the original ordered, received, and billed quantities for audit
- Closed orders reject new goods receipts and new purchase bills
- Close validation uses each active line's received and billed quantities directly (sum of posted GoodsReceiptLine and MATCHED PurchaseBillLine records referencing each line)

## Process Flow

```mermaid
flowchart TD
    A[Receive close request] --> B{Purchase order exists?}
    B -->|No| C[Return PURCHASE_ORDER_NOT_FOUND]
    B -->|Yes| D{Status closable?}
    D -->|No| E[Return PURCHASE_ORDER_NOT_CLOSABLE]
    D -->|Yes| H{Open quantity fully resolved or write-off reason provided?}
    H -->|No| I[Return OPEN_QUANTITY_REMAINS]
    H -->|Yes| J["Set orderStatus to CLOSED (preserve receiptStatus and billingStatus)"]
    J --> K[Return closed order]
```

## External Dependencies

- None

## Error Scenarios

- **PURCHASE_ORDER_NOT_FOUND**: Referenced purchase order does not exist
- **PURCHASE_ORDER_NOT_CLOSABLE**: Purchase order status does not allow closure
- **OPEN_QUANTITY_REMAINS**: Remaining quantity is not fulfilled or explicitly written off
- **CLOSE_REASON_REQUIRED**: Residual open quantity exists but no write-off reason was provided

## Test Cases

- closes a fully billed purchase order
- closes a partially received order when remaining quantity is explicitly written off
- returns error when purchase order does not exist
- returns error when purchase order status does not allow closure
- returns error when unresolved open quantity remains
- returns error when residual quantity exists without a close reason
- allows closure without write-off when each line is fully received
- returns OPEN_QUANTITY_REMAINS before requiring a close reason when write-off is not requested
- closes an order with no lines (empty PO line IDs skip GR/Bill line queries)
- sums received and billed quantities across multiple GR/bill lines per PO line
- detects open quantity when only billed but not received
