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:
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:
| Field | Type | Description |
|---|---|---|
track_inventory | boolean | Enable/disable inventory tracking |
stock_quantity | integer | Initial stock quantity (quantity on hand) |
reserved_quantity | integer | Stock allocated to orders |
reorder_point | integer | Minimum stock level before reordering |
reorder_quantity | integer | Suggested quantity to reorder |
allow_backorder | boolean | Allow orders when out of stock |
Stock Quantities
The system maintains three key quantities:
- Quantity On Hand - Physical stock in warehouse
- Quantity Reserved - Stock allocated to pending orders
- Quantity Available - On hand minus reserved (available to sell)
quantity_available = quantity_on_hand - quantity_reservedBusiness Rules:
quantity_on_handcannot be negativequantity_reservedcannot exceedquantity_on_handquantity_availableis computed, not stored
Stock Status
Products automatically calculate their stock status:
{
"id": 123,
"name": "Premium Laptop",
"stock_status": "in_stock",
"in_stock": true,
"stock_quantity": 45
}Stock Statuses:
| Status | Condition |
|---|---|
in_stock | quantity_available > 0 |
out_of_stock | quantity_available <= 0 and backorders not allowed |
on_backorder | quantity_available <= 0 and backorders allowed |
low_stock | quantity_on_hand <= reorder_point |
Inventory Endpoints
Get Product Inventory
Retrieve detailed inventory information for a product:
GET /api/v1/operations/products/123?include=inventoryResponse:
{
"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:
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 trailreference- Optional reference (PO number, count ID, etc.)
Response:
{
"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:
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:
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:
POST /api/v1/operations/inventory/{productId}/count
{
"counted_quantity": 48,
"counted_by": "John Doe",
"notes": "Monthly inventory count"
}What happens:
- System compares counted quantity with
quantity_on_hand - Automatically adjusts if discrepancy found
- Creates stock movement record for audit trail
- Updates
last_counted_attimestamp
Response:
{
"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:
PATCH /api/v1/operations/products/123
{
"reorder_point": 25,
"reorder_quantity": 100
}Low Stock Alerts
Get products below reorder point:
GET /api/v1/operations/inventory/low-stockResponse:
{
"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:
GET /api/v1/operations/inventory/out-of-stockReorder Report
Generate reorder recommendations:
GET /api/v1/operations/inventory/reorder-reportReturns products below reorder point with suggested order quantities.
Multi-Warehouse Inventory
Warehouse-Specific Stock
Each product can have inventory in multiple warehouses:
GET /api/v1/operations/products/123/inventoryResponse:
{
"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:
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:
No Negative Stock
json{ "errors": { "quantity": ["Stock quantity cannot be negative"] } }Reserved Cannot Exceed On Hand
json{ "errors": { "reserved_quantity": ["Reserved quantity cannot exceed stock quantity"] } }Sufficient Available Stock
json{ "errors": { "quantity": ["Insufficient stock available. Available: 5, Requested: 10"] } }
Stock Movement History
All inventory changes are tracked in stock movements:
GET /api/v1/operations/stock-movements?product_id=123Response:
{
"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 receivedout- Stock shipped/soldadjustment- Manual adjustmenttransfer- Warehouse transfercount- Physical inventory countreserved- Stock reservationreleased- Reservation released
Best Practices
1. Regular Physical Counts
Perform physical inventory counts periodically to maintain accuracy:
# Monthly count
POST /api/v1/operations/inventory/123/count2. 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_stock3. Monitor Low Stock
Check low stock report regularly:
GET /api/v1/operations/inventory/low-stock4. Use Stock Reservations
Reserve stock when orders are placed (not just when shipped):
# 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 reservation5. Track All Movements
Always provide context for inventory changes:
POST /api/v1/operations/inventory/123/adjust
{
"quantity": -3,
"reason": "Damaged during inspection",
"reference": "DMG-2025-001"
}Next Steps
- Learn about Stock Movements tracking
- Understand Warehouse Transfers
- Review Physical Count procedures
- Explore Purchase Order Workflow for restocking