# CancelInboundShipment

## Permission Scope

inboundShipmentOperation

## Overview

cancelInboundShipment transitions a DRAFT InboundShipment to CANCELLED. It is a soft cancel: the InboundShipment and InboundShipmentLine rows remain for traceability, but no stock, ledger, supply-plan, or valuation changes occur. Posted inbound shipments cannot be cancelled.

## Business Rules

- The target InboundShipment must exist
- Only DRAFT inbound shipments can be cancelled
- Cancellation transitions status from DRAFT to CANCELLED
- Cancellation does not delete the InboundShipment or InboundShipmentLine rows
- Cancellation does not create InventoryLedger rows or update StockLevel, InventorySupplyPlan, 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 inbound shipment request] --> B[Lock InboundShipment]
    B --> C{DRAFT?}
    C -->|No| D[Return error: INVALID_STATUS]
    C -->|Yes| E[Transition InboundShipment to CANCELLED]
    E --> F[Return cancelled shipment id]
```

## External Dependencies

- [inbound-shipment::InboundShipment](../model/InboundShipment.md) - Validates existence and current status, then updates status to CANCELLED
- [inbound-shipment::InboundShipmentLine](../model/InboundShipment.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 inbound shipment is missing
- returns error when inbound shipment is posted
- transitions draft inbound shipment to CANCELLED without deleting lines
