# StockLevel

## Description

StockLevel tracks the current quantity of a specific item at a specific storage location. It maintains four quantity buckets: on-hand (physically present), reserved (allocated for outbound orders), incoming (expected inbound from confirmed purchase orders), and blocked (quarantined stock, including stock under inspection). The available quantity is derived as on-hand minus reserved minus blocked. Stock levels are updated internally when InventoryLedger entries are created, when reservations are placed or released, and when incoming quantities are adjusted by upstream modules.

Stock level records persist even when all quantities reach zero — they are never deleted.

## Domain Model Definitions

### Model type

Standard

### Command Definitions

- Stock levels are updated internally by the following operations:
  - [receiveStock](../commands/ReceiveStock.md) - Increases onHand, decreases incoming. When `toBlocked=true`, also increases blocked (stock under inspection); available remains unchanged
  - [issueStock](../commands/IssueStock.md) - Decreases onHand. When `fromBlocked=true`, also decreases blocked (returning blocked stock)
  - [confirmStockAdjustment](../commands/ConfirmStockAdjustment.md) - Adjusts onHand and/or blocked depending on adjustment type
  - [reserveStock](../commands/ReserveStock.md) - Increases reserved
  - [releaseReservation](../commands/ReleaseReservation.md) - Decreases reserved
- The `blocked` field is updated by: `receiveStock(toBlocked=true)`, `issueStock(fromBlocked=true)`, `confirmStockAdjustment(BLOCK/UNBLOCK)`, `confirmStockAdjustment(SCRAP, fromStockCategory=BLOCKED)`

### Query Definitions

- [getStockLevel](../queries/GetStockLevel.md) - Retrieve the stock level for a specific item at a specific location
- [listStockLevels](../queries/ListStockLevels.md) - List stock levels with optional filters
- [getSiteStockSummary](../queries/GetSiteStockSummary.md) - Retrieve aggregated stock summary for a site

### Models

- StockLevel

### Invariants

- Unique per item-storageLocation pair
- Available quantity = onHand - reserved - blocked
- Available quantity cannot go negative (reservation or block rejected if it would exceed available)
- blocked includes both explicitly blocked (quarantined) stock and stock under inspection
- Quantities are stored in the item's base unit of measure
- Records persist with zero quantities and are not deleted
- Concurrent movements must produce correct final quantities

### Relationships

- **References Item**: Each stock level references an Item from the item-management module
- **References StorageLocation**: Each stock level belongs to a specific storage location
