40% off everything — use code SAVE40 at checkout · ends in …
Skip to content
phpguru.store

Customize a PHP Pharmacy Billing System

By Prakash Panthi, Founder · Published September 6, 2026 · Updated September 15, 2026

A pharmacy billing system that works fine for a generic retail shop usually falls short for an actual pharmacy the moment real medicine inventory shows up — batches expire, drug schedules carry legal record-keeping rules, and a GST invoice has requirements a plain sales receipt doesn't. Here's what most pharmacies actually need customized, and how each piece fits into an existing PHP/MySQL billing codebase.

1. GST-compliant invoice fields

Under GST Rule 46, a valid tax invoice needs a defined set of fields — GSTIN, a serial invoice number, HSN code, taxable value, and the tax breakup, among others. For pharmacies specifically, most medicines fall under HSN code 3004 (packaged medicaments), with 3003 and 3006 covering some bulk/other categories. Since January 2024, HSN-wise summaries are required in GSTR-1 reporting regardless of turnover, so this isn't optional even for smaller pharmacies. If your billing system's invoice template doesn't already have a dedicated HSN field per line item, that's usually the first customization worth doing — missing or incorrect invoice details can cause the buyer's input tax credit to be denied, which is a real business problem for pharmacies billing other businesses.

2. Batch number and expiry date tracking

Batch and expiry tracking isn't a GST requirement — it comes from the Drugs and Cosmetics Act, and it's arguably the single most important customization a generic billing system needs before it's fit for a pharmacy. The clean way to add it without disrupting an existing schema:

  • Keep your existing medicines table as the master record (name, manufacturer, category, base pricing).
  • Add a new batches table: batch_no, medicine_id (foreign key), expiry_date, quantity_on_hand, purchase_price, mrp, supplier_id.
  • Never store expiry on the medicine row itself — a single medicine routinely has multiple batches in stock at once with different expiry dates, and collapsing that onto one row is the most common mistake in a first attempt at this feature.

Stock deduction should then follow FEFO — First-Expiry, First-Out — not FIFO. At the point of sale, query that medicine's batches ordered by expiry_date ASC, and deduct the sale quantity across batches in that order until it's fully accounted for. This matters specifically for pharmacies: selling the oldest-received stock first (FIFO) can still leave a shorter-dated batch sitting unsold behind newer stock, where selling by nearest expiry first (FEFO) actually reduces expired-stock write-offs.

3. Schedule H1 register

Certain drug categories (Schedule H, H1, X) carry a legal requirement to maintain a register capturing the drug name (brand and generic), quantity sold, batch number, the patient's name and address, and the prescribing doctor's name and registration number — retained for a minimum of three years from the last entry. A common inspection failure isn't missing data entirely, it's a register that allows silent edits after the fact. If you're customizing this feature, build it to auto-populate directly from the billing transaction (not a separate manual entry step), and make edits to existing entries append a new record rather than overwrite the original — an auditable trail matters as much as the data itself.

4. Barcode/QR scanning at billing

Once batch tracking exists, scanning becomes far more useful — a barcode tied to a specific batch can pull the correct expiry and stock line directly, instead of a cashier manually selecting from a list of batches for the same medicine. This is usually a straightforward addition once the batch table exists; it's a much bigger job if you try to bolt it onto a schema that has no batch concept yet.

5. Multi-unit pricing

Pharmacies routinely sell the same medicine as a full box, a strip, or a single loose tablet, each at a different effective price. If your base system only tracks one price per medicine, this needs a small pricing table keyed by unit type per medicine, with the billing screen deducting stock in the correct base unit regardless of which unit was sold.

6. Low-stock and expiry alerts

With a batch table in place, two useful alert queries become easy to add: stock below a reorder threshold, and batches approaching expiry — commonly flagged at 90/60/30 days out so there's time to run a distributor return or a clearance sale before the stock actually expires.

FAQ

Do I need all of these customizations, or just some?

GST invoice fields and the Schedule H1 register (if you stock scheduled drugs) are the two with real legal weight — prioritize those. Batch/expiry tracking is close behind since it protects against real financial loss from expired stock. Barcode scanning and multi-unit pricing are genuine convenience upgrades, worth adding once the data model supports them.

Can these be added without touching the core billing logic?

Mostly yes — batch tracking, alerts, and the H1 register are additive: new tables and new screens that reference existing medicine and sale records, rather than rewrites of the core billing flow. The one place that does need a real logic change is stock deduction, which has to move from "reduce this medicine's quantity" to "reduce quantity from the earliest- expiring batch first."

Is FEFO more complex to implement than FIFO?

Only slightly — it's the same batch-deduction loop, just ordered by expiry_date instead of received_date. The real work is adding the batch table in the first place; once that exists, switching the sort order is a small change.

Available systems in this category

The system this guide was written for is not available for new purchases right now. These PHPGuru-developed systems cover related needs — check each page for exactly what it includes.