FPOS Wow
A fast and intuitive front till for retail checkout counters.
Final
Final POS
About this flow
FPOS Wow is a front till register recreated for counter environments, featuring high-contrast light and dark themes, drill-down category tiles, and resilient cart calculations. Designed for retail operators who need fast scanning, accurate line-level discounts, and synchronous receipt printing without lag.
What it can do
Color-Coded Tile Grid
Renders product and category tiles with colors derived from catalog rank so staff retain visual memory.
Flexible Discounting
Supports percentage and monetary discounts applied at both individual line-item and full cart levels.
Quick Cash & Tenders
Features interactive numeric keypads with quick-cash note shortcuts, balance tracking, and cash tender safeguards.
Optimized Item Scanning
Queues rapid barcode scans and manual taps to reliably increment quantities without line collisions.
Screenshots
Tags
Version history
- v2.0.6Current
Two fixes in the refund dialog. - The dialog no longer overwrites the engine's own theme tokens. Its local aliases were named --success, --success-bg, --destructive-bg and --stage, which are ENGINE-OWNED: assigning them inside .rf-overlay silently disconnected the brand knobs for every element beneath it, and pinned the engine's success colour to the brand primary. They are now --rf-* and each still derives from a real token, so nothing hardcodes a hex. Measured in preview after the change: --success resolves to the engine's own value again inside the dialog, while the dialog's own accents still follow the brand. --r8 / --r4 were renamed the same way; all eleven widget files were checked for stale references. - The reason section prints real glyphs. It carried literal \u2014 and \u2026 escape sequences inside JSX text, so the dialog read "optional \u2014 stock action is on each line" and its note placeholder "Add a note (optional)\u2026" on screen. Not device-verified: this release changes presentation only, and no refund money path was re-exercised. Note for anyone testing in preview: this sandbox has no mock handler for getRefundPlan, and the dialog renders nothing until a plan resolves — so an empty refund dialog there is the mock, not the flow.
- v2.0.5
Refund amounts now show what was actually paid back. - `summary.total` on a refund is the refund as COMPUTED, before the company's cash rounding is applied on the way out. On a rounding company the two figures differ, so the order detail was quoting the computed figure while the customer had been handed the rounded one — a refund line that disagrees with the drawer is worse than no refund line at all. The refund's own PAYMENT LEGS now win: `refundPayment[].amount` is a record of what moved, not a calculation of what should have. `summary.total` stays as the fallback for a refund carrying no legs. The magnitude is taken because a refund leg's sign is not consistent and the UI supplies the minus itself — that normalises presentation, it does not compute an amount; every figure shown is still one the host sent. - Where the host applied rounding, the refund row now carries an "includes cash rounding" line showing the delta, so a rounded refund reads as the company's setting working rather than as an arithmetic mistake. - The order-level Refunded and Net paid figures are summed from the same paid-back amounts, so the total agrees with the rows beneath it and with the drawer. The list row's "Part refunded" marker uses the same reader. Not device-verified: printing, cash rounding and refunds remain mocked or absent in preview. The refund-remainder path has still not been exercised against a real second refund.
- v2.0.4
Order detail: real refund records, and the order's status. - Refund detail was missing because the figure it relied on does not exist. 2.0.3 read `summary.amountRefunded`, which is OPTIONAL on CFSummary and was simply absent on a real part-refunded order — so the detail showed no sign a refund had ever happened. The screen now reads getRefunds({ orderId }), which is authoritative, and lists every refund taken against the order: when it happened, how much went back, and which tender it returned to. Which tender is the part a drawer reconciliation needs and the part a single total cannot carry. The order's own embedded refund[] is the fallback for a host that does not answer the query, and an empty query result defers to it rather than overwriting a good local answer with nothing. - The totals block now carries Refunded and, when something was returned, Net paid — what the customer is actually left having paid. Net paid is shown only when a refund exists, since otherwise it just restates the total. - Order detail shows STATUS. Status, payment state and fulfilment state are each rendered when the order carries them, in a strip under the header. The state vocabulary belongs to the host and is not enumerated anywhere this flow can read, so values are printed as they come with only punctuation and casing normalised ("partially_refunded" reads "Partially refunded") — a lookup table would silently mislabel any state we had not seen. An order carrying none of the three says "Not reported" rather than showing an empty strip. - The list row's refunded marker now falls back to summing the order's own refund[] when summary.amountRefunded is absent, so "Part refunded" appears there for the same orders. Not device-verified: printing, cash rounding and refunds remain mocked or absent in preview. The refund-remainder path has still not been exercised against a real second refund.
- v2.0.3
Two fixes. - The receipt names the customer again. Who a sale is for lives on the CART — assignCustomer and removeCustomerFromCart both write the cart, which is why the whole till reads it from there — but the receipt was seeded from the order the tender call hands back, and that order came with an empty customer. Completing the sale then clears the cart, so by the time anyone tapped Print the answer no longer existed anywhere. The name is now latched while the cart is still alive and carried in the print seed, exactly as tendered and change already were, and for the same reason. A reprint from ORDERS still prefers the historical order's own customer record over the latched one. - A refunded order stays in the order list. The list asked the host for status: "completed"; refunding moves an order off that status, so a partly-refunded sale vanished from its own history the moment it was refunded — taking with it the only route back to refunding the remainder. getOrders takes one status string rather than a list, so "completed plus whatever refunding produces" cannot be expressed as a query, and guessing the host's spelling for a partial refund risks hiding real sales again. The query now asks for everything and only PARKED is filtered out here, because the HOLD sheet owns those. Paging still counts raw rows so the offset stays in step with the host. Also in this release: refunded money is now visible rather than implied. The order row carries "Part refunded" or "Refunded", the order detail carries a Refunded line under the total, a reprint of a part-refunded sale says so on the slip, and the refund button reads "Refund rest" once something has already gone back. The refund dialog needed no change — it asks the engine for the order's own refund plan, which already accounts for earlier returns. Not device-verified: printing, cash rounding and refunds remain mocked or absent in preview. The refund-remainder path in particular has not been exercised against a real second refund.
- v2.0.2
Follow-up to 2.0.1 on two operator reports. - Per-line product notes now appear on the receipt and in the order detail. This is a different field from the sale's own note: addProductNote writes CFLineItem.note, addOrderNote writes the order's. 2.0.1 added only the latter, so "no onions" and "gift wrap" — usually the note that had to travel with the goods — were still dropped from both surfaces. - The stock check now subtracts the live basket. The dimming came from a catalog snapshot, and that snapshot does not move when a unit goes into the cart — the host reduces stock when the sale completes. So a variant with one unit on hand stayed sellable after that unit was rung, and the cashier could ring a second, a third, a tenth; only items already at zero before the sale began ever greyed out. The guard now reads the on-hand figure rather than a boolean, subtracts what is already in the basket, and is shared by the grid and search so the two cannot disagree. Two distinct refusals, because they are fixable in different ways: "<item> is out of stock" versus "Only N of <item> in stock, and they are all in the basket". - Fixed a latent fault in the same reader while there. It summed inventory[].stock into a 0 that stayed 0 when no row carried a readable figure, then concluded 0 <= 0 — so a catalog that merely spelled that field differently would have greyed out every tracked product on the till. An unreadable row is now an unknown, and an unknown never blocks a sale. Backorder-enabled variants and stock-pool borrowers (stockVariantId, whose inventory is derived from the owning variant's ledger) are likewise treated as no-claim rather than summed. Not device-verified: printing, cash rounding and refunds remain mocked or absent in preview.
About the maker

Final
Final POS
