Skip to content

A medicine isn't a SKU, so the catalog is generic, strength and company before it's a product

A pharmacy counter system whose catalog is modeled on how medicines actually differ (generic, strength and manufacturer as separate axes), so when a brand is out of stock the counter can find an equivalent instead of turning the customer away.

Worklist

Everyone the dispensary owes something to this morning, in the order they came in

All statusesGeneric, brand, pack or Rx numberThu 17 Sep 2026
Waiting in shop4at the counter now
Owed a line3owings to fill
Ready2bagged
Collecting later2today
Fridge lines2store cold
CD cabinet2controlled drugs

Prescriptions in

11 open · by status, then time in
PatientFirst itemWhere it isStorageIn
Mrs J. OkaforRX-60418 · 2 itemsOmeprazole 20mg GR capsules · 28+ 1 moreWaiting in shopOut of stock · equivalents shown–09:12
Mr D. HartleyRX-60421 · 2 itemsMorphine sulfate 10mg/5ml oral solution · 100ml+ 1 moreWaiting in shopSecond checkCD09:18
Ms P. LindqvistRX-60423 · 1 itemInsulin aspart 100 units/ml pre-filled pen · 5Single itemWaiting in shopLabellingFridge09:24
Mr K. AddoRX-60425 · 4 itemsRamipril 5mg capsules · 28+ 3 moreWaiting in shopPicking–09:31
Mrs E. WhitcombeRX-60402 · 2 itemsLatanoprost 50mcg/ml eye drops · 2.5ml+ 1 moreOwed a lineOwed 1 line · due FriFridgeTue
Mr S. BhattRX-60397 · 3 itemsSertraline 50mg tablets · 28+ 2 moreOwed a lineOwed 1 line · due today 14:00–Mon
Miss R. CoyleRX-60410 · 1 itemSalbutamol 100mcg/dose inhaler · 200 dosesSingle itemOwed a lineOwed 1 line · wholesaler short–Wed
Mr A. FerreiraRX-60414 · 2 itemsOxycodone 5mg capsules · 56+ 1 moreReadyBagged · CD cabinetCD08:55
Mrs H. DoyleRX-60416 · 5 itemsMetformin 500mg tablets · 84+ 4 moreReadyBagged · shelf B3–09:02
Mr T. NakamuraRX-60419 · 2 itemsAmlodipine 5mg tablets · 28+ 1 moreCollecting laterCollecting after 16:00–09:15
Mrs L. BaptisteRX-60420 · 1 itemAtorvastatin 20mg tablets · 28Single itemCollecting laterDelivery round 2–09:16

Fridge & CD cabinet

4 prescriptions
Mr D. HartleyMorphine sulfate 10mg/5ml oral solution · 100mlCD
Ms P. LindqvistInsulin aspart 100 units/ml pre-filled pen · 5Fridge
Mrs E. WhitcombeLatanoprost 50mcg/ml eye drops · 2.5mlFridge
Mr A. FerreiraOxycodone 5mg capsules · 56CD

Owed a line

3 owings
Mrs E. WhitcombeLatanoprost eye dropsdue FriOwing
Mr S. BhattSertraline 50mg tabletsdue today 14:00Owing
Miss R. CoyleSalbutamol inhalerwholesaler shortOwing
Owings clear from delivery booking-in, line by line.

What the engagement involved

Industry
Healthcare & Dental Practices
Duration
16 weeks
Cooperation model
Dedicated team
Services
Platform engineeringCatalogue modellingBack office
Integrations
Barcode label printingReceipt printingSMS notificationsAccounting exportScheduled backups
Technologies
LaravelMySQLBladejQueryBootstrap
Team
1 Engagement lead2 Backend engineers1 Frontend engineer1 QA engineer

Client name withheld under NDA. Engagement details are shown to the extent our agreement permits.

The problem

The hard problem

Their previous system treated every medicine as a product with a name. Paracetamol 500mg from one manufacturer and paracetamol 500mg from another were unrelated rows, so a search for one returned nothing when the other was on the shelf. Staff kept the equivalences in their heads, and locum staff didn't have them.

Paracetamol 500mg from one manufacturer and the same from another were unrelated rows, so a search for one returned nothing while the other sat in the drawer. Regular staff bridged that from memory, which meant the business didn't actually possess the knowledge. Locum cover exposed it immediately, and out of stock became a dead end instead of a substitution.

Model the axes separately. A product is a generic at a strength from a company, so "what else is this" becomes a query instead of a memory. Out of stock stops being a dead end: the counter sees the alternatives on the shelf, with their prices.

Introduction

The system we were asked to build

The pharmacy chain runs community pharmacies where the counter question is rarely "do you have this box" and usually "do you have something equivalent." We built the system around that: a catalog split into generic, strength and manufacturer, with purchasing, dispensing and payments on top.

A community pharmacy chain where the counter question is rarely "do you have this box" and almost always "do you have something equivalent." Their system treated every medicine as a product with a name, so the equivalences lived in the heads of regular staff. The engagement was commissioned after a run of locum cover during which sales were lost on stock that was physically on the shelf.

Full-Stack Engineering

How the pieces fit

  1. 01

    Split generic, strength and manufacturer into their own dimensions, each queryable on its own

    Generic, strength and manufacturer are three separate dimensions, not components of a product name, which is what makes equivalence an indexed query.

  2. 02

    Made substitution a query over those dimensions instead of a maintained equivalence list

    Substitution derives from those dimensions, with no maintained list, so it can't go stale as the catalog changes.

  3. 03

    Kept purchase and dispensing against the same product rows, so stock is a derived figure

    Making stock derived removed the adjustment screen entirely. It was the change staff objected to most, and they stopped mentioning it within two weeks.

  4. 04

    Recorded payment type on the order, because part-cash part-card is normal at a counter

    Payments are typed records with several allowed per order, because part cash and part card is routine at a counter.

  5. 05

    Gave locum staff the same answers as regulars by putting the equivalences in the data

    The equivalences live in the data instead of in staff memory, so a locum gets the same answers a regular would have given.

Generic, strength, company

Three separate axes under every product name, which is what makes an equivalence a query.

A product is modeled as three separate things: a generic, a strength and a manufacturer. None of them is buried inside a name. Once the axes are separate, "what else is this medicine" becomes an indexed query instead of something the person at the counter has to know. Packs and units hang off that, so the same medicine in two pack sizes is one equivalence, not two products.

What shipped
  • Generic, strength and manufacturer as three separate axes
  • Equivalence becomes a query, not counter knowledge
  • Two pack sizes of one medicine remain one equivalence
Catalogue

Browse the way a medicine is shaped: generic, then strength and form, then every interchangeable pack

New packGeneric, brand, pack or Rx numberThu 17 Sep 2026
Omeprazole20mg gastro-resistant capsulesany companyThe third column is not a list anyone keeps: it is every pack sharing the first two axes.3 catalogue axes0 equivalence lists

1Generic

14 shown
Filter generics
Amlodipine3 · 9 packs
Atorvastatin4 · 11 packs
Cetirizine hydrochloride2 · 7 packs
Esomeprazole3 · 6 packs
Ibuprofen5 · 14 packs
Lansoprazole3 · 8 packs
Loratadine2 · 6 packs
Metformin hydrochloride3 · 10 packs
Omeprazole5 · 13 packs
Paracetamol6 · 17 packs
Ramipril4 · 12 packs
Salbutamol3 · 7 packs
Sertraline2 · 8 packs
Simvastatin4 · 10 packs

2Strength & form

Omeprazole
10mggastro-resistant capsules2 packs · 4 on shelf
20mggastro-resistant capsules4 packs · 20 on shelf
40mggastro-resistant capsules3 packs · 12 on shelf
20mggastro-resistant tablets2 packs · 9 on shelf
10mgdispersible gastro-resistant tablets2 packs · 2 on shelf
Why 20mg tablets are a separate rowStrength and form are both part of what a medicine is. A 20mg capsule and a 20mg tablet of omeprazole share a generic and a strength, and still never appear as each other’s equivalent.

3Interchangeable packs

4 packs · 20 on shelf
Company · packPriceOn shelf
Gastrelle · Harwick Pharma28 capsules · PK-10442£6.25Out of stock
Tay Valley Labs28 capsules · PK-10451£4.6011 packs
Selbourne Generics28 capsules · PK-10447£4.956 packs
Ashby Laboratories56 capsules · PK-10458£8.403 packs
Two pack sizesAshby’s 56 and everyone’s 28 are one equivalence, not two products. The pack size hangs off the product.
A new company’s packEnter its generic, strength and form once, and it appears here and at the counter. Nothing else to update.
On screen

Browsing the catalog on its axes: choose a generic, then a strength and form, and every interchangeable pack falls out in the third column, two pack sizes included, with no equivalence list behind it.

RX-60418 · Mrs J. Okafor

Private prescription · 2 items · waiting in shop since 09:12

Waiting in shopGeneric, brand, pack or Rx numberThu 17 Sep 2026
Item 1 of 2 · as writtenGastrelle 20mg gastro-resistant capsules · 28Omeprazole20mg gastro-resistant capsulesHarwick Pharma£6.25
Out of stock · 0 on shelf3 equivalents on the shelf now

Same generic, same strength, same form

Offered, never applied
Company · packMatches onPriceOn shelf
Tay Valley LabsOmeprazole 20mg gastro-resistant capsules · 28GenericStrengthForm£4.6011Offered
Selbourne GenericsOmeprazole 20mg gastro-resistant capsules · 28GenericStrengthForm£4.956Offer
Ashby LaboratoriesOmeprazole 20mg gastro-resistant capsules · 56GenericStrengthForm£8.403Offer
Nothing changes on the prescription until the pharmacist accepts an equivalent.

Same generic, not offered

Different strength or form
Omeprazole 20mg gastro-resistant tablets · 28 tabletsCorran Medical · 9 on shelfDifferent form
Omeprazole 40mg gastro-resistant capsules · 28 capsulesTay Valley Labs · 7 on shelfDifferent strength
Omeprazole 10mg gastro-resistant capsules · 28 capsulesSelbourne Generics · 4 on shelfDifferent strength

The pharmacist decides

Offered, not applied
Offered in place of GastrelleTay Valley LabsOmeprazole 20mg gastro-resistant capsules · 28£4.60 · 11 on shelf
Patient askedHappy with another company’s pack
Accepted by Owen PrycePharmacist · 09:21
Label printed for the equivalentDispensed from Tay Valley stock
Choice recorded on the patientOmeprazole 20mg capsules: no company preferenceNext month’s repeat opens with this answer, so nobody asks again.
Print label · continue

Substitution at the counter

On screen

An out-of-stock brand resolving to equivalents with the same generic, strength and form, each with its price and shelf count; other strengths and forms shown but not offered, and the pharmacist's decision recorded on the patient.

An out-of-stock line shows what else on the shelf is the same medicine, with price and quantity.

An out-of-stock line stops being a dead end: the counter immediately sees the same generic at the same strength from other manufacturers, with the price and the quantity actually on the shelf. The substitution is offered, never applied (the pharmacist decides), and the choice is recorded so a customer who prefers one brand isn't asked again next month.

What shipped
  • Alternatives shown with real shelf price and quantity
  • Offered, never applied: the pharmacist decides
  • The choice recorded, so a preference isn't asked twice

Stock is derived

Purchases and dispensing write to the same product rows, so the figure on screen is a sum nobody can adjust.

Purchases and dispensing write to the same product rows, so the stock figure on screen is a sum of movements that nobody can type over. That removes the whole category of drift where an adjustment was made to make a screen agree with a shelf and the reason was never recorded. A discrepancy here is an event you can point at.

What shipped
  • Stock derived from movements, never directly editable
  • Purchases and dispensing write the same rows
  • Every discrepancy traces to a specific event
Booking in · Denholm Wholesale

DN-448213 against PO-0917-01 · arrived 08:36 · booked in line by line

Finish booking inGeneric, brand, pack or Rx numberThu 17 Sep 2026
Denholm WholesaleDN-448213 · 2 totesLines12In full9Short2Not sent1Received at cost£149.30

Delivery lines

Received is counted, not typed from the note
PackCompanyOrd.Recd.LineShelf
Amlodipine 5mg tablets · 28Selbourne Generics1010In full+10
Atorvastatin 20mg tablets · 28Corran Medical1212In full+12
Cetirizine 10mg tablets · 30Tay Valley Labs66In full+6
Insulin aspart 100 units/ml pen · 5FridgeFerris & Lowe22In full+2
Latanoprost 50mcg/ml eye drops · 2.5mlFridgeAshby Laboratories42Short+2
Metformin 500mg tablets · 84Selbourne Generics88In full+8
Omeprazole 20mg GR capsules · 28Tay Valley Labs1010In full+10
Omeprazole 20mg GR capsules · 28Harwick Pharma60Not sentnone
Oxycodone 5mg capsules · 56CDCorran Medical22In full+2
Ramipril 5mg capsules · 28Tay Valley Labs1010In full+10
Salbutamol 100mcg/dose inhalerAshby Laboratories127Short+7
Sertraline 50mg tablets · 28Selbourne Generics66In full+6
Each received line writes one intake movement against the product rowPO-0917-01

Credit request

CR-2026-0917-03
Latanoprost 50mcg/ml eye drops · 2.5ml2 × £1.86 · short£3.72
Omeprazole 20mg GR capsules · 286 × £2.12 · not sent£12.72
Salbutamol 100mcg/dose inhaler5 × £1.50 · short£7.50
Credit to claim£23.94
Raise creditRe-order short

Stock after this line

A sum, not a field
Omeprazole 20mg GR capsules · 28Tay Valley Labs
Before this delivery1Intake · DN-448213+10On the shelf11
There is no adjustment screen. A gap between shelf and screen is a movement you can point at.
On screen

A wholesaler delivery booked in line by line: two lines short and one never sent, the credit raised from the same screen, and each received line written as a movement so the shelf figure is a sum.

ORD-2026-091744 · Mrs J. Okafor

Register 2 · 2 prescription items and 3 counter lines · prices include VAT where it applies

Paid in fullGeneric, brand, pack or Rx numberThu 17 Sep 2026

Order

5 lines
ItemQtyEachLine
Omeprazole 20mg gastro-resistant capsules · 28RxEquivalentPrivate prescription · Tay Valley Labs, in place of Gastrelle1£4.60£4.60
Amlodipine 5mg tablets · 28RxPrivate prescription · Selbourne Generics1£4.20£4.20
Cetirizine hydrochloride 10mg tablets · 30Pharmacy counter · Tay Valley Labs1£2.49£2.49
Paracetamol 500mg tablets · 32Pharmacy counter · Corran Medical2£0.95£1.90
Ibuprofen 200mg tablets · 24Pharmacy counter · Ashby Laboratories1£1.60£1.60
Order total£14.79

Tender records

Any number per order
RecordTypeDetailApplied
TND-88121 CardContactless · Visa ending 2281 · approved 09:26£10.00
TND-88122 CashHanded £5.00 · change £0.21£4.79
Two records on one order. No second invoice for the remainder.Balance £0.00

Take payment

Till 2
Total due£14.79Card £10.00Cash £4.79
CardContactless · approved£10.00Taken
CashHanded £5.00 · change £0.21£4.79Taken
+ Add another tender
Remaining£0.00The order closes when its tender records sum to the total, however many there are.
Print receiptEmail
On screen

Part card, part cash: one order carrying two tender records, each with its own type, the change on the cash record, and the order closing when the records sum to the total.

Split tenders

Payments are records with a type, so part cash and part card is the normal path.

Payments are records with a type, so an invoice can carry cash and card together as two entries, with no single tender and no remainder handled as a workaround. Split tenders are ordinary here, which matters at a counter where part-cash is routine and the previous system was being defeated with a second invoice.

What shipped
  • Payments are typed records, several per invoice
  • Part cash and part card is the normal path
  • No second invoice needed to represent a split

Reports by generic

Buying decisions come from what was dispensed, whichever manufacturer happened to be stocked.

Reporting aggregates by generic instead of by manufacturer, so a buying decision reflects what was actually dispensed, whichever brand happened to be stocked when demand arrived. That inverts the previous cycle, where stocking a brand made it look popular and popularity justified stocking it again.

What shipped
  • Aggregated by generic, not by whichever brand was stocked
  • Buying driven by dispensed demand
  • Breaks the stock-it-so-it-sells feedback loop
Dispensed by generic

24 Aug – 20 Sep 2026 · four weeks · Castle Street

Export CSVGeneric, brand, pack or Rx numberThu 17 Sep 2026
Group by genericGroup by companyGroup by packA row is a generic at one strength and form, summed across every company that supplied it.912 packs ·72 via an equivalent

Packs dispensed

Wk 1 = w/c 24 Aug · packs across every company
Generic · strength & formWk 1Wk 2Wk 3Wk 4Four weeksCos.Equiv.
Omeprazole20mg gastro-resistant capsules41384429152423
Atorvastatin20mg tablets3639352713736
Amlodipine5mg tablets3331342412239
Ramipril5mg capsules2830272110624
Metformin hydrochloride500mg tablets262529199933
Sertraline50mg tablets192220157627
Salbutamol100mcg/dose inhaler1715211669212
Cetirizine hydrochloride10mg tablets221814106432
Lansoprazole30mg gastro-resistant capsules12141194625
Simvastatin40mg tablets11101284121
All ten rows24524224717891272

The same row, by box

152 packs
Harwick Pharma (Gastrelle)105
Tay Valley Labs24
Selbourne Generics14
Ashby Laboratories9
By box, Gastrelle looks like the demand. By generic, the demand is omeprazole 20mg capsules, whoever makes them.

What buying reads

Next wholesaler order
Order onGeneric, strength & formPick company byCost and availabilityNot onWhichever brand was stocked
Stocking a brand no longer makes it look popular: its sales count toward the generic it belongs to.
On screen

Four weeks grouped by generic instead of by box, with how often an equivalent was reached for, beside the same omeprazole row split by company to show what a by-box report would have said.

Process

Phase by phase

  1. Phase 1: The Catalogue

    Three Axes, Not One Name

    Modeled generic, strength, company, category and unit as separate entities. A product is the intersection, which is what makes substitution answerable without maintaining a second list.

    • Generic & Strength
    • Company
    • Product Model
  2. Phase 2: Purchasing

    Suppliers And Intake

    Built purchase orders and intake against the same product rows the counter sells from, so stock is derived from movements, never kept as a number somebody adjusts.

    • Suppliers
    • Purchase Orders
    • Intake
  3. Phase 3: The Counter

    Substitution In The Flow

    Built dispensing so that an out-of-stock line offers the equivalents immediately (same generic, same strength, different company) with each one's price and quantity on the shelf.

    • Dispense Flow
    • Substitution Panel
    • Stock Display
  4. Phase 4: Payment

    Split Tenders

    Built order payments as their own records with a payment type, because a counter regularly takes part cash and part card, and a single payment field turns that into a workaround.

    • Payment Types
    • Split Payment
    • Receipts
  5. Phase 5: Reporting

    By Generic, Not By Box

    Built reporting that groups by generic, so buying decisions follow what was actually dispensed instead of which manufacturer happened to be in stock.

    • Sales By Generic
    • Stock Reports
    • Supplier Reports
Stock · Omeprazole 20mg gastro-resistant capsules · 28

Tay Valley Labs · PK-10451 · every figure below is a movement

No adjustment screenGeneric, brand, pack or Rx numberThu 17 Sep 2026
Omeprazole20mg gastro-resistant capsulesTay Valley LabsPurchases and dispensing write to this same row. The shelf figure is their sum; nobody can type over it.On the shelf11sum of 10 movements

Movements

1 Sep – 17 Sep 2026
WhenMovementReferenceByQtyShelf
01 Sep 08:40IntakeDN-445902 · DenholmA. Rahman+1010
03 Sep 11:02DispensedRX-59644A. Rahman−28
05 Sep 15:27DispensedRX-59781L. Moss−17
08 Sep 09:15IntakeDN-446870 · DenholmL. Moss+613
09 Sep 10:48DispensedRX-59930A. Rahman−310
10 Sep 16:05ReturnedDamaged pack · to DenholmO. Pryce−19
12 Sep 12:31DispensedRX-60114L. Moss−45
15 Sep 09:58DispensedRX-60250A. Rahman−23
16 Sep 14:12DispensedRX-60344A. Rahman−21
17 Sep 08:36IntakeDN-448213 · DenholmA. Rahman+1011
Sum of movements11

Same generic, strength & form

20 on shelf
Gastrelle · Harwick Pharma28 capsules0
Tay Valley Labs28 capsules11
Selbourne Generics28 capsules6
Ashby Laboratories56 capsules3

A discrepancy is an event

Stock check · 10 Sep
Counted 9, screen said 10Traced to a damaged pack set aside on 10 Sep, recorded as a return to the wholesaler by Owen Pryce.
OPThe figure moved because a movement was written, with a person, a time and a reason. There is no other way to move it.
Open 10 Sep movement
On screen

One pack's stock as its movements: intakes, dispensings and a returned damaged pack summing to the shelf figure, its interchangeable siblings beside it, and a stock-check discrepancy traced to the event that caused it.

What it carries now

3

Catalogue axes

0

Equivalence lists maintained

None

Out-of-stock dead ends

Any

Tenders per order

Catalog axes is a count. Equivalence lists maintained is zero: equivalence is derived from the dimensions, never curated. Out-of-stock dead ends is none, since alternatives are shown wherever they exist. Tenders per order is "any," which describes the payment model and isn't a measured figure.

Client name withheld under NDA. Figures are approximate, drawn from the engagement’s own reporting.

What the architecture settled

  1. 01

    If the domain has axes, model the axes. Folding them into a product name is what makes obvious questions unanswerable.

    When a domain genuinely has axes, folding them into a name makes the obvious questions unanswerable, and the questions people ask at a counter are the obvious ones.

  2. 02

    An equivalence you maintain as a list goes stale; one you derive from dimensions can't.

    A maintained equivalence list goes stale the first month nobody updates it; one derived from the dimensions is correct by construction.

  3. 03

    Knowledge held in regular staff's heads is knowledge the business doesn't have. Locum cover exposes that immediately.

    The chain measured it during a locum week: sales lost on stock physically present, which is the clearest possible statement of who actually held the catalogue.

  4. 04

    A single payment field is a bet that nobody pays two ways. At a counter, that bet loses daily.

    One payment field bets that nobody pays two ways, and at a pharmacy counter that bet loses daily and is defeated by staff raising a second invoice.

Ways of working

How the work was run

  1. 01

    The superintendent pharmacist reviewed the catalog model before a line of it was built, and rejected the first version: it had strength as a string on the product instead of its own entity, which would have made "anything at this strength" unanswerable. That correction shaped everything after it.

    A dedicated team for sixteen weeks, with the three-axis catalog modeled and migrated before any counter work, because substitution is a property of the model and not a feature on top of it. The superintendent pharmacist reviewed the substitution rules directly: an offered equivalence is a clinical suggestion, not a merchandising one.

One out-of-stock brand, followed to the register

The box is gone. The medicine is still on the shelf.

Choose an out-of-stock brand and step through what the counter does with it: resolve it to a generic, a strength and a form, see which packs share all three and why the others are excluded, then take the sale in as many tenders as the customer wants. Switch tabs, or use the arrow keys once one is focused.

Out of stock

The request names a brand from one company, and that pack is out of stock.

As written at the counterGastrelle 20mg gastro-resistant capsulesHarwick Pharma · 28 capsules · £6.25 Out of stock · 0 on the shelf
What the old catalogue could sayEvery medicine was a product with a name, so “Gastrelle” matched only itself. The search came back empty while the same medicine from another company sat on the shelf, and only regular staff knew to look.Out of stock was a dead end.

Why nobody keeps a list: equivalence is derived from the axes every pack already has, so a new company’s pack is interchangeable the moment it is entered. Brands, companies, prices and shelf counts here are illustrative.

Architecture

From a line at the counter to an equivalent on the shelf

The three-axis catalog was modeled and migrated before any counter work, because substitution is a property of the model and not a feature on top of it. Everything downstream reads the same product rows.

  1. 01 · Trigger
    A counter line or a delivery lineDispensing and wholesaler intake are both recorded against a product row, never against a name typed at the register.
  2. 02 · Ingestion
    Laravel purchase & dispense flowsPurchases and dispensing write to the same product rows, so stock is derived from movements and never kept as a number.
  3. 03 · Engine
    Substitution as a queryEquivalents are an indexed query over the catalog's dimensions, not a maintained list, so they can't go stale as the catalog changes.
  4. 04 · State
    MySQL: products, movements, paymentsGeneric, strength, company, category and unit are separate entities; payments are typed records, several allowed per order.
  5. 05 · Delivery
    Blade counter panel & reportsAlternatives are offered with price and shelf quantity, never applied; reports aggregate by generic, not by manufacturer.

What the counter can't get wrong

Strength, storage & shortages

A different strength or form is never offered

An equivalent must share the generic, the strength and the form. Other strengths and forms of the same generic are shown as not offered, and any substitution is only offered: the pharmacist decides, and the choice is recorded.

Fridge and CD items are flagged on the worklist

The dispenser's worklist marks which prescriptions need the fridge and which need the controlled drugs cabinet, beside who is waiting and who is owed a line, so neither is found by reading the label.

A shortage is a line, not a silent gap

Wholesaler deliveries are booked in line by line, so a short or never-sent line is visible where it was found and the credit is raised from that screen. Stock is derived from movements, so every discrepancy traces to an event.

Is your catalogue a list of names when the counter needs to know what else is the same? Scope your build in 3 minutes.

Scope your build
Have a project?

Let's talk

Running a large platform, shaping a first MVP, or getting a product ready for a funding round? Tell us where you are. We'll shape the process around it, and stay with you after launch.