Storing prices with tax and currency: how to get totals right for every shop
A number in a price column means nothing on its own. Which currency, whether tax is inside it, which rate, and whether shipping is part of the total are four separate facts, and every one of them has to come from the shop.
Every multi-shop system eventually discovers that €100 is not a fact. It is a number attached to at least four other facts, and a system that stores only the number will be wrong for the second shop that signs up — usually in reporting, quietly, months later.
The fix is boring and structural: read the shop's own settings, store them alongside the money, and never infer.
The four facts that travel with a price
- Currency. Stored as an ISO code on the order, not derived from the shop's current setting — shops change currency, and historical orders must keep theirs.
- Whether the displayed price includes tax. A shop configured to show inc-VAT prices and one showing ex-VAT both put 100 in the field and mean different totals.
- The rate actually applied, per line, at the time of the order. Rates change, and recomputing an old order at today's rate is how a report stops matching the accounts.
- The base country. Which determines the default rate and, for cross-border sales, which country's rules applied.
None of these are things to ask the merchant during setup. They already exist in WooCommerce, and asking is a second place to be wrong.
The total that means nothing
Store the components and compute what you need:
- Goods total — the line items, before shipping. This is what a campaign actually sold.
- Shipping total and shipping tax, separately. "Did this order ship free" and "was shipping taxed" are different questions with different answers.
- Discount total, so a margin conversation is possible later.
- Refunded amount, per order, so revenue can be reported net without recomputing from scratch.
Report revenue on goods total, net of refunds. That number is comparable between campaigns, between months and between shops. The order total is not.
Net of tax, when the shops disagree
If one shop shows prices with tax included and another does not, "revenue" means two different things unless you normalise. Decide once, globally, which you report — net of tax is the usual choice because it is what the business earns — and convert consistently.
That conversion needs the per-line rate that was applied, not a shop-level default. An order containing a standard-rated and a reduced-rated item has two rates in it, and a single shop-wide rate will quietly misstate both.
Multi-currency without a reporting mess
- Store the order in its own currency, always, unchanged.
- Also store a converted amount in your reporting currency, at the rate on the order date, computed once and never recalculated.
- Record the rate used alongside it. Without this, no one can ever reconcile a report to the accounts.
- Never convert at query time against today's rate. Last year's revenue will move every day, which makes every historical comparison meaningless.
Displaying it back to the shop
Formatting is the visible half of the same problem. Currency symbol placement, decimal separator and thousands separator are locale properties, not preferences, and a hard-coded € or a hard-coded comma is a bug for the next shop.
- Format from the shop's own locale and currency.
- Say explicitly, on any screen showing revenue, whether the figure includes tax.
- When showing a comparison across shops in different currencies, label the conversion and its date rather than presenting a single total as if it were native.
Sources and further reading (4)
- European Commission — VAT rules and rates
- EU — VAT One Stop Shop
- WooCommerce — Tax settings documentation
- ISO 4217 — Currency codes
Checked on 23 September 2026. Provider prices, mailbox rules and legal guidance change — verify anything you plan to act on.
Currency and tax that come from the shop itself
Auralata reads currency, tax treatment, every configured rate, base country and units from WooCommerce on every pair — so a euro in one shop's report means the same thing as a euro in another's.