---
id: WF-COM-FUL-016
title: Record stock movements and transfers and fill backorders
trigger: 'Staff receipt, adjustment or transfer changes physical stock.'
product_area: commerce
module: fulfillment
revision: 1
status: draft
design_intent: confirmed
origin: >-
  Decision M, Andrew 2026-10-18 ("build the transfer now"):
  services-commerce:docs/migrations/inventory/README.md#D-P8I-14
implementation_evidence: observed
inference: []
source_sha:
  services-commerce: c8b66a98e2490617aec38ba5c8165dd9bd0a8f9b
implements:
  - CAP-COM-FUL-017
  - CAP-COM-FUL-018
moves:
  - STATE-COM-FUL-009
crosses:
  - SVC-COM-FUL-inventory
idempotency: >-
  A movement key returns the original only when the checked movement facts
  agree. Transfer halves derive stable keys from the same request.
concurrency: >-
  Transfers lock participating item identities in stable order. Backorder fill
  locks candidate units and obeys the available-stock constraints.
hops:
  - 'n': 1
    actor_or_service: Inventory API (movement)
    action: >-
      Validate movement type and sign, create a permitted receipt item when
      needed and append the balance-changing ledger entry.
    anchor: >-
      services-commerce:modules/inventory/services/persistence/inventory-movements.ts:recordMovement
    seam: sync
    on_failure: Refuse the movement when database balances cannot support it.
    left_inconsistent: The failed movement changes no balance.
    observer: Movement response.
    provenance: observed
    source: >-
      services-commerce:modules/inventory/services/stock/staff-movements.ts:recordStaffMovement
  - 'n': 2
    actor_or_service: Inventory API (same transaction)
    action: >-
      Commit waiting backorders in oldest-order order when sellable stock
      arrives.
    anchor: >-
      services-commerce:modules/inventory/services/persistence/inventory-allocations.ts:fillBackorders
    seam: sync
    on_failure: Rollback the incoming movement if its fill fails.
    left_inconsistent: No partial incoming balance survives that transaction.
    observer: Filled allocation records.
    provenance: observed
    source: 'services-commerce:modules/inventory/services/stock/staff-movements.ts'
  - 'n': 3
    actor_or_service: 'Inventory API (transfer, one transaction)'
    action: >-
      Validate transfer availability and places, retain both paired movements,
      move cost layers and fill destination backorders.
    anchor: >-
      services-commerce:modules/inventory/services/stock/transfer-stock.ts:transferStock
    seam: sync
    on_failure: Rollback the complete transfer on refusal.
    left_inconsistent: Neither movement half survives a failed transfer.
    observer: Transfer readback.
    provenance: documented
    source: 'services-commerce:docs/migrations/inventory/README.md#D-P8I-14'
branches:
  - >-
    Shipment, restock, transfer and count movements are retained only by their
    own processes; staff may not record them directly.
  - >-
    The filled backorders are picked at a subsequent shipment's creation, not
    re-dispatched.
waits: []
evidence:
  - >-
    services-commerce at c8b66a98: modules/inventory/services/stock/*.ts;
    services/persistence/inventory-movements.ts, inventory-allocations.ts,
    inventory-transfers.ts; modules/purchasing/services/cost/transfer-cost.ts;
    docs/migrations/inventory/README.md (D-P8I-05, D-P8I-14, D-P8I-22).
controls: [TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-AZ-005, TC-AZ-006, TC-TEN-001, TC-TEN-002, TC-TEN-003, TC-CRY-001, TC-DAT-001, TC-DAT-002, TC-DAT-003, TC-LOG-004, TC-LOG-005, TC-PI-001, TC-PI-003, TC-PI-005, TC-PRV-001, TC-PRV-002]
---

# Record Stock Movements and Transfers and Fill Backorders

## What It Does

Staff movements explain receipts and adjustments through the ledger. Sellable arrivals fill waiting backorders. Transfers retain paired outgoing and incoming movements, carry cost layers and fill destination backorders inside one transaction.

## The Flow

```mermaid
sequenceDiagram
  participant S as Staff
  participant I as Inventory API
  participant M as Movement ledger
  participant A as Allocation ledger
  participant C as Cost layers
  S->>I: movement or transfer (key, reason)
  I->>M: write movement(s); balances move
  I->>C: transfer moves cost (same transaction)
  I->>A: fill backorders at sellable locations
  I-->>S: recorded, or the original on repeat
```

## When Something Fails

Invalid signs, unavailable quantities or conflicting key reuse refuse the transaction. A failed transfer retains neither half. Repeated valid movement keys return the original facts rather than moving stock again.
