All work

The in-house pharmacy of Lady Rafat Medical Centre, Karachi. 2025 to 2026

Point of sale and stock control for a clinic pharmacy

The pharmacy kept its stock in a 56-sheet Excel workbook, and nothing tied sales to supplier deliveries, returns or what customers owed. I built a Laravel 12 system around a sales counter run from the keyboard, with an 80mm thermal receipt, purchases and returns that move stock by fixed rules, and pay-later accounts for named customers.

Sheets in the Excel workbook the stock lived in
56
Thermal receipt that prints itself
80mm
Return window, with super-admin sign-off
30 days

How the pharmacy system works

The problem

Fifty-six sheets, and nothing joined up

The pharmacy kept its stock in one Excel workbook with 56 sheets. Nothing tied a sale to the supplier delivery that stocked it, to a return, or to the balance a customer owed.

Step one

Moving the stock across

I wrote an analyser to study the packing formats in the workbook, then a template importer. It finds the header row by itself, matches columns by name so their order does not matter, and has a dry-run mode, so an import can be checked before anything is saved. It updates medicines that already exist by title, creates missing companies and categories, and retries when a generated code is already taken.

Every item is stocked and priced per selling unit, such as a tablet, a bottle or a packet, with 33 unit types to choose from.

Step two

A counter run from the keyboard

Cashiers press F2 to search by name or code, move around the cart with the arrow keys, save with Ctrl+S and cancel with Esc. They take cash, card or bank transfer, or put the sale on pay-later against a named customer.

The browser will not add an out-of-stock item or sell more than is on the shelf, and the server checks each item’s stock again. The receipt is laid out for an 80mm thermal roll and prints by itself.

Step three

Stock moves by fixed rules

A sale takes stock off the shelf. A supplier purchase can be edited and saved again without counting stock twice: each save reverses the purchase’s earlier lines, then applies the new ones and sets the retail price at an 18% markup. Once the supplier is paid, the purchase is locked.

Returns must come within 30 days, cannot exceed what was sold, and run inside database transactions. A cashier raises a return, only a super-admin can approve and complete it, and only then does the stock go back.

The result

What is owed, and what sold

Every customer’s page shows what they owe on pay-later sales, and a debt can be marked paid with the method used. The dashboard charts sales and revenue over the last seven days and shows what is low or out of stock. The sales, inventory and staff reports export to Excel and PDF.

How it fits together

How stock moves

  • A sale is savedEach item comes off the shelf after the browser, then the server, checks its stock
  • A sale is deletedIts items go back on the shelf
  • A purchase is savedIts earlier lines are reversed and the new ones applied, so saving again never counts stock twice. Retail is set at an 18% markup
  • A purchase is deletedIts stock comes back out
  • The supplier is paidThe purchase is locked against edits
  • A return is completedOnly after a super-admin approves it, within 30 days of the sale and never for more than was sold

Who can do what

Cashier

  • Sells at the terminal and prints the receipt
  • Adds customers, including from the terminal
  • Raises returns, but cannot approve them

Super-admin

  • Approves, completes or rejects returns
  • Manages users and their roles
  • Runs the reports and exports them

The work

Built for
The in-house pharmacy of Lady Rafat Medical Centre in Karachi, Pakistan
When
June to August 2025, with two small fixes in 2026
My part
All of it, on my own: the importers, sales terminal, receipt, stock rules, returns, customer accounts, dashboard and reports
  • Laravel
  • PHP
  • MySQL
  • jQuery
  • Bootstrap
  • Chart.js
  • DataTables
  • Spatie Permission
  • Laravel Excel
  • DomPDF