AWRA OpsHub Search

One Number, Two Shapes

The till and the stock valuation once used different definitions of what an item cost. Both were defensible, both were implemented correctly, and the integrity report that compared them reported a variance that was purely a difference of opinion.

Point of Sale AWRA OpsHub Team 11 min read

There is a particular kind of bug that is not a bug in any single place. Every function is right. Every test passes. The system is simply holding two answers to one question, and something eventually compares them.

Two defensible answers

What does an item cost? There are at least two honest answers and this product held both.

The weighted average is what the units on your shelf actually cost you, blended across every purchase that contributed to them. The buying price is what the item costs to buy today, from the supplier, at the current price on the item record.

Neither is wrong. They answer different questions, and a system that uses one for valuation and the other for margin is not making a mistake so much as failing to have a conversation with itself.

Where it surfaced

On an accounting integrity screen, which compares what the ledger says the stock is worth against what the stock module says it is worth.

The ledger posts cost of sales at the weighted average. The stock side was valued at buying price. So the screen faithfully reported a variance between the books and the warehouse — a variance that did not exist in the world, and would not have been resolved by counting anything.

An integrity check comparing two definitions reports a discrepancy that no amount of investigation will ever close, because the difference is in the question rather than in the data.

The fix, and the detail inside it

One definition, in two forms — one for objects and one for aggregate queries — and five call sites moved onto it: the till's cost-of-sales posting on both the web and the API path, till margin analytics, the integrity check, and the value tile on item categories.

The definition is: use the weighted average, unless it is zero, in which case use the buying price, and otherwise zero.

That "unless it is zero" clause is the whole subtlety. A weighted average of zero does not mean the item was free. It means the item has never been costed — nothing has been received against it at a known price yet. Treating that as zero would value new stock at nothing and post a cost of sales of nothing, producing a margin of one hundred per cent on every sale of a newly-listed product.

The same item, under both bases

Received 60 at 100 Weighted average 100
Received 40 more at 150 Weighted average 120
Sold 1, cost of sales posted 120
Stock valued, old basis 99 × 150 = 14,850
Stock valued, one basis 99 × 120 = 11,880
Phantom variance removed 2,970

Illustrative figures. Nothing was miscounted and nothing was mispriced — the entire difference was which question the two sides were answering.

What was deliberately left alone

Purchase price is still used, on purpose, in procurement, quotations and requests for quotation. Those are genuinely asking a different question: not what did this cost me, but what will this cost me next.

Unifying those too would have been the same mistake in the opposite direction. The rule is not "one number everywhere" — it is "one number per question, and know which question you are asking".

Four questions about cost in any system

What basis does the margin report use?

A good answer sounds like

A named basis, and the same one as valuation.

What it actually means

Ask valuation the same question separately. Two answers is the finding, and it is common.

What is the cost of an item never received?

A good answer sounds like

Not zero — a fallback.

What it actually means

Zero produces hundred-per-cent margins on new products, which is flattering and wrong.

Can I choose FIFO instead?

A good answer sounds like

Yes, or an honest no.

What it actually means

Ours is a no — weighted average is the only basis, and there is no method setting to change.

What happens to a cost correction after the fact?

A good answer sounds like

A new transaction, or a re-costing.

What it actually means

Ours is a new transaction; there is no retrospective re-costing. Old movements keep the cost they were valued at.

Our position

One number per question, and write down which question each screen is asking. The failure mode here was not a wrong calculation — it was two correct calculations answering different questions and then being compared. That happens in every system that grows, and the only defence is the boring one: a single definition, in code, that every consumer has to go through.

Costing, precisely

What AWRA OpsHub does today

  • A single cost definition used by stock valuation, dead-stock reporting, count write-backs, till cost-of-sales posting and till margin analytics.
  • A zero weighted average treated as never-costed rather than as free, falling back to the buying price.
  • Both an object form and a SQL form of the same definition, so aggregate queries cannot drift from row-level ones.
  • Purchase price retained deliberately in procurement, quotations and requests for quotation, because those ask a forward-looking question.
  • An internal integrity screen comparing the ledger against stock, which is what surfaced the divergence.

What it does not do

  • A choice of costing method. Weighted average is the only basis and there is no setting.
  • A FIFO or specific-identification cost-flow engine.
  • Retrospective re-costing. A correction is a new transaction, not a restatement.
  • Landed cost by weight or volume — allocation is by value or quantity only.
  • Any standard-cost concept, and therefore no purchase price variance.

Not ours, by choice

  • Weighted average is acceptable under IFRS and the position is argued openly rather than presented as a limitation we are working around. A layered cost engine would touch valuation, cost of sales and every unit-cost report, and we would not build it speculatively.
  • The divergence described here was real, live, and produced a phantom variance on a screen designed to find real ones. That is the worst kind of place for it to be and it is why it is written up.
  • Nothing here is Peruvian. Peru is here as a multi-branch retail and distribution market where margin per branch is the number people argue about, and an argument about margin is usually an argument about basis.

This is scope, not a ceiling

What is not built for your market today can still be built for you

Anything described above as not built is a statement about what ships in the standard product today — not a limit on what AWRA OpsHub can do in your market. Kenya's eTIMS integration and its maintained payroll engine exist because Kenyan clients needed them and commissioned them; neither appeared by itself. The same door is open here. If the seam to a clearance provider, a supplier invoice that can be read, a limit that is not an amount, a bank or mobile money feed, a statutory return format, a rule your own operation needs that the standard one does not have, or a link to a system you already run is what stands between you and a decision, tell us and we will scope it as a build — written spec, timeline and price — before you commit to anything.

Which end of the document you stand at, and what the limit is written in

Three builds cover most of what this region exposes, and the first is a seam rather than a system. Document exchange with the authority runs through a role somebody is accredited for, so what we build is the two-way join to the provider you pick — our document handed over in the shape they expect, and the reference, status and any acknowledgement written straight back onto our record, which is what turns "which of ours are not yet cleared" into a report rather than a reconstruction. Second, reading a supplier's electronic invoice into lines that carry tax, so the purchase side holds a rate and not only an amount. Third, a limit expressed as a multiple of an index unit rather than as a sum of money, with something that actually reads the unit when it is revalued. All three are data-model changes rather than settings, and we would quote them as such.

Local payment rails, and obligations that fall on the buyer

Statement feeds and local payment rails wired into the Payments Register, alongside the buyer-side obligations this region is unusual for — an acknowledgement generated from a receiving event and transmitted, and a report of purchases received but not yet acknowledged. Receiving against the order already runs; the outbound half is the buildable part on top of it.

The operational work, which is what most commissions actually are

An extra approval stage in a chain that does not match the standard one, a custom field set on employees or assets that only your sector needs, an expiry that has to block an order rather than send an email, a report your board asks for in a shape nothing produces, or a scanner or weighbridge feeding the goods-in door. These are the commissions we are asked for most often and the smallest ones we quote — and unlike a revenue-authority pipeline, none of them waits on a regulator.

Payroll and statutory returns

A local payroll engine with income tax tables and social security contributions computed on live employee records, producing returns in the layout your authority expects rather than rebuilt each month.

Systems you already run

The accounting package, CRM, online store or custom database you intend to keep — connected through our API so a fact is entered once and appears everywhere it is needed.

How it works: you describe the requirement, we return a written scope, timeline and cost, and once agreed it is built into your environment and maintained as part of the product. No roadmap slide, and no pretending in a demo that something exists when it does not.

Tell us what you need integrated

Ask both screens the same question

Open the margin report and the stock valuation, and ask what each one thinks a single item costs. If the two numbers differ, you have found something — and it will not be in the data.

Talk about costing

Frequently asked questions

Why is weighted average the only option?

It is IFRS-acceptable and it is the basis every part of this product now agrees on. Adding a method choice means every valuation, cost-of-sales and unit-cost path learns about layers, which is a project rather than a setting — and the gap file says not to build it unless a deal turns on it.

What if my buying price is more current than my average?

It is, and that is exactly why it stays in use for procurement and quoting. It is the right number for deciding what to pay next and the wrong one for valuing what you already hold.

Does the till post cost of sales at the moment of sale?

Yes, at the shared basis, on both the web and API paths. That is the change that made the integrity check meaningful — before it, the two sides of that comparison were not comparable.

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