Why Utility Billing Is Harder Than It Looks
A bill is a meter reading multiplied by a rate. That description survives about ten minutes of contact with a real housing society. Here is what actually sits between a meter and a correct bill.
A utility bill looks like arithmetic. Take this month's meter reading, subtract last month's, multiply by a rate. Print it.
That description survives about ten minutes of contact with a real housing society.
We build and run HUBS, a utility billing system for residential societies. This is what actually sits between a meter and a correct bill — written down because we have never found anyone else willing to write it down.
One society is not one tariff
The first assumption to go is that a society has a rate.
A society has property types, and each one bills differently. Ours handles nine — domestic, commercial, shops, un-built plots, internal connections, temporary domestic, temporary commercial, and two flavours of net-metered. An un-built plot has no consumption but still owes a fixed charge. A temporary commercial connection bills at a different rate to a permanent one. A shop is not a house.
So a billing engine cannot hold one formula. It holds a pipeline per property type, and each pipeline references monthly variables — the per-unit electricity tariff, the fuel price adjustment, the television fee — that change every month for everyone at once.
We evaluate those formulas in a sandboxed expression evaluator rather than hard-coding them, because the society's accountant needs to change a rate in March without waiting for a developer.
Net metering is not "subtract what they exported"
Once a society has solar, the arithmetic stops being arithmetic.
A net-metered consumer both imports and exports electricity, at different rates. Export is capped seasonally — the cap is not the same in June as in December. There is an administrative deduction. And crucially, surplus does not vanish at month end: it accumulates as a credit balance in rupees, carried forward, drawn down against future bills.
That means a net-metering bill is not a calculation over one month's readings. It is a calculation over a running ledger that has to survive years of monthly cycles without drifting by a rupee.
Payment is where most systems quietly break
Generating a bill is the easy half. Matching a payment to it is where billing systems fail in ways nobody notices for months.
Residents pay through a bank aggregator, over the counter at several different banks, and in cash. The aggregator sends a file. Each bank sends a different file, with different columns, different header rows, and no shared identifier.
So payment import needs:
- Consumer matching by fallback, not by one key. We match on four priorities in order, because the reference number is missing more often than anyone admits.
- Bank deposit files matched by reference, meter number, or house and plot — whichever the bank actually supplied.
- Configurable column mapping and header offsets per bank, because a bank will change its export format without telling anyone.
- Oldest-bill-first allocation. When a resident pays a lump sum against four months of arrears, the money has to land on the oldest bill first, and the remainder has to become advance credit rather than disappearing.
Get allocation wrong and the ledger looks fine while every individual account is subtly incorrect.
The part that matters most is the part nobody asks about
Every system above produces numbers. The question a society committee will eventually ask is: can these numbers be trusted?
Our billing and formula audit records are create-only, enforced in the ORM rather than by policy. They cannot be edited or deleted — not by a clerk, not by an administrator, not by us. A correction is a new entry; the original stays visible.
The formula logic is version-locked, so a bill issued eighteen months ago can be re-derived under exactly the rules in force when it was issued. When a resident disputes a charge from last year, the answer is not "our records show" — it is the actual calculation, with the actual rates, as they stood that day.
We also round every computed amount to a whole rupee through a single shared function rather than at each step. That sounds pedantic. It is the difference between a ledger that reconciles and one that is out by eleven rupees for reasons nobody can reconstruct.
Why this is worth writing down
None of the above is exotic. It is the ordinary reality of billing a few thousand households, and it is invisible until you are inside it.
It is also why "we'll just use a spreadsheet" holds up for about a year, and why replacing that spreadsheet is not a data-entry exercise. The complexity is not in the arithmetic. It is in the exceptions, the reconciliation, and the ability to prove — months later, to a sceptical committee — that a number was right.
If you run a society and any of this sounds familiar, tell us what you are dealing with. We will tell you honestly whether we are the right fit.
Need Odoo help for your business?
Tell us about your operation and we'll map out a solution.