# CancelPurchaseOrder

## Permission Scope

purchaseOrder

## Overview

CancelPurchaseOrder stops a purchase order before fulfillment becomes irreversible and moves `orderStatus` to `CANCELLED`.

## Business Rules

- Target purchase order must exist
- Only orders with `orderStatus` in `DRAFT`, `SUBMITTED`, or `ORDERED` can be cancelled
- Cancellation is forbidden once a posted goods receipt exists against any active line
- Cancellation is forbidden once a matched supplier bill exists against any active line
- 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| H{Posted receipt or matched bill exists on any line?}
    H -->|Yes| I[Return PURCHASE_ORDER_ALREADY_FULFILLED]
    H -->|No| J["Set orderStatus to CANCELLED"]
    J --> K[Return cancelled order]
```

## External Dependencies

- None

## Error Scenarios

- **PURCHASE_ORDER_NOT_FOUND**: Referenced 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
