Ask a finance team about Odoo POS reporting and you hear the same complaint. The numbers exist. Getting them into one defensible figure is the problem.
Odoo reports the point of sale session by session — close a register, post the entries, read that summary. Fine for one shop with one till. It stops working the moment you run six branches in three countries and someone asks what the group took yesterday. Odoo ships no consolidated Z-report, so the work falls to whoever holds the spreadsheet.
Octivex Retail Analytics ends that rebuild. It is a retail analytics dashboard for Odoo POS that reports across companies, branches and dates in one screen, with every figure traceable to a posted Odoo record.
Checked by Bookkeepers, Not Just Built by Developers
Most POS dashboards are designed by engineers asking what looks good on a chart. This one was reviewed line by line with accountants and bookkeepers — people who have to explain a number, not admire it.
A developer asks whether a query is correct. A bookkeeper asks the harder one: which ledger entry does this tie back to, and what happens at month end? Every metric had to survive that before it shipped. It shows in the sales summary, which walks the gross-to-net chain in ledger order — the consolidated Z-report Odoo does not provide:
Gross Sales → Sales Discount → Sales Refunds → Net Sales → Taxes → Net Sales With Tax → Tips → Grand Total
Every intermediate line is visible, so when Grand Total disagrees with the bank the disagreement is already isolated to a row instead of buried in an aggregate.
The Numbers Reconcile Exactly, by Design
Accuracy here is not a claim about careful arithmetic. It is a consequence of how the module is built.
The dashboard stores nothing — no extra tables, no cached totals, no nightly rebuild. Every figure is computed at read time through Odoo's own ORM, from the same posted records your accountant reports on. A reporting layer holding its own totals can disagree with the accounts, and eventually will — after a refund is reversed, a session reopened, an entry corrected in the back office. This one has nothing to disagree with: correct an entry in Odoo and the next refresh shows it, because the dashboard was never showing anything else.
The Trading Day Starts When You Say It Does
A restaurant that stops serving at 2am does not have two trading days. It has one, and the calendar disagrees.
Most tools split those sales across midnight, corrupting every day-over-day comparison a manager makes and every like-for-like a bookkeeper runs afterwards. Ours uses a configurable day-start hour, 07:00 by default, so a shift running past midnight lands on the day it was actually traded. A small setting, and the difference between a report an operator trusts and one they stop opening.
Cash, Voids, Payments and Discounts
Sales figures tell you how trade went. Cash and void figures tell you whether anything went wrong.
The cash panel reports opening float, cash payments in, adjustments in and out, refunds and closing balance — the drawer question, answered. The void panel reports amount, order count, item count and void amount as a percentage of sales. One voided order is routine; a branch consistently voiding more than its peers is a control issue.
The payment method report splits every method into in-count, amount, tips, out-count, refunds and total, so a card settlement arriving in the bank as one figure ties back to the day's trading. Discounts report separately — among the easiest ways for margin to disappear quietly.
The Employee Table: Sales per Hour, and Profit per Hour
Ask a store manager what they want from a sales by employee report and the answer is consistent: sales per hour, transactions, average basket, and some sense of who is profitable. Most POS reports deliver the first three. This one reports all of it, per person, per branch, per period:
| Hours | worked in the period |
| Sales and % of sales | contribution to the branch total |
| Refunds and Discount | given by that employee |
| Cost and Profit | with profit % |
| Sales / hour | the standard productivity measure |
| Profit / hour | the one that actually decides scheduling |
| Transactions and Avg transaction | transaction count and ATV |
| Qty and Qty / transaction | units per transaction (UPT) |
Profit per hour is the column worth pausing on. Ranking staff by sales rewards whoever worked the busy shift; ranking by profit per hour compares people against the hours they were paid for. Most cashier reports cannot produce it, because they never carry cost — which is also why they cannot show margin.
Read alongside ATV and UPT it separates the two kinds of strong performer: the one who serves more people, and the one who sells more to each. Those need different coaching.
One honest dependency: hours come from your Odoo attendance records. If staff are not clocking in and out, the per-hour columns have nothing to divide by.
Alongside them sit the tables an operations lead actually opens — top products, top customers, top orders and top sessions — plus an hourly sales trend chart. Ranking sessions rather than days shows which shift, at which branch, under which manager produced the result. Every table sorts, searches and exports to Excel.
Above-Store Reporting, With Branch-Level Access
Multi-unit operators call this above-store reporting: consolidated visibility over locations, not one report per till.
Filters cover company, branch, date and time, so one screen serves a branch manager checking a site and a group finance lead comparing all of them. Crucially, access is enforced per branch — a manager whose permissions cover one store cannot open another store's dashboard or export its data. In a franchise that is the precondition for letting franchisees near the system at all.
Comparisons run like-for-like against the same weekday a week earlier. Tuesday against Monday tells you nothing about a business whose week has a shape.
It runs this way in production today: a restaurant franchise across the GCC, the United Kingdom, Pakistan and Canada; a retail group across Egypt, Morocco, the United Kingdom, Saudi Arabia and the United Arab Emirates. Different currencies, different tax treatments, one reporting definition — and a dashboard closing tills nightly on four continents has met far more edge cases than one running in a single shop.
Beyond the Till
The POS dashboard is one of several in the module, sharing its filters, definitions and access rules. A daily sales report carries the finance view — net sales against target, COGS and staff cost each as a percentage of net sales, month-to-date by branch, bank position — with staff cost from real attendance records against hourly rates, not a flat estimate. An inventory dashboard covers stock valuation, stockouts, wastage and slow movers; for a food operator, wastage and COGS percentage read together are the fastest route to an explanation when margin moves.
What It Runs On
It supports Odoo 17, 18 and 19, Community and Enterprise, and installs alongside your existing point of sale without changing how your tills operate. There are no external Python packages to install — a common reason competing dashboards fail on Odoo.sh and SaaS, where you cannot add arbitrary dependencies.
If your close means exporting sessions into a spreadsheet before anyone can say what the group sold yesterday, that is the work this replaces.
