"POS — selling when the network drops"
"The counter keeps taking cash when the connection drops: sales are kept on the device, a provisional receipt prints, and everything syncs when the network is back — plus what still needs the network."
In the POS app, a status bar at the top of every counter screen shows Online or Offline, how many sales are waiting to sync, how many conflicts there are, and how old the device's catalogue is. Press Offline queue to open the queue.
"You're offline. Cash sales only. Tables/kitchen, returns, debts, shifts and stock need the network."
That sentence is this page in short. Four things catch people out, so here they are first:
- It is ON by default, and it is per device, not per shop. Each device keeps its own catalogue and its own queue; no other device sees this one's offline sales until it has synced them.
- Clearing the browser's data loses any sales that have not synced. An offline sale lives on that device and nowhere else.
- The receipt printed while offline is provisional, numbered
NT-…, not the order's official number. - A sale is recorded at the server's time when it syncs, not when it was rung up. Sold at 23:50 and synced at 00:10, it lands on the next day in your reports.
Turning it on and off
The Sell when offline switch lives in the Offline queue panel:
"Keeps a catalogue on this device and queues cash sales while the network is down."
It starts on for a plain reason: the catalogue has to download before the network goes. Switching it on once you are already offline is too late. Turning it off on one device stops that device downloading the catalogue and selling offline; other devices are unaffected. There is no shop-wide switch yet.
What you can sell offline
Quick sales paid in cash, and nothing else. You can still scan or search, type the cash received, apply a manual discount, and type a customer's phone and name as plain text. The pay button becomes Finish (offline).
Everything else needs the network: bank transfer/VietQR, card, discount codes, looking up an existing customer, debt and debt payments, returns, voids, opening and closing shifts, cash in/out, receiving, transfers and stock counts, tables and kitchen tickets, ticket scanning. The reason: cash is the one payment the counter can confirm without asking anyone. The others change something several devices share (a shift, a debt, a table, a code's uses), and doing them offline creates two versions of the same fact.
If the network drops at the very moment an online sale is being finished, the screen offers Finish offline (cash). If a transfer QR is showing, the app does not switch to cash on its own: the cashier has to choose Take cash instead, because only the person at the counter knows whether the customer already paid.
When the finish button is replaced by a sentence, the sentence says why. The usual ones:
- No catalogue on this device, or one for another location: connect once so it can download.
- The shop adds tax on top or runs an automatic discount. Only the server can calculate those, so the device cannot print a correct total. Offline selling switches off rather than print a wrong number.
- The register requires a shift and this device holds no open one: open a shift while you are online.
The provisional receipt
"Provisional receipt — offline. The official number is issued when it syncs."
The NT- code is followed by eight characters taken from that sale
itself, so two devices selling offline never collide, and the device's
clock plays no part. Once it syncs, the queue row shows the real order
number ("Recorded as …") and an Official receipt button to reprint
the official version if the customer wants one. In Manage → Orders,
the order's note reads Bán ngoại tuyến · NT-… · <device time>, so you can
trace a provisional receipt to its real order.
A sale counts as made only once it is saved on the device. If it cannot be saved (usually because browser storage is full), the app says so, prints nothing, does not open the drawer, and keeps the cart as it was.
The queue and syncing
When the network returns the app syncs on its own; Sync now does it on demand. Sales go up in the order they were made. Each one becomes exactly one order even if the connection flickers mid-way or two tabs sync at once: sending it again never creates a second order.
The panel has four groups: Needs a decision, Waiting, Synced and Removed. Synced sales stay visible for 7 days and removed ones for 30, then they are cleared. Waiting and conflicted sales are never cleared automatically.
A device only syncs sales made by the account that is signed in.
Another person's sales on the same device show "Waiting for
A sale is recorded in the register's shift that is open when it syncs, because that is the drawer the cash is in. If that differs from the shift at the time of sale, the row says "recorded in another shift".
Conflicts
A sale lands in Needs a decision when the server will not take it as it was rung up. The app never fixes it silently; each kind has a button:
- The price changed. The row shows "Charged … · System total … · Difference … (will show in the drawer count)". Use the system total records the sale at the system's current price. The cash the customer paid is already in the drawer, so the difference shows up in the shift's cash count (over/short) at closing. That is the right place to see it, rather than the device quietly rewriting a price.
- A product was deleted. Drop the deleted line records the rest; the difference goes to the drawer count as above.
- The system does not have the stock. The goods have left the shop, so the system's stock figure is wrong. Correct it (receive or count), then Retry. Stock is never allowed to go negative.
- The register's shift is closed. Open a shift, then retry.
- Handled elsewhere, for example a manager dealt with the sale while force-closing a shift: Mark as handled.
Remove from queue is a decision, not a tidy-up button: it asks for a reason, the sale will never be sent, and the cash taken stays in the drawer and shows in the shift's count.
A shift will not close while this device holds unsynced sales
"N offline sales on this register haven't synced yet. Sync or resolve them before closing the shift."
Closing a shift with cash in the drawer that is not in the books makes the end-of-shift report wrong for certain. One limit: the block exists only on the device holding the queue. Close the shift from another device and that device cannot see this queue.
The catalogue on the device
The status bar shows "Offline catalogue: … ago". The catalogue is a snapshot of products, prices and stock for the location the register is at, refreshed about every 15 minutes while online; Reload catalogue refreshes it now. Past 12 hours its age turns to a warning colour: the prices and stock you are selling from may be stale, and every stale one is a conflict at sync time. If a refresh fails, the device keeps using the previous snapshot and the queue panel says what went wrong.
While offline, the device will not sell more than the snapshot's stock minus what is already in the queue. When several devices sell the last unit offline, whichever syncs later gets a stock conflict.
Browser storage
The queue panel shows "Storage kept by the browser: yes/no" and how much is used. "No" means the browser may clear the site's data on its own when the device runs short of space. The app asks to be kept, but the browser may refuse. Either way, clearing browsing data, using a private window, or uninstalling the browser deletes the queue too, and once it is gone there is no way to tell what was lost. Before you clean up a counter device, make sure its queue has fully synced.
Reloading the page while offline still gets you back to the Sell screen, because the device keeps a copy of the app. The status bar then says "Started from this device's saved copy": the register, shift and permissions shown may be out of date until the network is back.
Updated 09/10/2026