# TANRAIL ONE — Phase 3.2 Inventory Data Model

## 1. Location Architecture
Inventory must map to physical reality without hardcoding business types. 
- **Hierarchy:** `Organization` → `Business Unit` → `Branch` → `InventoryLocation`
- A `Branch` can possess multiple `InventoryLocation`s (e.g., "Cold Room", "Front Shelf", "Warehouse A").
- `InventoryLocation` belongs strictly to a `branch_id`.
- By belonging to a Branch, the location inherently inherits the `business_unit_id` and `organization_id` security boundaries established in Phase 2.

## 2. Stock Balance Model
The `StockBalance` represents the current physical reality of an item at a specific location.
- **Entity:** `StockBalance`
- **Keys:** `inventory_location_id`, `item_id`
- **Fields:** 
  - `quantity` (Decimal: The total physical amount currently sitting in the location).
  - `reserved_quantity` (Decimal: Amount promised to pending orders/transfers but not yet physically removed).
- **Available Stock Formula:** `AVAILABLE = quantity - reserved_quantity`

## 3. Stock Movement Model (The Ledger)
The `StockMovement` table is the immutable ledger of all quantity changes.
- **Generic Types:** `RECEIVE`, `ISSUE`, `TRANSFER`, `ADJUST`
- **Fields:**
  - `item_id`
  - `type` (Enum)
  - `source_location_id` (Nullable: Null for external receipts)
  - `destination_location_id` (Nullable: Null for external issues)
  - `quantity` (Decimal)
  - `reference_type` / `reference_id` (Polymorphic link to the Order, Invoice, or Transfer that caused the movement).
  - `user_id` (Actor who performed it).

## 4. Transfer Model
Generic movement of stock between two internal locations.
- **Entity:** `StockTransfer`
- **Lifecycle:** `PENDING` → `IN_TRANSIT` (Optional) → `COMPLETED` / `CANCELLED`
- **Fields:** `source_location_id`, `destination_location_id`, `item_id`, `requested_qty`, `approved_qty`, `status`.
- *Note:* A completed `StockTransfer` mathematically results in two `StockMovement` records (Issue from Source, Receive at Destination).

## 5. Stock Adjustment Model
A formal process to correct discrepancies (e.g., physical count reveals 98 units, system says 100).
- Handled via a `StockMovement` of type `ADJUST`. 
- **Fields:** Requires a mandatory `reason` text field.
- **Approval:** Core permits direct adjustment by authorized roles. If a business requires multi-tier approval for adjustments, that workflow sits in the Reusable Module or Extension layer.

## 6. Unit of Measure & Item Relationship
- Inventory utilizes the `unit_id` defined directly on the `Item` (from Phase 3.1).
- **No Conversion Yet:** The system assumes stock is tracked in the Item's base unit. Unit conversion (e.g., buying in Pallets, issuing in Pieces) is a complex future capability that will not be implemented in this foundation phase.
- **Relationship:** Inventory applies equally to `PHYSICAL` and `PACKAGE` items. `SERVICE` items generally bypass inventory tracking (enforced by `Item->track_inventory` boolean).

## 7. Conceptual ERD

```mermaid
erDiagram
    BRANCH ||--o{ INVENTORY_LOCATION : owns
    INVENTORY_LOCATION ||--o{ STOCK_BALANCE : contains
    ITEM ||--o{ STOCK_BALANCE : tracks
    
    INVENTORY_LOCATION ||--o{ STOCK_MOVEMENT : source_for
    INVENTORY_LOCATION ||--o{ STOCK_MOVEMENT : destination_for
    ITEM ||--o{ STOCK_MOVEMENT : involves
    
    INVENTORY_LOCATION ||--o{ STOCK_TRANSFER : sends
    INVENTORY_LOCATION ||--o{ STOCK_TRANSFER : receives
    ITEM ||--o{ STOCK_TRANSFER : moves
```
