# outbound-shipment-processing

## Overview

Handles the issue of goods against confirmed sales orders — the sales-side mirror of inbound-shipment-processing (入庫). An Inventory Manager creates a DRAFT outbound shipment, choosing an issue-from storage location; the order's open quantities (ordered − shipped) are pre-filled per line. Posting reduces AVAILABLE stock and advances the linked sales order's shipped quantities and `fulfillmentStatus` in the same transaction. A DRAFT outbound shipment can be cancelled; a posted one cannot.

An outbound shipment is backed by an `OutboundShipment` header + `OutboundShipmentLine` rows (erp-kit 0.45 `outbound-shipment` module), created against a sales order. The source-document link lives on each line: `sourceDocumentType = SALES_ORDER`, `sourceDocumentId` = the sales order, and `sourceLineId` pointing at a sales order line — the mirror of how an inbound shipment is an `InboundShipment` against a purchase order.

> **Cross-module boundary.** Posting an outbound shipment reduces AVAILABLE stock, consumes matching reservations, and passes `SALES_ORDER` source-line deltas to the sales module. The sales module updates `fulfilledQuantity` and derives `fulfillmentStatus` in the same transaction.

## Actors Involved

- [Inventory Manager](../../actor/inventory-manager.md) — creates, settles, and cancels outbound shipments (fulfilment operator)

See [action-matrix.md](./action-matrix.md) for models involved and the action visibility matrix.

## Flow Diagram

```mermaid
sequenceDiagram
    participant IM as Inventory Manager
    participant S as System

    Note over S: A CONFIRMED sales order (sales-order-lifecycle) is the source; open quantity per line = ordered − shipped

    IM->>S: Create outbound shipment against sales order (issue-from location)
    S->>S: Pre-fill open quantities (ordered − shipped) per line
    S-->>IM: Outbound Shipment in DRAFT status (no stock moved)

    IM->>S: Settle (post) outbound shipment
    S->>S: Post outbound shipment (postOutboundShipment) → reduce AVAILABLE stock (ledger + StockLevel, consume matching reservations)
    S-->>IM: Outbound Shipment status → POSTED

    Note over S: Sales order fulfilledQuantity / status is NOT advanced here — reflecting fulfilment onto the order is a separate cross-module concern

    Note over IM,S: A DRAFT can be cancelled instead of settled

    IM->>S: Cancel outbound shipment
    S-->>IM: Outbound Shipment status → CANCELLED

    Note over S: Settle fails with INVENTORY_INSUFFICIENT_STOCK when there is not enough AVAILABLE stock; a posted outbound shipment cannot be cancelled (OUTBOUND_SHIPMENT_INVALID_STATUS)
```

## Stories

- [Create Outbound Shipment](./story/inventory-manager--create-outbound-shipment.md)
- [Settle Outbound Shipment](./story/inventory-manager--settle-outbound-shipment.md)
