An HaProduct designer — Hanoi

Case 01 — Pharmacy POS

When a cart row has to carry too much

A pharmacy checkout kept failing. The structure that fixed it came from an unrelated project: ticketing for a children's activity centre.

Role
Product designer
Product
POS & inventory platform sold through ecommerce app stores
Customer
A large pharmacy chain in Southeast Asia
Outcome
Proposed first, rejected, approved after two failed alternatives

The screen

The product was a general retail point of sale: a grid of product tiles filling the left of the screen, a cart panel down the right. For the shops it was built for that is the right shape — a t-shirt is a name, a size, a quantity and a price.

A pharmacy chain licensed it and asked for a pharmacy version. Two pharmacists work a shift and serve customers directly. They scan a barcode or type a code. They never browse tiles.

The problem

A normal order is three or four items. A patient being treated for blood pressure, diabetes, cholesterol and gout at the same time arrives with eight to twelve.

And every line carries far more than a line in a clothes shop: the unit it is sold in — a strip of ten, a single tablet, an insulin pen — the daily dose, the instructions to be printed on the patient's label, the batch, the expiry date, a discount.

A cart pinned to the right-hand third of the screen cannot hold that at any font size. Meanwhile the product grid took two thirds of the screen to serve a behaviour no pharmacist performs.

This was never a pharmacy problem. It is what happens whenever a line item has to carry too much.

I had met the shape before. Years earlier I worked on ticketing for a children's activity centre, where every ticket line carried a child's name, an age band, a session time, a wristband colour and a guardian. Unrelated industry, identical structural failure.

What carried over was not an interface — that project's screens were nothing to look at — but a structural decision: stop trying to fit the line item into whatever column is left over, and give it the width instead.

So I proposed it: drop the grid, give the full width of the screen to the line items.

The original cart, with every line item squeezed into a narrow column beside a grid of product tiles. The revision that followed: the same twelve rows, each one repeated again in a summary column down the right.
The original screen, and the revision that followed it. Both shown at twelve lines — the size of order this screen had to survive. Redrawn; the patient and the pharmacy are fictional.

The constraint

Two things shaped the work, and neither was technical.

The customer did not want the system to prevent anything. They required that a batch past its expiry date could still be sold: the screen should say so, and the pharmacist decides. That is a decision about how their staff work, and it meant the design's job was to inform, not to block.

And the layout had been chosen before I was asked to draw it. It came from a generated suggestion and it was chosen because it looked complete. Among other things it had invented a drug-allergy conflict panel that nobody had asked for — plausible for a pharmacy, absent from the brief, and expensive in the one resource that screen did not have: room.

It did not use the product's design system either. The approved screen takes its colours from tokens named for the job they do — text/mute, border/soft, surface/panel. The generated one names them Persian Green, Ebony Clay, Athens Gray: what a colour tool prints when you hand it a hex value, not names anyone chose.

That is how a screen can look finished and still look foreign. Every value in it was defensible on its own. None of them came from the same place as the rest of the product.

The decision

The full width goes to the cart. The grid is gone, replaced by a single search-and-scan field.

What stays on the row is what changes during a sale: quantity, the unit being sold, and the running line total. The expiry date sits under the product name and turns red as it approaches, because that is the thing a pharmacist has to notice without being stopped.

What leaves the row is everything set once or rarely — price, discount, batch, splitting a line, a note. They move into a per-row menu: two taps instead of a live input field. Slower for the rare case, and it removes a whole class of mis-tap from the common one. Price in particular can no longer be changed by brushing against it.

Daily dose and patient instructions leave the sale entirely. They are not needed while ringing up, and in the real workflow the label is printed after the order completes and stuck onto the box. So they live in that step, with a proper picker for quantity and unit per day.

Line items running the full width of the screen. The same twelve rows, now legible.
The approved layout, at the same twelve lines and the same data.

What happened

The proposal was turned down. A version built from the generated layout went to the customer and was rejected. The team revised it internally, moving back towards the original shape, and that was rejected too — the information the customer wanted on each line would not fit, and they would not accept a screen that busy.

I was asked to take it back, and proposed the same structure I had proposed at the start. It was approved.

The revision is the second screen above. It kept the full-width table and brought the cart back as well, as a summary column down the right: every item on the screen twice.

It did not survive its own structure. The table header counts twelve prescriptions and three hundred and seventeen units. The summary beside it counts eleven and two hundred and eighty-seven. Nobody typed a wrong number. There were two places where one total had to stay true, and they had already come apart in the file we were about to send.

The disagreement cost two full rounds, in time and in money.

Looking back

The advisory text is the part I would change. Those are the instructions that get printed and stuck to the patient's medicine, and today they are typed as free-form tags. They should be picked from a list the pharmacy maintains, so that take after food reads the same way on every label and cannot be mistyped. A list means building a settings screen to create and edit those presets, which was more than the budget allowed, so typing won. That is the right call for the budget and the wrong one for a label a patient reads at home. The same step should probably also offer to print automatically when an order completes.

The rest is about me. I was right early and it changed nothing, which is the part worth examining.

I argued the case more than once and lost it more than once. Repeating an opinion is the weakest form of argument a designer has; said often enough it becomes background noise and people learn to work around it. What would have settled this in an afternoon was a demonstration — build the twelve-row version beside the three-row version and let the two screens make the argument. That is the thing I do differently now.

The second lesson is about the generated layout. It was not stupid. It was complete: every field a pharmacy checkout might plausibly need, visible at once, plus a safety feature invented out of what a pharmacy sounds like. It optimised for coverage. The work needed prioritisation — and prioritisation requires knowing that the twelve-item order is the one that decides the layout, and that two thirds of that screen served nobody at all.

Real project, anonymised under a confidentiality agreement. Screens have been redrawn and all data is fictional.

← All work