# 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 any purchase-order line has billed quantity
- Cancelling preserves the original order for audit and traceability
- Cancelling closes any open inventory supply plans linked to the purchase-order lines

## 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 billed quantity exists on any line?}
    H -->|Yes| I[Return PURCHASE_ORDER_ALREADY_FULFILLED]
    H -->|No| J["Set orderStatus to CANCELLED"]
    J --> K[Close linked inventory supply plans]
    K --> L[Return cancelled order]
```

## External Dependencies

- [inventory::CloseInventorySupplyPlan](../../../inventory/docs/command/CloseInventorySupplyPlan.md) - Closes cancelled supplier commitments using `SOURCE_DOCUMENT` input for the PO source document

## 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 billed quantity already exists against the order

## Test Cases

- cancels a draft purchase order
- cancels a submitted purchase order
- cancels an ordered purchase order with no receipts or billed quantity
- 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 billed quantity already exists
