Chapter 45 min read

The Core Concept: Inventory Tracking Types

The Core Concept: Inventory Tracking Types

The key insight is that products don't differ by category (fruits vs laptops), they differ by how their stock is tracked. There are exactly 5 tracking behaviors that cover virtually every physical product on earth:

1. 📦 Simple Quantity (Count-Based)

  • Stock = a number. Sell one, subtract one.
  • Example: A packaged box of Wai Wai noodles, a bottle of Coke, a keyboard
  • This is what 90% of e-commerce systems do by default

2. ⚖️ Weighted / Measured (Unit-Based)

  • Stock tracked in kg, liters, meters — not "count"
  • When a customer buys 500g of rice, you deduct 0.5kg from your 50kg stock
  • Example: Loose rice, spices, fabric, cooking oil sold loose

3. 🧪 Batch / Lot Tracked (Perishables)

  • Stock is grouped into batches, each with an expiry date
  • You might have 3 batches of milk: Batch A (expires June 20), Batch B (expires June 25)
  • System enforces FIFO (First In, First Out) — sell the oldest batch first
  • Example: Milk, yogurt, meat, medicine, fruits & vegetables

4. 🔢 Serialized (Individual Unit Tracking)

  • Every single item has a unique serial number / IMEI
  • You don't just know "we have 5 laptops" — you know which 5 laptops
  • Enables warranty tracking, returns per unit, theft detection
  • Example: Laptops, phones, cameras, expensive jewelry

5. 📋 Catalog-Only (No Stock Tracking)

  • Just a menu. No inventory math at all.
  • Vendor manually toggles "Available" / "Unavailable"
  • Example: Restaurant dishes, bakery items baked daily, services (haircuts, repairs), made-to-order items

The Grocery Store Question (You're Right!)

Your instinct is spot-on. Nobody opens a carton of biscuits and scans each one. Here's what professional systems actually do:

  • Large retailers (Big Mart, Bhat-Bhateni): They use barcode POS scanning at checkout. Each scan deducts 1 from a bulk count. They do periodic physical inventory counts to reconcile.
  • Small grocery shops: They use Catalog-Only mode or a simple count. They reorder when the shelf looks empty (called Par Level system). No per-item tracking.
  • The pragmatic answer for Khoji Nepal: Let the vendor choose. A grocery store owner can list Wai Wai Noodles as a catalog item (available/unavailable) or as simple quantity ("I have ~200 packets"). Both are valid.

What About Variants? (Size, Color, Flavor)

Variants are separate from tracking type. A single product can have variants, and each variant has its own stock:

Product: "Nike Running Shoes"
  ├── Variant: Red / Size 8  → Stock: 12 (simple quantity)
  ├── Variant: Red / Size 9  → Stock: 8
  ├── Variant: Blue / Size 8 → Stock: 5
  └── Variant: Blue / Size 9 → Stock: 0 (out of stock)

Each variant gets its own SKU (Stock Keeping Unit) — a unique code.


Composite / Recipe Products (Bonus)

Some products are made from ingredients. When you sell 1 burger, the system deducts:

  • 1 bun from bun inventory
  • 1 patty from meat inventory
  • 2 lettuce leaves from produce inventory

This is called Bill of Materials (BOM) and is critical for restaurants and bakeries. It connects catalog-only menu items to actual ingredient inventory.


The Architecture: NOT Microservices

Should we create separate microservices for different product categories?

No! That would be massively over-engineered. You'd have to coordinate between services for orders, payments, search — it becomes a nightmare.

The correct approach is a single product & inventory system with a tracking_type field on each product:

Product
  ├── name, description, images, price
  ├── tracking_type: "simple" | "weighted" | "batch" | "serialized" | "catalog_only"
  ├── unit: "piece" | "kg" | "liter" | "meter" (for weighted)
  ├── has_variants: boolean
  └── Variants[] (optional)
        ├── sku, price_override, attributes (color, size, etc.)
        └── InventoryRecords[]
              ├── quantity / weight
              ├── batch_number (if batch)
              ├── expiry_date (if batch)
              └── serial_number (if serialized)

The UI adapts based on tracking_type:

  • If simple → show a quantity input
  • If weighted → show a weight input with unit selector
  • If batch → show batch form with expiry date picker
  • If serialized → show serial number entry field
  • If catalog_only → show just an availability toggle

This is exactly how professional systems like Odoo, ERPNext, Lightspeed, and Square handle it. One system, adaptive behavior.


Summary Table

Tracking TypeStock UnitExpiry?Per-Item ID?Example
Simple QuantityCountPackaged snacks, keyboards
Weightedkg/liter/meterLoose rice, fabric, oil
Batch/LotCount or WeightPer batchMilk, fruits, medicine
SerializedIndividual✅ (serial #)Laptops, phones, jewelry
Catalog OnlyNoneRestaurant dishes, services

What This Means for Khoji Nepal

When a vendor registers a product, we simply ask them: "How do you track this item?" and present friendly options like:

  • "I count individual pieces" → Simple
  • "I sell by weight/volume" → Weighted
  • "It has an expiry date" → Batch
  • "Each item has a serial number" → Serialized
  • "I just want to list it (no stock tracking)" → Catalog Only

This single design handles a fruit seller, a laptop shop, a restaurant, AND a grocery store — all within one system, no microservices needed.

Want me to start designing the database schema and Laravel models for this unified product/inventory system?