Skip to content

Product Inventory Management

This guide explains how inventory tracking works for products, including stock quantities, reservations, and reorder points.

Overview

Each product can track inventory across multiple warehouses. The system maintains separate inventory records for each product-warehouse combination, allowing for distributed inventory management.

Inventory Tracking

Enabling Inventory Tracking

When creating a product, set track_inventory to enable inventory management:

bash
POST /api/v1/operations/products
{
  "name": "Premium Laptop",
  "sku": "LAPTOP-001",
  "selling_price": 1299.99,
  "track_inventory": true,
  "stock_quantity": 100,
  "reorder_point": 20,
  "reorder_quantity": 50
}

Inventory Fields:

FieldTypeDescription
track_inventorybooleanEnable/disable inventory tracking
stock_quantityintegerInitial stock quantity (quantity on hand)
reserved_quantityintegerStock allocated to orders
reorder_pointintegerMinimum stock level before reordering
reorder_quantityintegerSuggested quantity to reorder
allow_backorderbooleanAllow orders when out of stock

Stock Quantities

The system maintains three key quantities:

  1. Quantity On Hand - Physical stock in warehouse
  2. Quantity Reserved - Stock allocated to pending orders
  3. Quantity Available - On hand minus reserved (available to sell)
quantity_available = quantity_on_hand - quantity_reserved

Business Rules:

  • quantity_on_hand cannot be negative
  • quantity_reserved cannot exceed quantity_on_hand
  • quantity_available is computed, not stored

Stock Status

Products automatically calculate their stock status:

json
{
  "id": 123,
  "name": "Premium Laptop",
  "stock_status": "in_stock",
  "in_stock": true,
  "stock_quantity": 45
}

Stock Statuses:

StatusCondition
in_stockquantity_available > 0
out_of_stockquantity_available <= 0 and backorders not allowed
on_backorderquantity_available <= 0 and backorders allowed
low_stockquantity_on_hand <= reorder_point

Inventory Endpoints

Get Product Inventory

Retrieve detailed inventory information for a product:

bash
GET /api/v1/operations/products/123?include=inventory

Response:

json
{
  "data": {
    "id": 123,
    "name": "Premium Laptop",
    "sku": "LAPTOP-001",
    "stock_status": "in_stock",
    "in_stock": true,
    "inventory": {
      "quantity_on_hand": 45,
      "quantity_reserved": 10,
      "quantity_available": 35,
      "reorder_point": 20,
      "reorder_quantity": 50,
      "last_counted_at": "2025-01-10T14:30:00Z",
      "last_movement_at": "2025-01-15T09:15:00Z"
    }
  }
}

Adjust Stock Level

Manually adjust inventory quantity:

bash
POST /api/v1/operations/inventory/{productId}/adjust
{
  "quantity": 10,
  "reason": "Received shipment from supplier",
  "reference": "PO-2025-001"
}

Parameters:

  • quantity - Change amount (positive = increase, negative = decrease)
  • reason - Required explanation for audit trail
  • reference - Optional reference (PO number, count ID, etc.)

Response:

json
{
  "message": "Stock adjusted successfully",
  "data": {
    "product_id": 123,
    "warehouse_id": 1,
    "quantity_on_hand": 55,
    "quantity_available": 45,
    "adjustment": 10
  }
}

Reserve Stock

Reserve stock for pending orders:

bash
POST /api/v1/operations/inventory/{productId}/reserve
{
  "quantity": 5,
  "order_id": 789,
  "notes": "Reserved for order #789"
}

This increases quantity_reserved and decreases quantity_available.

Release Stock

Release previously reserved stock:

bash
POST /api/v1/operations/inventory/{productId}/release
{
  "quantity": 3,
  "order_id": 789,
  "reason": "Order partially cancelled"
}

This decreases quantity_reserved and increases quantity_available.

Physical Inventory Count

Record actual physical count from warehouse:

bash
POST /api/v1/operations/inventory/{productId}/count
{
  "counted_quantity": 48,
  "counted_by": "John Doe",
  "notes": "Monthly inventory count"
}

What happens:

  1. System compares counted quantity with quantity_on_hand
  2. Automatically adjusts if discrepancy found
  3. Creates stock movement record for audit trail
  4. Updates last_counted_at timestamp

Response:

json
{
  "message": "Physical count recorded successfully",
  "data": {
    "product_id": 123,
    "counted_quantity": 48,
    "previous_quantity": 45,
    "discrepancy": 3,
    "quantity_on_hand": 48,
    "last_counted_at": "2025-01-15T16:45:00Z"
  }
}

Reorder Management

Reorder Points

Set minimum stock level that triggers reorder alert:

bash
PATCH /api/v1/operations/products/123
{
  "reorder_point": 25,
  "reorder_quantity": 100
}

Low Stock Alerts

Get products below reorder point:

bash
GET /api/v1/operations/inventory/low-stock

Response:

json
{
  "data": [
    {
      "product_id": 123,
      "name": "Premium Laptop",
      "sku": "LAPTOP-001",
      "quantity_on_hand": 18,
      "reorder_point": 20,
      "reorder_quantity": 50,
      "suggested_order": 50
    }
  ]
}

Out of Stock Products

Get products with zero available stock:

bash
GET /api/v1/operations/inventory/out-of-stock

Reorder Report

Generate reorder recommendations:

bash
GET /api/v1/operations/inventory/reorder-report

Returns products below reorder point with suggested order quantities.

Multi-Warehouse Inventory

Warehouse-Specific Stock

Each product can have inventory in multiple warehouses:

bash
GET /api/v1/operations/products/123/inventory

Response:

json
{
  "data": [
    {
      "warehouse_id": 1,
      "warehouse_name": "Main Warehouse",
      "quantity_on_hand": 45,
      "quantity_reserved": 10,
      "quantity_available": 35
    },
    {
      "warehouse_id": 2,
      "warehouse_name": "East Coast Warehouse",
      "quantity_on_hand": 30,
      "quantity_reserved": 5,
      "quantity_available": 25
    }
  ],
  "total_available": 60
}

Transfer Between Warehouses

Move stock between locations:

bash
POST /api/v1/operations/inventory/transfer
{
  "product_id": 123,
  "from_warehouse_id": 1,
  "to_warehouse_id": 2,
  "quantity": 10,
  "notes": "Rebalancing inventory"
}

See Warehouse Transfers for details.

Inventory Validation

Business Rules Enforced

When updating inventory, the system enforces:

  1. No Negative Stock

    json
    {
      "errors": {
        "quantity": ["Stock quantity cannot be negative"]
      }
    }
  2. Reserved Cannot Exceed On Hand

    json
    {
      "errors": {
        "reserved_quantity": ["Reserved quantity cannot exceed stock quantity"]
      }
    }
  3. Sufficient Available Stock

    json
    {
      "errors": {
        "quantity": ["Insufficient stock available. Available: 5, Requested: 10"]
      }
    }

Stock Movement History

All inventory changes are tracked in stock movements:

bash
GET /api/v1/operations/stock-movements?product_id=123

Response:

json
{
  "data": [
    {
      "id": 456,
      "product_id": 123,
      "warehouse_id": 1,
      "movement_type": "in",
      "quantity": 50,
      "reference_type": "purchase_order",
      "reference_id": 789,
      "notes": "Received from PO-2025-001",
      "created_at": "2025-01-15T10:30:00Z"
    },
    {
      "id": 457,
      "movement_type": "out",
      "quantity": -5,
      "reference_type": "sales_order",
      "notes": "Shipped for order #1234",
      "created_at": "2025-01-15T14:20:00Z"
    }
  ]
}

Movement Types:

  • in - Stock received
  • out - Stock shipped/sold
  • adjustment - Manual adjustment
  • transfer - Warehouse transfer
  • count - Physical inventory count
  • reserved - Stock reservation
  • released - Reservation released

Best Practices

1. Regular Physical Counts

Perform physical inventory counts periodically to maintain accuracy:

bash
# Monthly count
POST /api/v1/operations/inventory/123/count

2. Set Appropriate Reorder Points

Calculate reorder points based on:

  • Average daily sales
  • Lead time from supplier
  • Safety stock buffer
reorder_point = (daily_sales × lead_time_days) + safety_stock

3. Monitor Low Stock

Check low stock report regularly:

bash
GET /api/v1/operations/inventory/low-stock

4. Use Stock Reservations

Reserve stock when orders are placed (not just when shipped):

bash
# When order is placed
POST /api/v1/operations/inventory/123/reserve
{
  "quantity": 2,
  "order_id": 789
}

# When order ships
POST /api/v1/operations/inventory/123/adjust
{
  "quantity": -2,
  "reason": "Shipped order #789"
}

# This also auto-releases the reservation

5. Track All Movements

Always provide context for inventory changes:

bash
POST /api/v1/operations/inventory/123/adjust
{
  "quantity": -3,
  "reason": "Damaged during inspection",
  "reference": "DMG-2025-001"
}

Next Steps

Documentation for SynthesQ CRM/ERP Platform