# README

## Overview

The Inventory module manages physical stock tracking across storage locations. It provides real-time visibility into on-hand quantities and records all stock movements (receipts, issues, adjustments). The module also handles inventory valuation, physical inventory counts, and scrap disposal.

Inventory operates at the Item level (from item-management) and tracks stock within StorageLocations that the module owns. Organization's Site entity represents the physical facility (with address); each StorageLocation belongs directly to a Site.

## Key Features

- **Location Management**: Define StorageLocations under organizational Sites
- **Stock Tracking**: Real-time on-hand, blocked, in-transit, and location-level stock plus site-level reservation availability
- **Supply Planning**: Site-level future inbound supply projections via InventorySupplyPlan for planning and ATP workflows
- **Stock Movement**: A single posting API (`postInventoryLedger`) for externally driven changes from document modules (inbound-shipment, outbound-shipment), plus StockAdjustment workflow (CORRECTION / SCRAP / BLOCK / UNBLOCK) for operator-initiated changes — all producing immutable InventoryLedger records
- **Inventory Adjustment**: Manual corrections for discrepancies, damage, and shrinkage via StockAdjustment(CORRECTION)
- **Inventory Valuation**: Standard, FIFO, and moving-average costing over per-receipt cost layers, journalized directly in financial-accounting
- **Acquisition Cost Adjustment**: Invoice-driven receipt cost correction (`postAcquisitionCostAdjustment`) restating layers, averages, COGS, and variances when the invoiced price differs from the receipt cost
- **Inventory Count**: Physical inventory counts and cycle counts with variance review and approval
- **Scrap Management**: Record and track disposal of damaged, expired, or defective stock via StockAdjustment(SCRAP)

## Module Scope

### In Scope

- Storage location definition and management (flat, no zone/bin hierarchy)
- Real-time stock tracking per item/location and source-line reservations per item/site
- Future inbound supply projections per item and site using InventorySupplyPlan
- Stock posting API (`postInventoryLedger`) and StockAdjustment approval workflow (CORRECTION / SCRAP / BLOCK / UNBLOCK)
- Immutable inventory ledger recording for all stock changes (InventoryLedger) referencing its cause document generically via sourceType/sourceId/sourceLineId
- Inventory adjustment with reason codes via StockAdjustment(CORRECTION)
- Inventory valuation configuration (STANDARD, FIFO, and AVERAGE policies with posting accounts; per-item versioned standard costs)
- Costed-quantity tracking (CostLayer / CostLayerConsumption) maintained by every costed movement
- Standard costing of movements with PPV capture and revision revaluation
- FIFO actual costing of movements
- Moving-average costing of movements
- Invoice-driven acquisition cost adjustment (`postAcquisitionCostAdjustment`) called by account-payable posting, restating receipt layers and consumed cost by costing method
- Physical inventory count and cycle count workflows
- Scrap/disposal recording with quantity and valuation impact via StockAdjustment(SCRAP)

### Out of Scope

- Purchase order lifecycle management (purchasing module)
- Goods receipt / goods issue document lifecycle (inbound-shipment / outbound-shipment modules)
- Sales order and fulfillment workflows (sales module)
- Automated reorder point and replenishment rules (purchasing module)
- Pick/pack/ship multi-step fulfillment (warehouse operations / sales module)
- Putaway rules and automated storage location assignment
- Removal strategies — automated FIFO/FEFO/LIFO picking rules
- Demand forecasting and automated replenishment planning
- Drop-shipping and cross-docking
- Landed cost allocation (purchasing / future management-accounting module)
- Cross-company transfers (transfer orders between sites of different companies are rejected)
- Restating the billed quantity for a purchase order price change (only the unbilled quantity is repriced; the billed quantity's difference reaches inventory through posted AP correction documents)
- Account master and journal-entry mechanics (coa-management / financial-accounting modules; inventory records costing journals as drafts through financial-accounting commands)
- Barcode scanning device integration (application layer)
- Shipping carrier integration (application layer)

### Scope Decision Rationale

Inventory owns **physical stock state** -- where items are, how many exist, and what they cost. This is separated from purchasing (which owns the procurement lifecycle) and sales (which owns the fulfillment lifecycle) because stock tracking follows its own business rules and update patterns.

StorageLocation is owned by this module (not organization) because it represents an operational storage type with inventory-specific attributes (capacity, storage conditions). Organization's Site represents the physical facility identity and address; StorageLocation layers the storage layout directly on top of a Site. We intentionally do not introduce an intermediate "Warehouse" entity — locations belong directly to a Site, matching SAP MM's Plant → Storage Location pattern.

Stock changes flow through two complementary patterns, both landing in the immutable **InventoryLedger**:

- **The posting API** (`postInventoryLedger`) records movements handed over by document modules — inbound-shipment goods receipts, outbound-shipment goods issues, manufacturing completions — that have already gone through their own approval lifecycle
- **StockAdjustment** provides an approval workflow (DRAFT → SUBMITTED → CONFIRMED) for operator-initiated changes (CORRECTION, SCRAP, BLOCK, UNBLOCK). Ledger writes occur only on confirmation

InventoryLedger entries reference their cause document generically via `sourceType`, `sourceId`, and `sourceLineId`; the document itself (inbound shipment, outbound shipment, transfer order, stock adjustment) lives in its owning module or aggregate. This keeps the immutable ledger focused on stock facts while keeping document context queryable.

StockLevel is maintained as a per-(item, location, stockType) physical/logical balance cache derived from InventoryLedger. Reservation (`createStockReservation` / `updateStockReservation` / `closeStockReservation`) updates StockReservation instead of StockLevel and does not produce ledger entries, because reservations represent source-line demand commitments against site-level available stock rather than physical movement. Issue execution consumes reservations internally. Site-level availability is computed as the sum of `StockLevel(stockType=AVAILABLE)` across active site locations minus OPEN reservation quantity for the item and site, where open reservation quantity is `max(reservedQuantity - consumedQuantity, 0)`.

Inventory valuation is included because costing is intrinsically tied to inventory transactions (receipt costs, adjustment impacts). Inventory owns the costing decision — which amounts hit which posting roles — and records balanced draft journal entries through financial-accounting commands in the same transaction as the movement; account masters and journal mechanics stay in coa-management and financial-accounting.

## Module Dependencies

- [item-management](../item-management/README.md) — Item entity as the primary trackable unit (itemId/SKU)
- [organization](../organization/README.md) — Company for multi-company scoping, Site for physical facility (address, and parent of StorageLocation)
- [primitives](../primitives/README.md) — Unit of Measure for stock quantities, Currency for valuation amounts
