# CancelOutboundShipment

## Permission Scope

outboundShipmentOperation

## Overview

cancelOutboundShipment transitions a DRAFT OutboundShipment to CANCELLED. It is a soft cancel: the OutboundShipment and OutboundShipmentLine rows remain for traceability, but no stock, ledger, reservation, or valuation changes occur. Posted outbound shipments cannot be cancelled.

## Business Rules

- The target OutboundShipment must exist
- Only DRAFT outbound shipments can be cancelled
- Cancellation transitions status from DRAFT to CANCELLED
- Cancellation does not delete the OutboundShipment or OutboundShipmentLine rows
- Cancellation does not create InventoryLedger rows or update StockLevel, StockReservation, or valuation records
- POSTED shipments cannot be cancelled; future correction is represented by a separate reversal document when introduced

## Process Flow

```mermaid
flowchart TD
    A[Cancel outbound shipment request] --> B[Lock OutboundShipment]
    B --> C{DRAFT?}
    C -->|No| D[Return error: INVALID_STATUS]
    C -->|Yes| E[Transition OutboundShipment to CANCELLED]
    E --> F[Return cancelled shipment id]
```

## External Dependencies

- [outbound-shipment::OutboundShipment](../model/OutboundShipment.md) - Validates existence and current status, then updates status to CANCELLED
- [outbound-shipment::OutboundShipmentLine](../model/OutboundShipment.md) - Retained as the draft line snapshot; not deleted

## Error Scenarios

- **INVALID_STATUS**: Target entity is not in a valid status for this operation

## Test Cases

- returns error when outbound shipment is missing
- returns error when outbound shipment is posted
- transitions draft outbound shipment to CANCELLED without deleting lines
