Files
orion/app/modules/inventory/docs/user-guide.md
Samir Boulahtit f141cc4e6a docs: migrate module documentation to single source of truth
Move 39 documentation files from top-level docs/ into each module's
docs/ folder, accessible via symlinks from docs/modules/. Create
data-model.md files for 10 modules with full schema documentation.
Replace originals with redirect stubs. Remove empty guide stubs.

Modules migrated: tenancy, billing, loyalty, marketplace, orders,
messaging, cms, catalog, inventory, hosting, prospecting.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 23:38:37 +01:00

9.4 KiB

Inventory Management

Overview

The Orion platform provides comprehensive inventory management with support for:

  • Multi-location tracking - Track stock across warehouses, stores, and storage bins
  • Reservation system - Reserve items for pending orders
  • Digital products - Automatic unlimited inventory for digital goods
  • Admin operations - Manage inventory on behalf of stores

Key Concepts

Storage Locations

Inventory is tracked at the storage location level. Each product can have stock in multiple locations:

Product: "Wireless Headphones"
├── WAREHOUSE_MAIN: 100 units (10 reserved)
├── WAREHOUSE_WEST: 50 units (0 reserved)
└── STORE_FRONT: 25 units (5 reserved)

Total: 175 units | Reserved: 15 | Available: 160

Location naming: Locations are text strings, normalized to UPPERCASE (e.g., WAREHOUSE_A, STORE_01).

Inventory States

Field Description
quantity Total physical stock at location
reserved_quantity Items reserved for pending orders
available_quantity quantity - reserved_quantity (can be sold)

Product Types & Inventory

Product Type Inventory Behavior
Physical Requires inventory tracking, orders check available stock
Digital Unlimited inventory - no stock constraints
Service Treated as digital (unlimited)
Subscription Treated as digital (unlimited)

Digital Products

Digital products have unlimited inventory by default. This means:

  • Orders for digital products never fail due to "insufficient inventory"
  • No need to create inventory entries for digital products
  • The available_inventory property returns 999999 (effectively unlimited)

How It Works

# In Product model
@property
def has_unlimited_inventory(self) -> bool:
    """Digital products have unlimited inventory."""
    return self.is_digital

@property
def available_inventory(self) -> int:
    """Calculate available inventory."""
    if self.has_unlimited_inventory:
        return 999999  # Unlimited
    return sum(inv.available_quantity for inv in self.inventory_entries)

Setting a Product as Digital

Digital products are identified by the is_digital flag on the MarketplaceProduct:

marketplace_product.is_digital = True
marketplace_product.product_type_enum = "digital"
marketplace_product.digital_delivery_method = "license_key"  # or "download", "email"

Inventory Operations

Set Inventory

Replace the exact quantity at a location:

POST /api/v1/store/inventory/set
{
    "product_id": 123,
    "location": "WAREHOUSE_A",
    "quantity": 100
}

Adjust Inventory

Add or remove stock (positive = add, negative = remove):

POST /api/v1/store/inventory/adjust
{
    "product_id": 123,
    "location": "WAREHOUSE_A",
    "quantity": -10  // Remove 10 units
}

Reserve Inventory

Mark items as reserved for an order:

POST /api/v1/store/inventory/reserve
{
    "product_id": 123,
    "location": "WAREHOUSE_A",
    "quantity": 5
}

Release Reservation

Cancel a reservation (order cancelled):

POST /api/v1/store/inventory/release
{
    "product_id": 123,
    "location": "WAREHOUSE_A",
    "quantity": 5
}

Fulfill Reservation

Complete an order (items shipped):

POST /api/v1/store/inventory/fulfill
{
    "product_id": 123,
    "location": "WAREHOUSE_A",
    "quantity": 5
}

This decreases both quantity and reserved_quantity.


Reservation Workflow

┌─────────────────┐
│  Order Created  │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│ Reserve Items   │  reserved_quantity += order_qty
└────────┬────────┘
         │
    ┌────┴────┐
    │         │
    ▼         ▼
┌───────┐  ┌──────────┐
│Cancel │  │  Ship    │
└───┬───┘  └────┬─────┘
    │           │
    ▼           ▼
┌─────────┐  ┌──────────────┐
│ Release │  │   Fulfill    │
│reserved │  │ quantity -=  │
│  -= qty │  │ reserved -=  │
└─────────┘  └──────────────┘

Admin Inventory Management

Administrators can manage inventory on behalf of any store through the admin UI at /admin/inventory or via the API.

Admin UI Features

The admin inventory page provides:

  • Overview Statistics - Total entries, stock quantities, reserved items, and low stock alerts
  • Filtering - Filter by store, location, and low stock threshold
  • Search - Search by product title or SKU
  • Stock Adjustment - Add or remove stock with optional reason tracking
  • Set Quantity - Set exact stock quantity at any location
  • Delete Entries - Remove inventory entries

Admin API Endpoints

List All Inventory

GET /api/v1/admin/inventory
GET /api/v1/admin/inventory?store_id=1
GET /api/v1/admin/inventory?low_stock=10

Get Inventory Statistics

GET /api/v1/admin/inventory/stats

Response:
{
    "total_entries": 150,
    "total_quantity": 5000,
    "total_reserved": 200,
    "total_available": 4800,
    "low_stock_count": 12,
    "stores_with_inventory": 5,
    "unique_locations": 8
}

Low Stock Alerts

GET /api/v1/admin/inventory/low-stock?threshold=10

Response:
[
    {
        "product_id": 123,
        "store_name": "TechStore",
        "product_title": "USB Cable",
        "location": "WAREHOUSE_A",
        "quantity": 3,
        "available_quantity": 2
    }
]

Set Inventory (Admin)

POST /api/v1/admin/inventory/set
{
    "store_id": 1,
    "product_id": 123,
    "location": "WAREHOUSE_A",
    "quantity": 100
}

Adjust Inventory (Admin)

POST /api/v1/admin/inventory/adjust
{
    "store_id": 1,
    "product_id": 123,
    "location": "WAREHOUSE_A",
    "quantity": 25,
    "reason": "Restocking from supplier"
}

Database Schema

Inventory Table

CREATE TABLE inventory (
    id SERIAL PRIMARY KEY,
    product_id INTEGER NOT NULL REFERENCES products(id),
    store_id INTEGER NOT NULL REFERENCES stores(id),
    location VARCHAR NOT NULL,
    quantity INTEGER NOT NULL DEFAULT 0,
    reserved_quantity INTEGER DEFAULT 0,
    gtin VARCHAR,
    created_at TIMESTAMP DEFAULT NOW(),
    updated_at TIMESTAMP DEFAULT NOW(),

    UNIQUE(product_id, location)
);

CREATE INDEX idx_inventory_store_product ON inventory(store_id, product_id);
CREATE INDEX idx_inventory_product_location ON inventory(product_id, location);

Constraints

  • Unique constraint: (product_id, location) - One entry per product/location
  • Foreign keys: References products and stores tables
  • Non-negative: quantity and reserved_quantity must be >= 0

Best Practices

Physical Products

  1. Create inventory entries before accepting orders
  2. Use meaningful location names (e.g., WAREHOUSE_MAIN, STORE_NYC)
  3. Monitor low stock using the admin dashboard or API
  4. Reserve on order creation to prevent overselling

Digital Products

  1. No inventory setup needed - unlimited by default
  2. Optional: Create entries for license key tracking
  3. Focus on fulfillment - digital delivery mechanism

Multi-Location

  1. Aggregate queries use Product.total_inventory and Product.available_inventory
  2. Location-specific operations use the Inventory model directly
  3. Transfers between locations: adjust down at source, adjust up at destination

API Reference

Store Endpoints

Method Endpoint Description
POST /api/v1/store/inventory/set Set exact quantity
POST /api/v1/store/inventory/adjust Add/remove quantity
POST /api/v1/store/inventory/reserve Reserve for order
POST /api/v1/store/inventory/release Cancel reservation
POST /api/v1/store/inventory/fulfill Complete order
GET /api/v1/store/inventory/product/{id} Product summary
GET /api/v1/store/inventory List with filters
PUT /api/v1/store/inventory/{id} Update entry
DELETE /api/v1/store/inventory/{id} Delete entry

Admin Endpoints

Method Endpoint Description
GET /api/v1/admin/inventory List all (cross-store)
GET /api/v1/admin/inventory/stats Platform statistics
GET /api/v1/admin/inventory/low-stock Low stock alerts
GET /api/v1/admin/inventory/stores Stores with inventory
GET /api/v1/admin/inventory/locations Unique locations
GET /api/v1/admin/inventory/stores/{id} Store inventory
GET /api/v1/admin/inventory/products/{id} Product summary
POST /api/v1/admin/inventory/set Set (requires store_id)
POST /api/v1/admin/inventory/adjust Adjust (requires store_id)
PUT /api/v1/admin/inventory/{id} Update entry
DELETE /api/v1/admin/inventory/{id} Delete entry