Back to ER Diagram
Inventory Management

Inventory Management System

Comprehensive documentation of inventory control including stock levels, batch/serial tracking, goods receipt, stock movements, and inventory adjustments.

PostgreSQL
11 Tables
Batch/Serial Tracking
Schema v2.4

Stock Quantity Types

The stock_levels table tracks multiple quantity states for accurate inventory visibility.

On Hand
Physical stock in warehouse
Reserved
Allocated to orders
On Order
Pending from POs
In Transit
Shipped, not received
-- Available quantity calculation
SELECT
    item_id,
    warehouse_id,
    quantity_on_hand,
    quantity_reserved,
    quantity_on_order,
    quantity_in_transit,
    (quantity_on_hand - quantity_reserved) AS available_qty,
    (quantity_on_hand - quantity_reserved + quantity_on_order + quantity_in_transit) AS projected_qty
FROM inventory.stock_levels
WHERE item_id = :item_id;

Available vs Projected

Available: On Hand minus Reserved - what can be picked right now.
Projected: Available plus On Order plus In Transit - expected future availability.

Stock Movement Types

RECEIPT

Goods received from vendor

ISSUE

Items issued to production/dept

TRANSFER

Move between warehouses

ADJUSTMENT

Quantity corrections

RETURN

Return to vendor

SCRAP

Written off items

Movement Type Effect on Stock Reference Document
RECEIPT + quantity_on_hand, - quantity_in_transit GRN, ASN
ISSUE - quantity_on_hand, - quantity_reserved Issue Slip, Work Order
TRANSFER - from_warehouse, + to_warehouse Transfer Order
ADJUSTMENT +/- quantity_on_hand (variance) Stock Adjustment

Inventory Tables

inventory.warehouses

  • warehouse_code - Unique identifier per company
  • warehouse_type - GENERAL, RAW_MATERIAL, FINISHED_GOODS, COLD_STORAGE, BONDED
  • location_id - Reference to organization.locations
  • manager_id - Warehouse manager user
  • capacity_sqft - Storage capacity

inventory.storage_locations

  • location_code - Bin/rack identifier (e.g., A-01-02-03)
  • location_type - ZONE, AISLE, RACK, SHELF, BIN, PALLET
  • aisle / rack / shelf / bin - Hierarchical address
  • capacity - Maximum storage capacity

inventory.items

  • item_code - Unique item identifier
  • item_type - INVENTORY, NON_INVENTORY, SERVICE, ASSET
  • track_serial / track_batch / track_expiry - Tracking flags
  • reorder_level / reorder_qty - Replenishment triggers
  • lead_time_days - Standard procurement lead time
  • specifications - JSONB for technical specs

inventory.stock_levels

  • item_id + warehouse_id + storage_location_id - Unique stock position
  • quantity_on_hand - Physical stock count
  • quantity_reserved - Allocated to pending orders
  • quantity_on_order - Expected from POs
  • quantity_in_transit - Shipped but not received
  • last_movement_date - For slow-moving detection

inventory.stock_batches

  • batch_number - Lot/batch identifier
  • serial_number - For serialized items
  • manufacturing_date / expiry_date - Date tracking
  • status - AVAILABLE, QUARANTINE, EXPIRED, CONSUMED
  • grn_id - Receipt reference for traceability

inventory.stock_movements

  • movement_number - Unique transaction ID
  • movement_type - RECEIPT, ISSUE, TRANSFER, ADJUSTMENT, RETURN, SCRAP
  • from_warehouse_id / to_warehouse_id - Source/destination
  • reference_type / reference_id - Document linkage
  • batch_number / serial_number - Lot tracking

Goods Receipt Flow

PO Created
+ quantity_on_order
ASN Received
+ quantity_in_transit
GRN Created
QC Inspection
+ quantity_on_hand
- quantity_on_order
- quantity_in_transit
1

Create GRN Header

System generates GRN number, links to PO and ASN (if exists), captures receipt metadata.

INSERT INTO inventory.grns (
    grn_number, po_id, vendor_id, warehouse_id,
    receipt_date, received_by, status
)
VALUES (
    generate_grn_number(), :po_id, :vendor_id, :warehouse_id,
    CURRENT_DATE, :user_id, 'DRAFT'
);
2

Enter GRN Items

For each PO line, record received quantity, batch/serial info, and storage location.

3

Quality Inspection

If item requires QC, create inspection record. Accepted/rejected quantities determined.

Accepted

  • Update accepted_qty on GRN item
  • Create stock batch record
  • Update stock_levels

Rejected

  • Update rejected_qty on GRN item
  • Create debit note if applicable
  • Create return document
4

Complete GRN & Update Stock

Finalize GRN, create stock movement records, update all quantity fields.

-- Update stock levels on GRN completion
UPDATE inventory.stock_levels
SET
    quantity_on_hand = quantity_on_hand + :accepted_qty,
    quantity_on_order = quantity_on_order - :ordered_qty,
    quantity_in_transit = quantity_in_transit - :shipped_qty,
    last_movement_date = CURRENT_TIMESTAMP,
    updated_at = CURRENT_TIMESTAMP
WHERE
    item_id = :item_id
    AND warehouse_id = :warehouse_id;

Batch & Serial Tracking

Batch Tracking

Track items by lot/batch number. Useful for:

  • - Pharmaceuticals with expiry dates
  • - Food products with manufacturing dates
  • - Chemicals with lot specifications
  • - FIFO/FEFO consumption policies

Serial Tracking

Track individual items by serial number. Useful for:

  • - Equipment with warranties
  • - High-value assets
  • - Items requiring maintenance records
  • - Traceability requirements

FIFO/FEFO Logic

-- FEFO: First Expiry, First Out - for items with expiry tracking
SELECT
    sb.batch_number,
    sb.quantity,
    sb.expiry_date
FROM inventory.stock_batches sb
WHERE
    sb.item_id = :item_id
    AND sb.warehouse_id = :warehouse_id
    AND sb.status = 'AVAILABLE'
    AND sb.quantity > 0
    AND sb.expiry_date > CURRENT_DATE  -- Not expired
ORDER BY
    sb.expiry_date ASC,  -- Earliest expiry first
    sb.created_at ASC;   -- Then FIFO within same expiry

Expiry Alerts

A scheduled job checks stock_batches daily for items expiring within a configurable window (default 30 days). Notifications are sent to warehouse managers and purchase teams.

Stock Adjustment Process

Physical Count
Create Adjustment
Enter Actual Quantities
System Calculates Variance
Approval (if needed)
Apply Adjustment
Adjustment Type Description Approval Required
PHYSICAL_COUNT Reconciliation after inventory count Yes, if variance > threshold
DAMAGE Items damaged in storage Yes
EXPIRY Expired items written off Manager approval
CORRECTION Error correction Yes, with documentation
WRITE_OFF Full inventory write-off Finance + Management
-- Stock adjustment item with auto-calculated variance
CREATE TABLE inventory.stock_adjustment_items (
    ...
    system_qty DECIMAL(18, 4) NOT NULL,
    actual_qty DECIMAL(18, 4) NOT NULL,
    variance_qty DECIMAL(18, 4) GENERATED ALWAYS AS
        (actual_qty - system_qty) STORED,
    ...
);

Reorder Point Logic

-- Items below reorder level
SELECT
    i.item_code,
    i.item_name,
    sl.warehouse_id,
    w.warehouse_name,
    sl.quantity_on_hand,
    sl.quantity_reserved,
    (sl.quantity_on_hand - sl.quantity_reserved) AS available,
    sl.quantity_on_order,
    i.reorder_level,
    i.reorder_qty,
    i.lead_time_days,
    CASE
        WHEN (sl.quantity_on_hand - sl.quantity_reserved + sl.quantity_on_order) <= i.reorder_level
        THEN 'REORDER_NOW'
        WHEN (sl.quantity_on_hand - sl.quantity_reserved) <= i.min_stock
        THEN 'CRITICAL'
        ELSE 'OK'
    END AS stock_status
FROM inventory.items i
JOIN inventory.stock_levels sl ON i.id = sl.item_id
JOIN inventory.warehouses w ON sl.warehouse_id = w.id
WHERE
    i.is_active = true
    AND i.is_stockable = true
    AND (sl.quantity_on_hand - sl.quantity_reserved + sl.quantity_on_order) <= i.reorder_level
ORDER BY
    stock_status DESC,
    available ASC;

Auto-PR Generation

When configured, the system can automatically generate Purchase Requisitions for items below reorder level. The PR includes the reorder_qty and preferred vendors from vendor-item mappings.

Best Practices

Regular Cycle Counts

Instead of annual full counts, perform regular cycle counts on high-value/high-movement items. Use stock_adjustments to record and approve variances.

Use Storage Locations

For large warehouses, leverage storage_locations with aisle/rack/shelf/bin hierarchy. This enables efficient picking paths and capacity planning.

Monitor Expiry Dates

Set up alerts for items expiring within lead_time_days. This provides time to use or return items before they expire and become waste.

Maintain Movement Trail

Every stock change should create a stock_movements record with proper reference. This is essential for traceability and audit compliance.