Hybrid US Sales Tax engine for Odoo: resolves the combined state + county + city + district rate for a ZIP code, applies it to sale orders and invoices, and keeps a full audit trail of every calculation.
Resolution order: local rate database first, external API providers as
fallback (configured independently in their own
l10n_us_sales_tax_provider_* modules — this module never imports
their code directly). Tracks nexus per state, taxability per product
category, and caches external API responses to control call volume.
Important
This is an alpha version, the data model and design can change at any time without warning. Only for development or testing purpose, do not use in production. More details on development status
Table of contents
The local provider needs three things before it can resolve a tax rate for a ZIP code: a Jurisdiction (county/city), a ZIP Mapping pointing that ZIP to the jurisdiction, and a Tax Rate on that jurisdiction. None of these ship pre-loaded — only product categories and the provider registry are seeded on install.
US Sales Tax → Rate Database → Import Rates always requires a file upload — there is no "instant, no file" option in the wizard.
- Florida DOR: upload the official Master Address List CSV from https://pointmatch.floridarevenue.com/General/AddressFiles.aspx (select a county and effective date, then download). This creates the jurisdiction, the rate, and the ZIP mapping for every row — full ZIP-level resolution.
- Generic CSV (any state): any file with
ZIP,COUNTY/CITY, and a rate column works the same way.
For testing a single ZIP without downloading a file, create the three records by hand under US Sales Tax → Rate Database:
- Jurisdictions — name, type (county/city), state.
- ZIP Mappings — the ZIP code, pointing to that jurisdiction.
- Tax Rates — the actual rate values on that jurisdiction.
Creating a Nexus record (US Sales Tax → Configuration → Nexus) only marks that the company has a legal obligation to collect tax in that state — it does not create or require any jurisdiction, ZIP mapping, or rate. Both are needed independently before a sale order calculates a non-zero local tax.
When a line ends up with 0% tax, the engine always assigns a real
account.tax record rather than leaving the line untaxed:
- Exempt product category or no nexus in that state — assigned the
shared
US Sales Tax - Exempt (0%)tax (one tax for both reasons, across all states). - A state with a genuine 0% combined rate (e.g. Oregon, Montana —
states with no sales tax at all) — assigned
US Sales Tax {state} 0%, the same per-state-and-rate tax used for any other rate.
This is deliberate: an empty tax_id is indistinguishable from "tax
was never calculated" on an invoice or in a tax report filtered/grouped
by account.tax/account.tax.group. An explicit 0% tax record
shows that the line was evaluated and a deliberate "no tax due"
determination was made — the kind of audit trail a sales-tax-exempt line
should leave behind.
The specific reason for a 0% line (which product category, which
state, nexus or no nexus) is not encoded in the tax's name — that level
of detail already lives on us.tax.calculation.log, one record per
calculation. The tax itself only needs to answer "was this evaluated,
and is it taxable" at a glance.
Migration note: if you had ad-hoc reports filtering for lines with
no tax_id/tax_ids at all to flag "missing tax" cases, those
lines will stop matching once they carry the explicit 0% tax — this is
the intended effect of this change, not a regression.
Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed feedback.
Do not contact contributors directly about support or help with technical issues.
- Binhex
- Carlos R. Rodriguez <c.rodriguez@binhex.cloud>
This module is maintained by the OCA.
OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use.
Current maintainer:
This module is part of the OCA/l10n-usa project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.





