A 6-branch pharmacy chain in Nagpur ran three different off-the-shelf billing tools across 14 months and abandoned all three. The reasons were always the same: Schedule-H drug compliance the software couldn't enforce, batch-and-expiry tracking that broke at branch transfers, and stock counts that disagreed between branches by Friday. We built them a custom inventory-plus-billing app in 9 weeks. This is the build-versus-buy story, the QA we ran, and the specific failures that made "buy" the wrong answer.
6
Branches on one live stock ledger
3
Off-the-shelf tools tried and dropped
₹0
Expired-stock dispenses post-launch (90 days)
## The Answer in 60 Words
Off-the-shelf pharmacy software failed this chain on three hard requirements: enforcing Schedule-H prescription capture at the point of sale, tracking batch and expiry through inter-branch transfers, and keeping stock consistent across six locations in near real time. Generic retail billing tools treat medicine like any SKU. We built a custom app on Next.js and PostgreSQL in 9 weeks. Expired-stock dispenses dropped to zero in the first 90 days.
## Why This Matters Now
Indian pharmacies sit under the Drugs and Cosmetics Act, and Schedule-H and H1 drugs legally require a valid prescription record at sale. Drug inspectors check batch-wise records and expiry handling. A generic POS that lets a cashier sell a Schedule-H drug without logging the prescriber isn't just inconvenient — it's a compliance exposure. As chains add branches, the "spreadsheet per branch" approach collapses: stock you think is in Branch 2 was actually transferred to Branch 5 on Tuesday, and now you've sold air. The trigger for this client was a near-miss expiry incident that a manager caught by hand.
The compliance stake, plainly: a drug inspector can ask for batch-wise records and prescription proof for Schedule-H and H1 sales going back months. Software that can't produce a prescriber record per restricted sale, or can't show which batch was dispensed and when, leaves the owner personally exposed under the Drugs and Cosmetics Act. This is not a feature you bolt on later — it has to be enforced at the point of sale from day one.
## The Client (Specific Details)
-
Sector: Retail pharmacy chain (prescription + OTC + FMCG)
-
Location: Nagpur, Maharashtra
-
Size: 6 branches, 31 staff, ~₹19 crore annual turnover
-
Stack on day 0: Tool A (generic retail POS), Tool B (a pharmacy-specific desktop app), Tool C (a cloud billing SaaS) — none talking to each other; stock reconciled in Excel weekly
-
The trigger: A manager caught an about-to-expire batch on a shelf that the software still counted as fresh. The owner gave us a fixed scope and 10 weeks.
## Why Each Off-the-Shelf Tool Failed
💊
Tool A — Generic retail POS
No concept of Schedule-H. A medicine was just a barcode. No prescriber field, no batch-expiry at line level. Cashiers sold restricted drugs with no record. Hard stop.
🖥️
Tool B — Desktop pharmacy app
Handled batch-expiry well — but single-machine. Each branch had its own copy. Inter-branch stock transfers meant manual export-import. No live multi-branch view.
☁️
Tool C — Cloud billing SaaS
Multi-branch and cloud, but its expiry tracking was per-product, not per-batch. Two batches of the same drug with different expiry dates collapsed into one number. Useless for FEFO dispensing.
🔌
The integration tax
No two tools shared a data model. The owner paid three subscriptions and an accountant to reconcile them weekly — and still got Friday stock mismatches.
## Build vs Buy: The Honest Comparison
We don't default to "build." For most retail, off-the-shelf wins. Here's the actual decision table we walked the owner through.
| Dimension | Off-the-shelf | Custom build |
|---|---|---|
| Upfront cost | ₹0–₹40k setup | ₹6L–₹9L one-time |
| Monthly cost | ₹3k–₹12k per branch in subs | ₹3k–₹5k hosting, all branches |
| Schedule-H enforcement | Partial or none | Built to the exact rule |
| Batch + expiry (FEFO) | Per-product at best | Per-batch, enforced at sale |
| Multi-branch live stock | Tool-dependent | Single ledger, real time |
| Time to value | Days | 9 weeks |
| You own the data | No | Yes |
Custom wins when your compliance and operational rules are non-negotiable and no product enforces them. It loses when a ₹10k/month SaaS already does 90% of what you need. This client was firmly in the first camp — three failed tools proved it.
## How We Built It (The Methodology)
1
Shadow a branch for 2 days
2
Model the stock ledger first
3
Build billing around compliance
4
QA every edge before rollout
We started by sitting at the busiest branch's counter for two days. That's where we learned the cashier scans, then asks for the prescription, then bills — so the prescriber field had to slot into that exact rhythm or it'd get skipped. We modelled the stock ledger as an append-only log of movements (receipt, sale, transfer, return, write-off) rather than a mutable "current quantity" — so any branch's stock is a sum, and you can never get a mystery number you can't explain.
## What We Built
1
Per-batch stock ledger
Every unit carries a batch ID and expiry date. The sale screen defaults to FEFO — first-expiry-first-out — and blocks dispensing any batch within 30 days of expiry without a manager override that gets logged.
2
Schedule-H prescription capture
Selling a Schedule-H or H1 drug forces a prescriber name, registration number, and a photo of the prescription before the bill can be saved. No prescription, no sale — enforced server-side, not just hidden in the UI.
3
Inter-branch transfer as a first-class action
Branch 5 requests stock; Branch 2 approves; the units move on the ledger atomically. No export-import, no double-counting. The transfer carries its batch and expiry with it.
4
GST-ready billing
HSN codes per product, correct GST slabs, sequential invoice numbering per branch per financial year. The bill is GST-compliant the moment it prints.
5
Owner dashboard across all 6 branches
Live stock value, near-expiry alerts ranked by rupee value at risk, top sellers, and dead stock — all six branches in one view, no Excel reconciliation.
Verification we ran: the append-only ledger means every stock number is reproducible. During UAT we picked 40 random product-branch pairs, hand-counted the physical shelf, and reconciled against the app. We required an exact match on all 40 before sign-off. Three mismatches on the first pass were all data-entry during migration — none were logic bugs.
## The QA That Mattered (Manvi's Notes)
As
Manvi, who led QA on this build, the riskiest area was never the happy path — it was the edges. We wrote test cases for the ugly cases first: a sale that fails mid-transaction (does stock get decremented anyway?), a transfer approved twice, an expiry-blocked drug sold via override, a return of a batch that's since expired. Each got an automated test plus a manual run on a real device at a real counter. Pharmacy software that's only tested on the happy path will quietly corrupt stock within a week.
## Common Mistakes (When Custom Goes Wrong)
Symptom: "Stock numbers drift after a few weeks." Cause: mutable quantity field updated by multiple code paths. Fix: model stock as an append-only movement ledger; current quantity is always a sum, never a stored mutable value.
Symptom: "Cashiers skip the prescription field." Cause: it's optional in the UI. Fix: enforce it server-side for Schedule-H drugs — the save fails without it.
Symptom: "Expiry alerts are ignored." Cause: a flat list of 400 near-expiry items. Fix: rank by rupee value at risk, so the manager sees the ₹40,000 batch before the ₹12 strip.
Symptom: "Inter-branch transfers double-count." Cause: non-atomic move (deduct here, add there, in two steps). Fix: a single transaction that moves the units, or it doesn't happen at all.
## When Not to Build a Custom Pharmacy App
If you run a single branch and a ₹6k/month pharmacy SaaS already does batch-expiry and Schedule-H capture, buy it — a 9-week custom build is overkill. If you're under ₹3 crore turnover and not adding branches, the subscription math favours off-the-shelf for years. Custom earns its cost when compliance rules are strict, branches are multiplying, and no product on the market enforces your exact workflow. We told this client "buy" would've been our first recommendation — except they'd already proven it failed three times.
## Outcome
In the first 90 days post-launch: zero expired-stock dispenses, Friday stock reconciliation went from a half-day accountant task to a glance at one dashboard, and the owner cancelled three software subscriptions that had cost roughly ₹38,000 a month combined. We saw a similar "one system replaces a tangle of tools" payoff building
Radiant Finance's pipeline, and the same multi-branch inventory discipline shows up in our
FMCG multi-vendor marketplace build. For the diagnostics-sector cousin of this project, see our write-up on a
9-branch pathology lab app.
Build-vs-buy checklist for pharmacy software
- Does it enforce Schedule-H prescription capture server-side?
- Is expiry tracked per batch, not per product?
- Does the sale screen default to FEFO and block near-expiry batches?
- Is stock a single live ledger across all branches?
- Are inter-branch transfers atomic?
- Is billing GST-ready with per-branch sequential numbering?
- Do you own and can you export your data?
## A Note on the Stack
We built on Next.js (Pages Router) with a PostgreSQL backend, deployed on a single mid-tier cloud box for all six branches. We didn't reach for microservices — six branches and 31 staff do not need them, and they'd have tripled the ops burden. Our
web development team ships most SMB line-of-business apps as a well-structured monolith for exactly this reason: it's the cheapest thing to run and the easiest thing to debug at 9 pm when a counter's down.
## FAQ
### Why did off-the-shelf pharmacy software fail this chain?
Three specific gaps: no Schedule-H prescription enforcement at the point of sale, expiry tracked per product instead of per batch, and no live stock view across six branches. Each tool failed at least one of these, and no single product solved all three.
### What does per-batch expiry tracking actually require?
Every unit must carry its own batch ID and expiry date through receipt, sale, transfer, and return. The sale screen defaults to first-expiry-first-out and blocks batches near expiry. Per-product tracking collapses two batches with different dates into one number, which breaks safe dispensing.
### How long did the custom build take?
Nine weeks from kickoff to go-live, against a 10-week fixed scope. That included two days shadowing a live counter, building the stock ledger and billing, GST compliance, the owner dashboard, and a full UAT cycle with hand-counted stock reconciliation.
### When should a pharmacy buy instead of build?
A single branch under about ₹3 crore turnover, where an existing pharmacy SaaS already handles batch-expiry and Schedule-H capture, should buy. The subscription cost stays below a custom build's payback for years. Build wins when compliance is strict, branches multiply, and no product enforces your exact rules.
### How do you keep stock consistent across branches?
We model stock as an append-only ledger of movements rather than a mutable quantity. Any branch's stock is the sum of its movements, so a number is always explainable. Inter-branch transfers move units in a single atomic transaction, which removes double-counting.
### What did the chain save after launch?
Zero expired-stock dispenses in the first 90 days, Friday reconciliation reduced from a half-day accounting task to a dashboard glance, and roughly ₹38,000 a month in cancelled software subscriptions across three tools.
### What stack did you build it on?
Next.js with a PostgreSQL backend on a single cloud server for all six branches — a structured monolith, not microservices. At six branches and 31 staff, a monolith is cheaper to run and faster to debug than a distributed setup.
Off-the-Shelf Not Cutting It for Your Multi-Branch Business?
We build custom inventory, billing, and compliance apps for Indian SMBs with 3–15 branches. Fixed-scope, typically 8–12 weeks, ₹6L–₹12L. We'll tell you honestly if buying beats building. First call is with the engineer who'd lead it.
Book a 20-min Call