# CancelPurchaseOrder

## Overview

CancelPurchaseOrder stops a purchase order before fulfillment becomes irreversible and moves it into `CANCELLED` status.

## Business Rules

- Target purchase order must exist
- Only orders in `DRAFT`, `SUBMITTED`, or `ORDERED` can be cancelled
- Cancellation is forbidden once a posted goods receipt exists
- Cancellation is forbidden once a matched supplier bill exists
- Cancelling preserves the original order for audit and traceability

## Process Flow

```mermaid
flowchart TD
    A[Receive cancel request] --> B{Purchase order exists?}
    B -->|No| C[Return PURCHASE_ORDER_NOT_FOUND]
    B -->|Yes| D{Status cancellable?}
    D -->|No| E[Return PURCHASE_ORDER_NOT_CANCELLABLE]
    D -->|Yes| F{Posted receipt or matched bill exists?}
    F -->|Yes| G[Return PURCHASE_ORDER_ALREADY_FULFILLED]
    F -->|No| H[Set status to CANCELLED]
    H --> I[Return cancelled order]
```

## External Dependencies

- None

## Error Scenarios

- **PURCHASE_ORDER_NOT_FOUND**: Target purchase order does not exist
- **PURCHASE_ORDER_NOT_CANCELLABLE**: Purchase order status does not allow cancellation
- **PURCHASE_ORDER_ALREADY_FULFILLED**: Posted receipts or matched bills already exist against the order

## Test Cases

- cancels a draft purchase order
- cancels a submitted purchase order
- cancels an ordered purchase order with no receipts or matched bills
- returns error when purchase order does not exist
- returns error when purchase order status does not allow cancellation
- returns error when a posted receipt already exists
- returns error when a matched bill already exists
