# ReleasePurchaseBill

## Permission Scope

purchaseBill

## Overview

ReleasePurchaseBill moves a blocked supplier bill to `MATCHED` after an authorized user confirms that the recorded variance is acceptable or has been resolved outside the original comparison.

## Business Rules

- Target purchase bill must exist
- Only bills in `BLOCKED` status can be released
- Release reason or override note is required for audit
- Released bills preserve the original blocked variance evidence in addition to the release decision
- Releasing a bill recalculates the due schedule if needed

## Process Flow

```mermaid
flowchart TD
    A[Receive release request] --> B{Purchase bill exists?}
    B -->|No| C[Return PURCHASE_BILL_NOT_FOUND]
    B -->|Yes| D{Status is BLOCKED?}
    D -->|No| E[Return PURCHASE_BILL_NOT_BLOCKED]
    D -->|Yes| F{Override reason provided?}
    F -->|No| G[Return RELEASE_REASON_REQUIRED]
    F -->|Yes| H[Preserve variance evidence and set MATCHED]
    H --> I[Prepare due schedule]
    I --> J[Return released bill]
```

## External Dependencies

- None

## Error Scenarios

- **PURCHASE_BILL_NOT_FOUND**: Referenced purchase bill does not exist
- **PURCHASE_BILL_NOT_BLOCKED**: Purchase bill is not in `BLOCKED` status
- **RELEASE_REASON_REQUIRED**: No override or resolution reason was provided
- **PAYMENT_SCHEDULE_CALCULATION_FAILED**: Due schedule could not be derived from the payment-term snapshot

## Test Cases

- releases a blocked purchase bill with an override reason
- preserves original variance evidence when releasing
- returns error when purchase bill does not exist
- returns error when purchase bill is not blocked
- returns error when override reason is missing
- creates ThreeWayMatchEvent records when releasing a THREE_WAY blocked bill
- returns error when payment schedule calculation fails
- releases a bill with PO-unlinked lines (null purchaseOrderLineId)
- skips order line when getOrderLine returns undefined
- falls back to empty array when bill paymentTermSnapshotLines is null
