AWRA OpsHub Search
Accounting controls

A number that is confidently wrong is worse than one that is missing.

A blank cell gets investigated. A total that is neatly formatted, carries no warning and happens to be nonsense gets pasted into a board pack. Two of the three controls on this page were written because we shipped exactly that, found it, and fixed the class rather than the instance — which is the part worth telling you about.

The defect that produced the rule

Our aging report summed dollars into shillings and printed the result with no currency on it.

It had been doing it for a while, and nothing looked wrong. The report ran, the columns lined up, the total was formatted to two decimal places like every other total in the product. It was only found when a workspace that trades in more than one currency looked closely at a figure that felt slightly high. The sweep that followed found the same shape on the dashboard, in the top-customers report and in credit-hold exposure — all of them sitting on one shared helper that assumed every amount was in the same currency and had two decimal places.

Why nothing caught it

Every workspace we had looked at closely traded in one currency, and in one currency the broken code and the correct code produce identical output. The bug was invisible from the inside and obvious from a market we had not sat in. That is the usual shape of this class of defect, and it is why the fix was a rule rather than a patch.

Why a converted total would not have fixed it

The tempting repair is to convert everything to one currency and add it up. But a converted total needs a decision about which rate and as at when; it moves between two viewings of the same closed period; and it cannot be reconciled against any ledger, because no ledger holds it. You would have replaced a wrong number with an unstable one.

What replaced it

One rule, applied everywhere a single money figure is shown: display the largest single-currency total, label it with its code, and disclose how many other currencies sit behind it. No rate is required, the figure is true at every viewing, and the reader knows there is more — which the old single number never told them.

Rule one

Never add unlike currencies. Never convert to make them like.

The rule has two halves and the second is the one people argue with, so it is worth being explicit about what it costs and what it buys. It costs you a single all-in number. It buys you a number that can be reconciled, that does not move, and that nobody has to caveat in a meeting.

Where a single figure has to be shown

A dashboard tile, a summary line, a card at the top of a report — anywhere the layout has room for one number. The largest single-currency slice leads, labelled, with a disclosure of the remainder alongside it.

Any surface that knows the workspace's base currency passes it through, and that currency then leads whenever it is present. This matters more than it sounds. Without a rate the only available ordering is by nominal amount, and nominal amounts are not comparable: 215,000 shillings sorts above 38,400 dollars while being worth a fraction of it. Leading with the currency the reader thinks in is both more meaningful and more stable, because it does not reshuffle as balances move.

Where a whole report is involved

A report is scoped to one currency rather than summarised across several. You choose the currency, the rows are the rows in that currency, and the totals at the bottom are real totals of real rows. Running it three times for three currencies gives you three reports you can each hand to somebody, which is more useful than one you have to explain.

The nominal ordering described opposite is only ever used to sequence the disclosed remainder. It is never used to claim one exposure is larger than another, because without a rate that claim cannot be made honestly.

If you want a consolidated figure across currencies at a rate you control, that is a legitimate thing to want and it is in the ledger below as work we would do — with the rate and its as-at date stored on the record, so the number can be reproduced later. What we will not do is produce it silently.

Rule two

“UGX 1,234.56” is not a rounding infelicity. It is an amount that cannot exist.

Money was stored at two decimal places in 104 columns and formatted with two decimal places everywhere, on an assumption nobody had ever written down: that every currency has two. Of the 137 currencies the product ships tax profiles for, 105 do. 32 do not, and they miss in both directions.

26

currencies at zero places

The larger half, and the one nobody had noticed. It covers 38 of the 188 country rows we ship. XOF alone is the eight UEMOA states and XAF the six CEMAC states — so this is most of francophone West and Central Africa, plus Japan, Korea, Vietnam, Indonesia, Iceland and Hungary.

ALL BIF CLP COP DJF GNF HUF IDR IQD ISK JPY KMF KRW LAK LBP MGA MMK PKR PYG RWF SOS UGX VND VUV XAF XOF

6

currencies at three places

The half that had been noticed, because it is the one that visibly loses money. A Tunisian tax total of 201.900 was being stored and displayed as 201.90 — a real difference, silently discarded on every line.

BHD JOD KWD LYD OMR TND

105

currencies at two places

The assumption, which was right three-quarters of the time. Being right three-quarters of the time is what let it live for as long as it did: any single-market workspace could run for years without meeting the other quarter.

The place count comes from the internationalisation data already bundled with the framework rather than a table we keep by hand, because a hand-kept list is a second copy of a fact somebody else maintains. One consequence worth knowing before you check our figures against a standards document: that data answers “how many digits is this currency written with in practice”, which for a few currencies with an inflated-away subunit is fewer than the formal standard still assigns. The sharpest case is the Iraqi dinar, formally three places and written with none.

Rule three

There are five ways to pay a supplier. A control on one of them is theatre.

This is the control that finance teams ask for and that is most often built wrongly: refuse to release payment when the goods received do not agree with the order. The wrong way to build it is a check in the screen where you noticed the problem. The other four routes stay open, and whoever needs to get paid finds one.

WebPay from the purchase order
APIProgrammatic release
ManualRecording a payment made elsewhere
M-PesaB2B and B2C transfers
PaystackCard and bank rails

one gate, one definition of “may this be paid”

Those five paths write into two different ledgers, which is the other half of why a per-screen check could never work. Every one of them now calls the same gate before releasing anything, so the answer to “can this be paid” is defined in one place and cannot differ by route.

What the gate decides

One of these blocks by default and one only warns, and we would defend the difference.

A control that is right in principle and wrong on the first day gets switched off on the second. These defaults are chosen so that a working business can install the product on a Monday without anything legitimate being refused.

Blocks

The received quantity disagrees with the order

This is the control being asked for. What arrived does not match what was ordered, so the invoice sitting behind it is not yet trustworthy and the payment does not go. It blocks by default, on every one of the five routes.

Warns

Nothing has been received yet

Deposits, prepayments and proforma terms are legitimate and common, and a product that refused them outright would break working businesses on the day it shipped. So this warns rather than blocks — and an organisation whose policy is that nothing is paid before receipt turns the setting on and it blocks.

Overrides

Somebody decides to pay past a failed match

Possible, and it should be. It requires a permission that is deliberately not the same one as approving a purchase order — approving an order is routine work, paying past a failed match is not, and collapsing the two would hand the second to everyone who legitimately has the first. It also requires a written reason, and it is stamped with who did it and when.

Read this one carefully

Closing a period here records that you closed it. It does not yet refuse a backdated entry.

There is a period close in the product. It holds the month, the status, who closed it and when, any notes they left, and — if the month was reopened — who reopened it and when. That is a genuine and useful control record, and for a great many workspaces the discipline of having to reopen a month in front of colleagues is the whole of what they needed.

What it is

A soft close. The state is recorded per month, per workspace, with a full history of closes and reopens that you can read back. Nothing about the record is guessed or derived; each row is an action somebody took.

Used as intended it does real work: it establishes when a month was declared final, gives you an audit answer to “when did we close January”, and makes a reopen a visible event rather than a quiet one.

What it is not, and we are saying so here rather than in a footnote

Nothing consults that record before writing a journal entry. A backdated entry into a closed month is not refused today — it is posted, and the close record sits alongside it saying the month was closed. If your control requirement is that the system must refuse, this does not meet it yet.

A hard lock is a well-understood piece of work on top of a record that already exists, and it is in the ledger below. We would rather tell you now than have you discover it in an audit.

This is the sort of thing that normally reaches a customer as “period close” on a feature list and is understood as a lock. If you are comparing products on this row, ask each of them the same question: does closing a period refuse a posting into it, or record that it was closed?

Before you quote this to a controller

The finance-control rows, answered exactly.

Accounting controls — what the arithmetic actually does

What AWRA OpsHub does today

  • One money figure is never a sum of unlike currencies — the largest single-currency total leads, labelled, with the remainder disclosed rather than absorbed.
  • No silent conversion anywhere, so a figure reads the same at every viewing and can be reconciled against a ledger that actually holds it.
  • Decimal places read from the currency, across all 137 shipped currencies — 26 at zero places, 6 at three, 105 at two.
  • A base currency leads when the surface knows one, so ordering is meaningful rather than an artefact of nominal size.
  • A single payment gate across all five payment routes and both payment ledgers, with one definition of whether an order may be paid.
  • A quantity discrepancy blocks payment by default; payment before receipt warns by default and blocks when you turn the setting on.
  • Override of the payment gate behind its own permission, separate from purchase-order approval, requiring a written reason and stamped with who and when.
  • A period close record holding the month, the status, who closed it, who reopened it, when, and their notes.
  • A hash-sealed audit trail underneath all of it, with no delete button in the interface.

More we can add to your workspace

  • A hard period lock that refuses a posting into a closed month, turning the close record we already keep into an enforced boundary.
  • A consolidated multi-currency total at a rate you control, with the rate and its as-at date stored on the record so the figure can be reproduced months later.
  • Automatic revaluation of open foreign-currency balances at period end, with the gain or loss posted for you.
  • Segregation-of-duties rules across finance actions, refusing a role that could both raise a payment and release it.
  • Approval routing by value, where an amount over a threshold you set has to collect a named second signature before the payment gate is even consulted.
  • A maker-checker step on journal entries, so an entry is drafted by one person and posted by another.
  • Recurring journal templates for the accruals and prepayments that are the same every month.
  • A close checklist that tracks which reconciliations are done before the month can be declared final.

Where we point you to a specialist

  • We will not decide whether a charge is recoverable, deductible or capital. That is an adviser's judgement about your circumstances, and a software vendor willing to make it in a sales meeting is selling you a liability rather than a feature.
  • We point you to your accountant on which basis of accounting your figures should be prepared on. The system records what happened and when; how that is presented in a statutory account is their determination.
  • We will not sign a statutory return on your behalf. Where we file to a revenue authority — Kenya's eTIMS is the live example — we transmit what you issued and record what came back, and the declaration remains yours.
  • We will not produce a single all-in figure across currencies without a rate you chose. Not because it is hard, but because the resulting number cannot be reconciled to anything and reads as though it can.

Everything in the middle column sits on top of controls that already exist — the close record, the payment gate, the currency layer. If one of those rows is the one your controller keeps asking about, tell us and we will scope it.

Help Center

Need a quick answer while you read?

Run inventory, procurement, assets, sales, and field work with approved AWRA guidance for setup, migration, integrations, security, pricing, and support.

Search all approved AWRA public help articles.

Open Help Center