# CancelPurchaseBill

## Overview

CancelPurchaseBill voids a draft, blocked, or matched supplier bill while the bill is still owned by purchase and has not yet been accepted by downstream AP or accounting.

## Business Rules

- Target purchase bill must exist
- Only bills in `DRAFT`, `BLOCKED`, or `MATCHED` can be cancelled
- Cancellation is forbidden after downstream AP or accounting accepts the bill-ready handoff
- Cancellation preserves invoice identity, line references, and variance evidence for future dispute or credit-note workflows
- Cancelling a matched bill reverses the purchase-order billed quantity that was previously accumulated from that bill

## Process Flow

```mermaid
flowchart TD
    A[Receive cancel request] --> B{Purchase bill exists?}
    B -->|No| C[Return PURCHASE_BILL_NOT_FOUND]
    B -->|Yes| D{Status cancellable?}
    D -->|No| E[Return PURCHASE_BILL_NOT_CANCELLABLE]
    D -->|Yes| F{Downstream handoff already accepted?}
    F -->|Yes| G[Return DOWNSTREAM_HANDOFF_ACCEPTED]
    F -->|No| H[Preserve evidence and set CANCELLED]
    H --> I[Adjust PO billed quantity if previously matched]
    I --> J[Return cancelled bill]
```

## External Dependencies

- None

## Error Scenarios

- **PURCHASE_BILL_NOT_FOUND**: Target purchase bill does not exist
- **PURCHASE_BILL_NOT_CANCELLABLE**: Purchase bill status does not allow cancellation
- **DOWNSTREAM_HANDOFF_ACCEPTED**: Downstream AP or accounting already accepted the bill-ready handoff

## Test Cases

- cancels a draft purchase bill
- cancels a blocked purchase bill
- cancels a matched purchase bill before downstream acceptance
- preserves variance evidence when a blocked bill is cancelled
- reverses purchase-order billed quantity when a matched bill is cancelled
- returns error when purchase bill does not exist
- returns error when purchase bill status does not allow cancellation
- returns error when downstream handoff has already been accepted
