A quotation’s total prints in the right format — thousands separator, two decimals, a currency symbol — and it’s still wrong, because that symbol is the company’s home currency, not the customer’s. Nothing errored. Nothing looked obviously broken. The number and the format are both individually correct; the currency identifying what they mean is not.

The short version: a QWeb monetary widget doesn't know which currency a number is in unless you tell it explicitly via t-options-display_currency — without it, Odoo doesn't error, it silently falls back to the company's own currency, which is exactly the wrong answer on any document involving a foreign customer or supplier.

The widget formats; it doesn’t know the currency on its own

A monetary field on a model is really two things working together: the numeric value itself, and a separate currency_id field on the same record (or a related one) that says what currency that number is denominated in. The widget’s job in a report is purely presentational — thousands separators, decimal places, symbol placement — and none of that is possible without knowing which currency to format for:

<span t-field="doc.amount_total" t-options-widget="monetary" t-options-display_currency="doc.currency_id"/>

display_currency is the option doing the actual work here — it’s what tells the widget which currency’s symbol and decimal precision to use. Leave it out, and the widget still renders something — a number, a symbol, right-looking formatting — it just silently reaches for the company’s own currency instead of the document’s, because it needs some currency to format against and that’s its fallback. There’s no error, no warning, nothing in the rendered output that looks wrong on its own — the format is entirely self-consistent, just denominated in the wrong currency.

Watch out: this is exactly why it's easy to ship — every internal test against the company's own home currency renders correctly, because the fallback silently happens to match. The bug only surfaces on the first real document involving an actual foreign currency, often well after the report template has already gone to production.

The trap on models with more than one monetary field

A model with two monetary fields meant to hold values in genuinely different currencies can’t safely share one currency_id field between them — a single currency field can only describe one of the two correctly. Each monetary value that can be in a different currency from the others on the same record needs its own accompanying currency reference, and the report’s display_currency for each field needs to point at the matching one, not just whichever currency field happens to be nearby.

The other three real monetary options

display_currency is the one that actually determines correctness, but three more t-options genuinely change a monetary widget’s output, each narrower than it looks — the full widget reference beyond monetary (contact cards, images, dates) is covered in the QWeb Report Snippet Generator’s own field widget reference:

OptionWhat it actually does
display_currencyWhich currency’s symbol/precision to format with — the one covered above.
from_currencyThe source currency the raw value is actually stored in, when it differs from display_currency — triggers a real currency conversion at render time, not just a symbol swap.
dateThe exchange rate date to use for that conversion, when from_currency and display_currency differ — omitted, it defaults to today, which is wrong for a document dated in the past.
company_idWhich company’s own configured exchange rates to use for the conversion, in a multi-company setup where rates aren’t shared.

from_currency is the one most often needed alongside display_currency and most often forgotten: without it, the widget assumes the stored value is already in display_currency and only formats it — it does not convert. If the underlying value is actually stored in the company’s currency but needs to display in the customer’s, both from_currency and display_currency need to be set, or the number itself (not just its symbol) will be wrong.

Quick reference

SymptomCauseFix
Right number, wrong currency symbolNo display_currency set — silently defaulted to company currencyAdd t-options-display_currency pointing at the record’s real currency field
Wrong number and wrong symbolfrom_currency missing where an actual conversion was neededAdd t-options-from_currency alongside display_currency
Correct on some documents, wrong on othersThe record’s own currency_id differs between documents and isn’t the one referencedConfirm which currency field actually varies per record and reference that one, not a fixed company default
Right currency, wrong historical amountConversion using today’s rate instead of the document’s dateAdd t-options-date pointing at the document’s own date field

Frequently asked questions

Does the same fallback behavior apply to the monetary widget in form/list views, or just reports?

The underlying field and currency-resolution mechanics are the same ORM-level behavior everywhere the field is displayed — reports just make the silent fallback easier to miss, since there's no live UI context reminding you which currency should be expected the way a form view next to a customer record often does.

What happens if display_currency points at a field that doesn't exist on the record?

The expression fails to resolve, and — matching QWeb's general behavior for an unresolvable expression — the widget falls back to an empty or placeholder-like result rather than guessing; it does not silently substitute a different currency field on its own.

Is the company-currency fallback specific to reports, or true of the monetary field type generally?

It reflects a general truth about the monetary field type in Odoo: a monetary value is only ever meaningful together with a currency, and when no explicit currency is available in a given context, the company's own currency is the ORM-wide default assumption — reports simply have no separate safeguard against that default being the wrong one for the document.

Should I always set all four monetary options to be safe?

No — display_currency is worth setting explicitly on essentially every monetary field in a report; from_currency, date, and company_id only matter when an actual cross-currency conversion is happening, and setting them where no conversion occurs adds nothing.

How do I confirm which currency a field is actually using before fixing the widget?

Check the field's definition in the model (or in developer mode's field inspector) for which currency_id-typed field it's paired with — Odoo doesn't infer this automatically for you at the widget level, it's a relationship defined once in the model and referenced explicitly in every report that displays that value.

Further reading

And on this site: the Report Builder’s Properties panel exposes all four monetary options (display_currency/from_currency/date/company_id) directly, matching the real ir.qweb.field.monetary option set rather than a simplified subset — build or audit a monetary field’s widget options there without hand-writing the XML.