Point of Sale
The Point of Sale (POS) module gives a retail counter a full till: barcode-or-search checkout, cash and mobile-money tendering, automatic stock deduction, till (register) shift tracking with a closing Z-report, and TRA-fiscalized receipts. It works as its own standalone package — you do not need the Accounting or Logistics modules to run POS, though GL posting activates automatically if you have Accounting configured.
- POS is a real subscription plan — subscribe from the pricing page, or ask your service provider to add it to an existing subscription. Once your tenant is licensed for it, your Tenant Admin can turn it on/off in Platform Modules (reachable from the profile menu) like any other licensed module.
- Add at least one Item of type Product with a Selling Price — Checkout only sells from your Product Catalog.
- Configure at least one active payment method in Settings → Point of Sale (Cash is on by default).
Checkout
Go to Point of Sale → Checkout. The menu entry is usually called Checkout (Take Order at a restaurant till), or "[Profile] Checkout" when the till uses a POS Profile — and the profile decides which menu it sits under.
If you can see more than one store, Checkout first asks Choose a Store — pick the one you're working at. Before the register is opened you can go back with ← Change Store.
- Add items to the cart — scan a barcode (a physical scanner or a keyboard-wedge scanner both work directly into the search box), type a name/code/barcode to search, or tap a tile in the Quick-Add grid below the cart. To add several of the same item at once, type the quantity and
*before the code — e.g.3*then scan adds 3. - Adjust quantity or remove a line directly in the cart. Each line has an optional Disc. (discount amount) box, and there's a Whole-Sale Discount box under the Total. Every discounted sale is recorded in the System Audit Trail with its amount.
- Optionally pick a Customer — search by name, phone, or TIN, or use + New Customer. Picking a customer fills in their TIN. For a walk-in who wants their TIN on the receipt, just type the 9-digit number in Customer TIN.
- Click a payment method (Cash, M-Pesa, Mixx by Yas, Airtel Money, HaloPesa, CRDB Bank, or any custom method your tenant has activated) and enter the amount — Cash shows change due automatically; other methods have an optional Reference / Transaction ID box.
- Click Complete Sale. The button shows Saving… until the sale is confirmed saved — only then does the cart clear and the success message appear. The sale is recorded, stock is deducted, the register session's running totals update, and — if TRA VFD/EFD Fiscalization is on for your tenant — the sale is fiscalized and a fiscal QR code appears on the printed receipt.
If another till saved at the same moment, Checkout reloads the latest data and tries once more on its own. If it still can't save (for example, no connection), you get a clear error and the cart stays as it was — just press Complete Sale again.
The Last Sale card shows the sale's number, payments, customer/TIN, and TRA status (with a Retry if fiscalization failed), plus 🧾 Print Receipt (and Share via WhatsApp, if your tenant has it on).
Out-of-stock items
Search results and Quick-Add tiles show Low Stock or Out of Stock badges, and each cart line shows how many are in stock at this store. What happens when you add more than is in stock depends on the Out of Stock Sales setting: Allow (no check), Warn (a confirm box you can accept), or Block (the item isn't added, and Complete Sale stays disabled while any line is over the stock on hand).
Quick-Add tiles
The tile grid below the cart is a fast-tap alternative to scanning, seeded from two sources:
- Pinned favorites — items an
items.manageholder has explicitly pinned, always shown first. - Auto top-sellers — your store's best-selling items over time, filled in automatically, scoped to the current branch.
A user with items.manage sees a small ✕ on each tile to remove it (sets it to Hidden — it will never reappear even if it becomes a top seller again); cashiers without that permission see plain tiles with no remove control. The grid stays visible below the cart at all times, not just on an empty cart, so a cashier can keep tapping for the 2nd and 3rd item of a sale.
Held sales
Click ⏸ Hold to park the current cart (e.g. a customer steps away to get more cash) and start a new one. Held sales appear in a "sales on hold" bar above the cart — click one to see its items, then Resume This Sale. Resuming while your current cart still has items asks for confirmation first, since resuming replaces the cart. Held sales belong to the register session they were parked in, so finish or resume them before closing the register.
At a restaurant till, an optional Table / Tab field names the held sale (e.g. "Table 4") so it's easy to find again — see Hotel Management → Restaurant POS.
Splitting a payment across methods
Once your store has 2+ payment methods active, a + Split Payment link appears next to the Payment Method label — click it to pay one sale across multiple tenders (e.g. part Cash, part M-Pesa). Add a line per method (with an optional reference/transaction ID for non-Cash methods) until the Remaining indicator reaches zero — split payments must add up to the sale total exactly, with no change or overpayment concept, unlike a single-method Cash sale. Click ← Single Method to switch back to the normal one-tender flow. The receipt itemizes each method's amount, and reports (Sales, Reconciliation) split the sale's cash and non-cash portions correctly rather than counting the whole total under one tender.
Cash Out
Click 💵 Cash Out (next to the register status, not part of ringing up a sale) to record cash taken from the till directly — e.g. paying a delivery boy or a small supply run — without a sale involved. Enter the amount, pick a Category (searchable — defaults to "Till Cash Out"; choose a specific one so the Expenses report breaks it down properly), and a reason (required). This posts immediately as an expense and is subtracted from the till's expected closing cash, unless your tenant has Settings → Point of Sale → Cashier Expense Approval turned on and you don't hold expense-approval authority yourself — in that case it still reduces expected cash immediately, but needs a manager's approval before it posts to the books. Requires the expense.cashout.create permission (on by default for POS Cashier, POS Manager, and Tenant Admin) and an open register.
Voiding a sale
- The sale you just rang up — Void this sale on the Last Sale card (needs
pos.void). It's only there until you complete the next sale or leave Checkout. - Any earlier sale — Void on that sale's row in POS Reports → Sales (needs
pos.void.posted; Tenant Admin and POS Manager by default). If the sale's register is already closed, you're warned that the session's Expected Cash and Variance will change.
Either way a reason is required, and stock and GL postings are reversed. If the sale was already fiscalized, you must type CONFIRM first — TRA has no void from the system, so you also need to void the receipt in the TRA portal yourself. The sale then shows ⚠ TRA Void Pending in Sales and is listed under Pending TRA Portal Voids on the POS Manager dashboard until someone clicks Mark Done — Voided in TRA Portal.
Saving at the till
Opening and closing a register, a Cash Out, and a void only show success once the change is confirmed saved (the button shows Opening…, Closing… etc. meanwhile). If another till saved first, the system reloads and tries once more on its own. If it still fails, you get a clear message (e.g. "The register was NOT closed — check your connection and try Confirm Close again") and nothing changes — try again. You'll also be told if the action no longer applies, e.g. the register was already closed on another device.
VAT display
Two independent, cosmetic-only toggles in Settings → Point of Sale → Receipt & Stores control what's shown, not what's calculated — VAT is always computed and fiscalized correctly regardless of either setting. They only appear when your company is VAT-registered:
- Show VAT Breakdown on Checkout — hides/shows the VAT line on the live checkout screen (the Total is always correct either way).
- Show VAT Breakdown on Receipt — same, but for the printed/previewed receipt.
Whether prices are entered VAT-inclusive or exclusive is a separate, tenant-wide setting — see Settings → Company → Regional & Tax.
Fullscreen / kiosk mode
Click ⤢ Full Screen on the Checkout screen to hide the app's own header and navigation, not just the browser chrome — useful for a dedicated till terminal where you don't want a cashier navigating elsewhere in the ERP. Exit fullscreen (Esc, or the same icon) to return to the normal app.
Register Sessions & Z-Reports
A cashier or manager must open the register before Checkout is usable — enter an opening cash float and the shift begins.
At the end of a shift, close the register: count the cash drawer and enter the counted amount. The system shows:
| Field | Meaning |
|---|---|
| Expected Closing Cash | Opening float + the Cash portion of sales during the session (a split-payment sale only counts its Cash line, not its full total) − any Cash Outs logged during the session |
| Counted Closing Cash | What you actually counted |
| Variance | Counted − Expected (shown in red if short, green if over) |
The close screen also lists each Cash Out ("Cash Paid Out") and the full breakdown by payment method (Cash, M-Pesa, etc.) — this is the till's Z-report. At a hotel property, guest-folio settlements taken during the shift are counted here too. Every closed session, including its variance, is visible afterwards in POS Reports → Register Sessions; a nonzero variance also shows up in the Audit Trail.
Multi-branch (Stores)
If your tenant runs more than one physical location, set up Stores to keep checkout, stock, and reports scoped correctly per branch.
Stores (Branch CRUD)
Settings → Company → Stores — add, edit, deactivate, and set a default store. If you also run Hotel Management or Student Hostel, the same card is called Branches & Properties (or Properties). Reaching Settings needs the Manage Settings permission (Tenant Admin by default); adding and editing stores also needs branch.manage.
Locations are kept in separate sections, shown as tabs when you have more than one: Stores, and — depending on what your tenant runs — Filling Stations, Restaurants, Hotel Properties, Hostel Properties, and Logistics Stores (for Diesel Yard / Spare Parts stock). Each section has its own default and only appears on the screens that use it: Checkout offers stores, filling stations, restaurants and hotel properties (a hotel property doubles as its restaurant/front-desk till), but never a hostel property. If a location landed in the wrong section, edit it and change Section.
- Fields — name, code (unique across all locations), address, phone, TIN; for till locations also Brand Name, VRN (both printed on the receipt header) and, once you've created any, a POS Profile.
- Deactivate is refused for the last active location in a section, the section's default, or a location with an open register.
- Delete is only offered on an inactive location, to users with
branch.delete. - Export to Excel lists the current section.
Each store's own Brand Name and TIN print on that store's receipt header — useful if you run more than one retail brand's outlets, or each outlet is separately TRA-registered, under one eSecured tenant (e.g. a "Skechers Retail Outlet" store printing under that name rather than your account's own display name). Leave either blank to fall back to the tenant's own company name / TIN. Store address and phone print on the receipt too.
Per-user branch assignment
Settings → Users & Access — once you have 2+ stores, set each user's Assigned Store (shown as Assigned Location when you also have hotel or hostel properties):
- A user assigned to a store has Checkout auto-resolve to it — no picker shown.
- A user with
branch.viewAll(Tenant Admin by default) gets a "Choose a Store" picker instead, and can see data across every store in Reports. - An unassigned user without
branch.viewAllsees a blocking "ask your manager" screen instead of Checkout.
This scoping also applies to the POS Manager and POS Cashier landing dashboards, not just Checkout and Reports — a POS Manager without branch.viewAll sees only their assigned store's sales, top sellers, low-stock alerts, and register sessions on their own dashboard, and a POS Cashier's register status reflects their assigned store rather than the tenant's default store.
Stock Transfers
Point of Sale → Stock Transfers (needs stock.adjust) — move stock between two stores: Draft → Approved (stock moves at both ends) → Void. Voiding needs a reason; voiding an already-approved transfer reverses the stock movement. Each transfer has a printable 🧾 Slip.
With 2+ stores active, Purchase Invoices also gain a Receiving Store selector, so a vendor bill's stock receipt lands at the correct branch.
Reports
Point of Sale → Reports — one page, several tabs:
| Tab | Shows |
|---|---|
| Sales | All sales, filterable by store/cashier/payment method/date/status and searchable (sale number, cashier, store, customer TIN); Sales-by-Store and Sales-by-Cashier breakdown cards, both drill-down clickable. Every row has 🧾 Receipt to reprint or share a past receipt, and Void for users with pos.void.posted (see Voiding a sale). A user without pos.reports.viewFinancials (e.g. POS Cashier) sees only their own sales here |
| Expenses | Same Expenses records used elsewhere in the app, gated on expense.view |
| Stock Movement | The full stock ledger, with a running "Remaining Qty" per item and store. The Type filter covers every kind of movement: POS Sale, POS Refund, Purchase Receipt, Transfer In/Out, Adjustment, Opening Balance, Fuel Issue (Diesel Yard), Part Issue and Part Write-Off (Spare Parts), Supply Issue (Supplies) and Goods Received (PO) (Trading). Users with stock.adjust also get + Adjust Stock. For a large batch of counts at once (e.g. an initial stocktake when setting up a new store) use Settings → System → Data Import → Stock Levels instead — see Data Import & Onboarding → |
| Inventory | Stock-on-hand, stock value, and low/out-of-stock counts per item, filterable by store (needs items.view) |
| Register Sessions | Every register session with its Z-report; open a session's FactBox and click View Sales → to jump to that session's sales |
| Profit & Loss | A lightweight Revenue/COGS/Expenses/Net Profit view for POS-only tenants — hides itself automatically once you add the Accounting module, so it never disagrees with the real P&L in Financial Reports. Its Cash Position card shows Cash Sales, Cash Paid Out (Cash Outs), and Cash in Hand, plus a breakdown of other tenders — see Reconciliation below to confirm what actually landed for those other tenders |
| Reconciliation | Manually confirm what actually landed in your M-Pesa/Airtel Money/bank account against a day's till sales for each non-Cash payment method, per store — see below |
| Audit Trail | See below |
Revenue/COGS/Operating Expenses figures on the P&L tab, and the by-Store/by-Cashier rows on Sales, are all click-through — they jump to the underlying filtered records on the relevant tab. Stock Movement, Register Sessions, Profit & Loss and Reconciliation need pos.reports.viewFinancials. When TRA fiscalization is on, a 📊 Z-Reports → button at the top opens the fiscal Z-Report page.
Reconciliation
Cash already reconciles itself at register close (see Register Sessions above) — this tab is for everything else. One row per day/store/payment method with at least one completed sale: Expected is computed live from sales (so a later void/refund updates it immediately), and you enter Collected once you've checked the real statement — the Variance and Pending/Reconciled status update automatically. Gated on the pos.reports.reconcile permission (Tenant Admin and POS Manager by default) — viewing the tab itself only needs pos.reports.viewFinancials, so an Accountant can see it without being able to record a collected amount.
Audit Trail
Gated on the dedicated pos.audit.view permission (Tenant Admin only by default — not inherited from pos.reports.view, so a POS Manager doesn't automatically get it). Aggregates, read-only:
- Voided sales (a reason is required to void — cancelling the reason prompt aborts it)
- Stock adjustments
- Register session variances
- Stock transfer approvals and voids (same reason requirement as voiding a sale)
- Store deactivations
Every row shows actor and timestamp, and click-through lands on the matching source tab.
Settings
Settings → Point of Sale:
- Payment Methods — activate/deactivate tender types; Cash, M-Pesa, Mixx by Yas (Tigo Pesa's current Tanzania brand), Airtel Money, HaloPesa, CRDB Bank, and Other are pre-listed, or add your own. Activating a 2nd method is also what makes split-tender payments available at Checkout.
- Receipt & Stores — custom receipt footer text printed at the bottom of every receipt in place of the default; the two VAT display toggles; Show Customer TIN/VRN on Receipt (a linked customer's name and phone always print); and, once you have 2+ stores, the Default Store a shared device starts on when its user has no assigned store.
- Label Printing — label size (preset sizes, a continuous roll, or a custom size in mm), default copies per item, and whether the price prints. See Barcode labels & variant groups.
- Out of Stock Sales — Allow, Warn, or Block selling more than is in stock at that store (see Out-of-stock items). "Low stock" uses each item's own reorder level at that store, or 5 units when none is set.
- Cashier Expense Approval — off by default. Turn it on to require a manager's approval before a till expense or Cash Out from someone without approval authority posts to the books — it still reduces expected closing cash immediately either way, this only changes whether it needs sign-off before affecting the ledger. Pending items go to your approvers through Settings → Notifications → Approval Queue Notifications.
- POS Profiles — see POS Profiles below.
- WhatsApp Sharing — shortcut to the switch in Settings → Integrations that adds Share via WhatsApp to receipts.
Settings → Numbering:
- POS Sale / Stock Transfer numbering — configurable prefix and starting number, same convention as invoice/quotation numbering elsewhere in the app.
POS Profiles
A POS Profile is a named till setup — e.g. Store, Restaurant, Filling Station, Cement — set up in Settings → Point of Sale → POS Profiles (editing needs the Manage Item Categories permission). Each profile has:
- Item Categories — which item categories it covers. With Filter Enabled ticked, Checkout at that till only offers items in those categories (plus uncategorised items, unless Require Category is also ticked).
- Show in menu under — which menu the till's "[Profile] Checkout" entry appears in, and which menu stays highlighted while that till is open. Automatic follows the location's type: filling stations under Fuel, restaurants and hotel properties under Hotel & Hostel, everything else under Point of Sale. The other choices (Point of Sale, Fuel, Cement/Trading, Hotel & Hostel, Parts) only list menus your tenant actually has, and only matter in the business-unit menu layout — with a single Point of Sale menu, the entry appears there whichever you pick.
Assign a profile to a till in Settings → Company → Stores → Edit → POS Profile. A till with no profile shows every Product item. If a Checkout entry covers several of your tills, Checkout asks you to choose one; it won't switch tills while a sale is in progress.
Barcode labels & variant groups
From Items you can print barcode labels — 🏷 Print Label on a Product, or 🏷 Print Labels for a whole variant group or selected sizes. Choose the number of copies per item ("N each", or Match stock on hand); the price on the label is the price Checkout charges. Labels open in a print window like receipts, sized by Settings → Point of Sale → Label Printing — make sure the label stock in your printer matches.
Variant Groups (a tab on the Items page) group the sizes or colours of one product — e.g. one shoe style in sizes 38–44. Each size is still its own item with its own code, barcode, price and stock, so scanning at Checkout works exactly as normal. Inside a group you can add sizes (codes and in-store barcodes are suggested for you), link existing items, set one price for several sizes at once, and see total stock. See Items & Product Catalog →.
Roles
Two roles are purpose-built for POS, in addition to any of the general-purpose roles. On a tenant with 2+ stores, both dashboards below are scoped to the user's assigned store unless they hold branch.viewAll — see Per-user branch assignment above:
| Role | Scope | Lands on |
|---|---|---|
| POS Manager | Full till/store control — sell, void (both the last sale and earlier sales), register open/close, split-tender, Cash Out, the financially-sensitive Reports tabs (Stock Movement, Register Sessions, Profit & Loss, Reconciliation) and recording collected amounts, stock adjust and stock transfers, view Items, view/create Purchase Invoices, view/create/edit Expenses. Not broader ERP admin — no Settings access by default. | POS Manager dashboard (today's sales, sales by tender, top sellers, low-stock alerts, recent register sessions, pending TRA submissions, pending TRA portal voids) |
| POS Cashier | Deliberately the most restrictive — sell (including split-tender), Cash Out, and open/close their register, plus the Sales (their own sales only) and Expenses tabs of Reports. No void, no stock adjustments, and none of the financially-sensitive Reports tabs (Stock Movement, Register Sessions, Profit & Loss, Reconciliation) — those need pos.reports.viewFinancials, which Cashier doesn't hold by default. | A minimal shift-status screen, so they can see whether their register is already open before diving into Checkout |
See the Permissions Reference → for the exact permission grid, including these two roles alongside the six general-purpose ones.
Fiscalization
POS sales reuse the exact same TRA VFD/EFD Fiscalization integration and feature flag as Invoices — it works whether that flag is on or off for your tenant. A completed sale is fiscalized automatically when the flag is active; the receipt carries the same fiscal QR code, Receipt Verification Code, and Z-Report number an invoice does. Any sale that fails to fiscalize at the time of sale shows up in the POS Manager dashboard's Pending TRA Submissions queue for retry.
Not yet built
- Hardware integration (QZ Tray / ESC-POS bridge) — no auto-print, drawer-kick, or "No Sale / Open Drawer" action yet. Receipts and labels print via the browser's own print dialog today (a past receipt can be reprinted from POS Reports → Sales).
- Consolidated multi-branch dashboard — Reports already give per-store filtering and breakdowns; a single "all stores at a glance" rollup view doesn't exist yet.
Related
- Items & Product Catalog → — Checkout only sells Product-type items with a Selling Price; variant groups and label printing
- Filling Station → and Hotel Management → — POS at a fuel pump and at a restaurant/hotel
- Purchase Invoices → — vendor bills, with a Receiving Store selector once you have 2+ stores
- TRA VFD/EFD Fiscalization → — the fiscal receipt integration POS reuses
- Permissions Reference → — full permission grid including POS Manager and POS Cashier