06 April 2026 Custom Software, MySQL, Inventory, ERP

Building Centralized Multi-Branch Inventory Tracking Systems in PHP

Multi-Branch Retail Inventory and Warehouse Transfer System PHP MySQL - Safal Bhurtel

Retail and wholesale businesses expanding across Nepal—such as electronics chains, apparel brands, and pharmaceutical distributors—frequently struggle with decentralized inventory tracking. A business with a central distribution hub in Kathmandu and retail outlets in Pokhara, Butwal, and Narayangarh often suffers from stockouts in one branch while excess inventory sits unsold in another. Off-the-shelf software is often too rigid or expensive, making custom PHP/MySQL multi-branch inventory systems an ideal solution.

Strategic Executive Summary

  • Core Insight: When multiple branch cashiers sell items simultaneously, unmanaged database reads cause negative inventory balances. Always use database row-level locking ( SELECT ... FOR UPDATE ) within atomic transactions.
  • Production Quality: Battle-tested engineering techniques designed specifically for Nepal's network infrastructure and business environment.
  • Direct Implementation: Copy-paste ready code architectures with security safeguards against race conditions, data corruption, and unauthorized access.
Table of Contents
  1. 1. Relational Schema for Multi-Branch Inventory
  2. 2. Managing Inter-Branch Stock Transfers Safely
  3. 3. Automated Low-Stock Alerts via SMS & Email

1. Relational Schema for Multi-Branch Inventory

Stock quantities must be isolated per branch rather than stored as a single global attribute on the product table:

schema.sql MySQL 8.0
CREATE TABLE branches (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    branch_name VARCHAR(100) NOT NULL, -- e.g. "Butwal Main Outlet"
    location VARCHAR(150) NOT NULL,
    is_warehouse TINYINT(1) DEFAULT 0
);

CREATE TABLE products (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    sku VARCHAR(50) NOT NULL UNIQUE,
    product_name VARCHAR(200) NOT NULL,
    selling_price DECIMAL(10,2) NOT NULL
);

CREATE TABLE branch_inventory (
    branch_id INT UNSIGNED NOT NULL,
    product_id BIGINT UNSIGNED NOT NULL,
    stock_quantity INT NOT NULL DEFAULT 0,
    reorder_threshold INT NOT NULL DEFAULT 5,
    PRIMARY KEY (branch_id, product_id),
    FOREIGN KEY (branch_id) REFERENCES branches(id),
    FOREIGN KEY (product_id) REFERENCES products(id)
);

2. Managing Inter-Branch Stock Transfers Safely

Transferring goods between branches requires a multi-stage status workflow: PENDING > IN_TRANSIT > RECEIVED.

Lock source branch row for update PHP 8.3
<?php
function executeBranchTransfer(PDO $pdo, int $fromBranch, int $toBranch, int $productId, int $qty): bool {
    $pdo->beginTransaction();
    try {
        // Lock source branch row for update
        $stmt = $pdo->prepare("SELECT stock_quantity FROM branch_inventory 
                               WHERE branch_id = :b AND product_id = :p FOR UPDATE");
        $stmt->execute(['b' => $fromBranch, 'p' => $productId]);
        $currentStock = $stmt->fetchColumn();

        if ($currentStock < $qty) {
            throw new Exception("Insufficient stock at originating branch.");
        }

        // Deduct from source branch
        $deduct = $pdo->prepare("UPDATE branch_inventory SET stock_quantity = stock_quantity - :qty 
                                 WHERE branch_id = :b AND product_id = :p");
        $deduct->execute(['qty' => $qty, 'b' => $fromBranch, 'p' => $productId]);

        // Add to destination branch (or insert if first shipment)
        $add = $pdo->prepare("INSERT INTO branch_inventory (branch_id, product_id, stock_quantity) 
                              VALUES (:b, :p, :qty) 
                              ON DUPLICATE KEY UPDATE stock_quantity = stock_quantity + :qty");
        $add->execute(['qty' => $qty, 'b' => $toBranch, 'p' => $productId]);

        // Record immutable transfer audit log
        $log = $pdo->prepare("INSERT INTO stock_transfer_logs (from_branch, to_branch, product_id, quantity) 
                              VALUES (?, ?, ?, ?)");
        $log->execute([$fromBranch, $toBranch, $productId, $qty]);

        $pdo->commit();
        return true;
    } catch (Exception $e) {
        $pdo->rollBack();
        return false;
    }
}

3. Automated Low-Stock Alerts via SMS & Email

Set up a daily cron job that scans branch_inventory where stock_quantity <= reorder_threshold and dispatches aggregated stock alerts to warehouse procurement officers, preventing lost sales.

Safal Bhurtel

Safal Bhurtel

Full-Stack Web Developer • Butwal, Nepal

Safal Bhurtel has 6+ years of specialized web engineering experience developing custom PHP/MySQL web applications, high-converting WordPress/WooCommerce websites, API payment integrations (eSewa, Khalti, Fonepay), and speed-optimized digital solutions across Nepal.