Point of sale · Inventory · Clinical

Run the whole pharmacy.
Trust what it tells you.. Never lose a sale offline.. Sell the oldest box first.

PharmaNex is the counter, the stockroom and the clinical desk in one console — offline-capable at the till, exact about which batch left the shelf, and explicit about the limits of what it can verify.

PKR
Tenant currency, en-PK grouping, Asia/Karachi clocks
Row-level security
Per-pharmacy isolation enforced in Postgres
Offline outbox
Sales queue locally and replay idempotently
NIH + FDA
RxNorm and openFDA, quoted and attributed

Till 1 — Main counter

Interactive demo · sample data

The date shown is the earliest sellable expiry — the batch the next sale comes out of. Allocation is FEFO and happens server-side, so two tills cannot both claim the last box.

Current sale

Panadol 500mg

2 × Rs 120

Rs 240
TotalRs 240

Sent straight through. The batch is allocated FEFO on the server, so the receipt records the box that actually left the shelf.

The counter

The till keeps working when the network doesn’t.

A pharmacy does not close because the connection dropped. The hard part is not staying on screen — it is making sure the sale that happened during the outage is still true afterwards, in the ledger, against the right batch, in the right hour.

Sales survive the outage

The customer paid and walked out with the box, so the record has to exist. A sale rung with the network down is held locally, with the id it was rung under and the minute it happened. Replay is a plain retry — idempotent, so a timeout that lands after the server already committed cannot bill twice — and it books into the hour it was sold, not the hour it synced.

FEFO, decided at the server

A register cannot see the other tills, so it never picks a batch. Allocation runs server-side when the sale lands, oldest sellable expiry first. A line split across two batches becomes two rows in the ledger — the receipt still shows one line, but a recall needs to know which physical box left the shelf.

Scan what is actually in your hand

A carton barcode and a bottle barcode are different codes for the same product. The till prefills the quantity from the pack level that was read, and prefills nothing at all when the code has not been tagged yet — a guess in that position is a stock count that quietly stops matching the shelf.

Clinical checks

It tells you when it couldn’t check.

The NLM retired the RxNav drug-interaction API at the start of 2024. It returns 404 now. Any checker written as if (!res.ok) return [] has been answering “no interactions found” ever since — which converts an outage into a clean bill of health at the exact moment a pharmacist is deciding whether to hand over two drugs together.

What it does

Each drug is resolved to its ingredients through RxNorm. The Drug Interactions section of each drug’s FDA label is then read from openFDA, and the system reports where one drug’s label names the other’s ingredient — quoting the label’s own wording and attributing it.

Every response carries an explicit status. Nothing returns an empty result to mean failure, because “we checked and found nothing” and “we could not check” are not the same answer.

What it is not

  • Not severity-graded. Labels do not grade interactions, and inventing a severity would be worse than offering none.
  • Not exhaustive. A label may omit an interaction that another source lists.
  • Not a replacement for a curated database such as Micromedex or DrugBank.

Those three sentences travel with the response itself, so no screen can present the result as more than it is.

Platform

The parts you only notice when they are wrong.

None of these sell a demo. All of them are the difference between software that works for a month and software a pharmacy can still trust in year three.

Tenant isolation in the database

Every query runs inside a transaction that sets the tenant with SET LOCAL, so the value reverts on commit and cannot leak onto the next request that borrows that pooled connection.

Money is never a float

Amounts stay numeric(14,2) and come out of Postgres as strings. The conversion happens once, at the display boundary, where precision no longer matters.

Deliveries and prescriptions by OCR

Supplier delivery notes and uploaded prescriptions are read into structured lines. A person confirms them before any stock moves or anything is dispensed.

Roles that are actually enforced

The console hides what you cannot use, and the API independently re-checks every request. A redirect is an affordance; the 403 is the control.

An audit trail

Who changed a price, who reversed a sale, who edited a batch — recorded, with the tenant it happened in, and readable from the console.

A storefront on the same stock

Customers order online against the same inventory the counter sells from. Light-themed on purpose: retail is read on a phone, outdoors, in daylight.

Restocking from real movement

Reorder suggestions come from what actually sold and what is close to expiry, not from a reorder level someone typed in once and never revisited.

Labels and receipts that fit the printer

A 50×25mm thermal label sheet and a 76mm receipt, each on its own print path, so printing an invoice never emits a blank page from the label roll.

Open the console.

Fourteen screens, one login: the till, stock and batches, purchasing, prescriptions, online orders, clinical reference, and the reports that come out of all of it.