Building a Till That Keeps Selling When the Internet DropsBy:  Muhammad Faisal

How a shop’s checkout software handles lost connections without losing money or making duplicate sales · Muhammad Faisal · Week ending October 23, 2026

Imagine a busy shop at closing time. A queue of customers is waiting, and the internet goes down. If the checkout software stops, the shop loses sales and customers lose patience. This week I worked on making the IQ-POS desktop app keep selling offline, then catch up safely once the connection returns.

This post explains how, in plain language. You do not need a technical background.

What IQ-POS is

IQ-POS is software for shopkeepers. It handles billing at the counter, stock, receipts, supplier records and customer credit. This week’s work focused on the Windows desktop version, which runs on the shop’s own computer.

The problem in one sentence

A sale made while offline must be stored safely, protected from prying eyes, and sent to the server exactly once, even if the connection drops again halfway.

The five challenges at a glance

ChallengeEveryday comparisonWhat we built
Keep unsent sales safeA locked drawer under the counterEncrypted local storage, with a separate key for each shop
Record what was agreedA sealed, signed receiptAn unchangeable sale record with prices, totals and payment terms
Send each sale only onceA numbered chequeA unique key the server uses to spot repeats
Avoid two things at onceOne cashier at the tillA worker that sends sales one at a time
Show what is happeningA tray labelled sent and waitingA status panel with a Retry button

1. A locked drawer for unsent sales

When the internet is down, sales have to wait somewhere on the shop computer. That storage must be private, because it holds customer and payment details.

What we did. Offline data is stored in a small local database and encrypted. Encryption scrambles information so that only someone with the right key can read it. A master key is created for the installation and protected by Windows itself. From it, each shop gets its own separate key.

Why it works. Think of one building with many shop units, each with its own lock. Even if someone copies a locked box from one unit, it will not open in another. A tampered copy also fails to open, because the encryption checks that the contents have not been changed.

A deliberate detail. Signing out clears the cached product and customer lists, but keeps any sales still waiting to be sent. A shopkeeper should never lose a sale just because they logged out.

2. A sealed record of each sale

When a sale happens offline, the app does not just note a total. It saves a complete, unchangeable record of the agreement: the shop, the customer, each product, the agreed prices, the stock it saw at that moment, the totals, how it was paid, and the local time it was completed. It also gets a receipt reference so the customer has something to hold.

What is allowed offline. Cash and customer credit work offline. Cash must cover the full total. Credit needs a valid due date and must leave a balance still owed. Card payments are refused with a clear message that a connection is required.

Why it works. A sealed receipt cannot be quietly edited later. If anyone questions the sale, the record shows exactly what was agreed at the counter.

3. Send each sale exactly once

This is the part that surprises most people. Sending a sale is risky in a particular way. Suppose the app sends it, the server records it, but the reply is lost on the way back. The app thinks it failed and tries again. Without protection, the shop now has the same sale twice.

What we did. Every sale carries a unique key, a bit like a cheque number. The server remembers the keys it has seen for each retailer. If the same sale arrives again, the server recognizes the key and returns the original result instead of creating a second sale.

A safe, separate door. The server received a new dedicated entrance for these sales. It checks the money adds up and saves everything in one all-or-nothing step, which databases call a transaction. The existing web checkout was left untouched, so nothing already working could break.

4. One at a time

A computer can try to do many things at once, and that can cause clashes. The sending worker claims one waiting sale at a time and records the result. If the app is closed halfway through a send, the next start moves that sale back to waiting. Thanks to the unique key, trying again is safe.

5. Show what is happening

A shopkeeper needs to see the state of things without reading logs. The sidebar shows whether the computer is online, how many sales are waiting, and which receipts have a conflict. Sending starts when the app opens online, again when the connection returns, and on demand with a button.

If a sale cannot be applied, it is marked as a conflict instead of being silently dropped. The only action offered is Retry, which keeps the process simple and safe. The screen never sees the scrambled data or the keys, only the receipt number and its state.

The cash drawer

Many shops use a USB cash drawer. The desktop app can list the connected ports, remember the chosen one, run a test, and open the drawer after a successful cash payment. It opens whenever the cash part of a payment is above zero, including mixed payments, but never for card-only or credit-only sales. The screen cannot send arbitrary commands to the device, only the approved action.

The same idea for online orders

The customer side of the app faced a similar problem. When a customer places a cash-on-delivery order and the connection times out, the order may already exist. Placing it again with a fresh key could create a duplicate.

So the app keeps the same key for every retry and locks the delivery details while the outcome is uncertain. If the server already has the order, it replies with that same order. The saved attempt is kept only for that customer, in temporary storage, and removed once the order is finished.

A related rule applies to reading data: simple look-ups are retried up to twice after a network problem, but anything that moves money is never retried automatically.

What is not yet proven

Good engineering means saying what has not been tested. The checkout work is marked conditionally complete. Real tests with live accounts are still outstanding: a completed sale, a stock conflict, a duplicate completion attempt, and two different shops trying to reach each other’s data. They are listed as release blockers, and moving on does not remove them.

There were also build problems. One runtime download was only partly unpacked, and the installer failed on a computer with very little free disk space. Both were diagnosed and have clear fixes.

What I learned

  1. A timeout is not a failure. Retry with the same key, never a new one.
  2. The server stays the final authority on money. The app reloads the bill after every change.
  3. Give each shop its own lock, so one leak cannot expose everyone.
  4. Record what was agreed at the moment of sale, in a form that cannot be edited.
  5. Show people the state of the system, and offer only safe actions.
  6. Keep a list of what is not yet verified, and do not delete items from it just because work moved on.

A short glossary

TermPlain meaning
Offline-firstSoftware that keeps working when the internet is unavailable
EncryptionScrambling information so only someone with the key can read it
Idempotency keyA unique number that lets a server recognize a repeated request
TransactionA group of saves that either all happen or none do
ConflictA sale the server could not apply as sent, needing attention
Release blockerA test that must pass before the software is released

What comes next

Next week I plan to run the live tests with two approved shop accounts, free the disk space needed to build the Windows installer, test the offline sales on the packaged app, and finish the customer screens for order tracking and profile.

Leave a Reply

Your email address will not be published. Required fields are marked *