Skip to content

[18.0][ADD] l10n_us_sales_tax_engine: Hybrid US Sales Tax Engine#173

Open
crrodrigueztrujillo wants to merge 1 commit into
OCA:18.0from
BinhexTeam:18.0-add-l10n_us_sales_tax_engine
Open

[18.0][ADD] l10n_us_sales_tax_engine: Hybrid US Sales Tax Engine#173
crrodrigueztrujillo wants to merge 1 commit into
OCA:18.0from
BinhexTeam:18.0-add-l10n_us_sales_tax_engine

Conversation

@crrodrigueztrujillo
Copy link
Copy Markdown

@crrodrigueztrujillo crrodrigueztrujillo commented May 20, 2026

Summary

This PR adds l10n_us_sales_tax_engine, a provider-agnostic hybrid sales tax
calculation engine for all 50 US states, developed by @BinhexTeam.

  • Local tax rate database (Florida DOR seed data — 67 counties) queried first
    for zero-latency lookups
  • External API fallback chain: ZipTax → API Ninjas → TaxJar
    (priority-ordered, skips providers that have exhausted their monthly limit)
  • Response cache with configurable TTL (default 30 days) to minimize API calls
  • Full immutable audit log per calculation (source, rate breakdown,
    provider, address)
  • Nexus management per company/state (economic nexus threshold support)
  • Product fiscal categories: TANGIBLE, SERVICE, FOOD, MEDICINE, DIGITAL,
    SHIPPING, EXEMPT
  • Sale Order and Customer Invoice integration — auto-calculates on confirm
  • Internal REST endpoints (/api/v1/us_tax/calculate,
    /api/v1/us_tax/rate_lookup)
  • Provider-agnostic architecture — new providers can be added without touching
    the engine core

Test plan

  • Enable engine in Accounting → Configuration → Settings
  • Configure nexus states
  • Sale Order with US address → Calculate US Tax → verify Calculation Log
  • Fallback chain: disable local provider → confirm API provider used
  • Cache: second calculation for same ZIP → source = cache
  • Exempt rule: NY services → source = exempt_rule, tax = 0
  • Import Florida DOR CSV via Configuration → Import Rates

Screenshots

11 screenshots included in static/description/ showing settings, menu,
nexus, calculation logs, providers and tax rates.


Contribution by Carlos R. Rodriguez — @BinhexTeam

@OCA-git-bot OCA-git-bot added series:18.0 mod:l10n_us_sales_tax_engine Module l10n_us_sales_tax_engine labels May 20, 2026
@rrebollo
Copy link
Copy Markdown

@crrodrigueztrujillo please squash your commits into the first one.

@rrebollo
Copy link
Copy Markdown

@crrodrigueztrujillo please prefix the PR name with the targeted version, like "[18.0] [ADD] ..."

Copy link
Copy Markdown

@rrebollo rrebollo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First of all, thank you for the effort and value of this contribution to the OCA ecosystem, and especially for the US localization space.

I tried to perform a thorough review, but with more than 5k added lines it becomes very difficult to properly assess all aspects of the implementation. With that in mind, I wanted to share a couple of broader considerations beyond implementation details:

  • Splitting the solution into multiple addons could help significantly from a review and maintainability perspective by reducing the volume and scope of each component. Whether this also brings functional benefits in terms of avoiding unnecessary installations is something I cannot properly judge from my side.

  • I would also encourage considering reuse of patterns and solutions that the community has already adopted for common problems, such as connector, connector_importer, component, or queue_job. From my own experience, I know these frameworks are not always well documented and require a certain technical background, so sometimes reimplementing things from scratch feels simpler and faster. However, over time, solutions that initially seemed sufficient can start growing organically until they become difficult to maintain or extend.

I would be interested in hearing your thoughts on these points.

Once again, thank you for the contribution.

Comment thread l10n_us_sales_tax_engine/__manifest__.py Outdated
Comment thread l10n_us_sales_tax_engine/setup.cfg Outdated
Comment thread l10n_us_sales_tax_engine/models/us_tax_api_cache.py Outdated
Comment thread l10n_us_sales_tax_engine/models/us_tax_api_cache.py Outdated
Comment thread l10n_us_sales_tax_engine/models/us_tax_api_cache.py Outdated
Comment thread l10n_us_sales_tax_engine/models/us_tax_zip_mapping.py
Comment thread l10n_us_sales_tax_engine/models/us_tax_import_batch.py
Comment thread l10n_us_sales_tax_engine/models/us_tax_rate.py Outdated
Comment thread l10n_us_sales_tax_engine/models/us_tax_rate.py Outdated
return specific
# Fallback to generic rate (no category)
return self.search(
domain + [("product_tax_category_id", "=", False)],
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
domain + [("product_tax_category_id", "=", False)],
domain,

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied. Also updated the test fixtures to align with the simplified lookup logic.

@usamahassan-rt
Copy link
Copy Markdown

What about california ?? CDFTA apis are best source ?

@crrodrigueztrujillo crrodrigueztrujillo changed the title [ADD] l10n_us_sales_tax_engine: Hybrid US Sales Tax Engine [18.0][ADD] l10n_us_sales_tax_engine: Hybrid US Sales Tax Engine Jun 1, 2026
@crrodrigueztrujillo crrodrigueztrujillo force-pushed the 18.0-add-l10n_us_sales_tax_engine branch 3 times, most recently from 28408e1 to 8614b75 Compare June 1, 2026 14:02
Hybrid sales tax calculation engine for all 50 US states.

- Local rate database (Florida DOR seed data, 67 counties)
- External API fallback chain: ZipTax > API Ninjas > TaxJar
- Response cache with configurable TTL (default 30 days)
- Immutable audit log per calculation
- Nexus management per company/state
- Product fiscal categories: TANGIBLE, SERVICE, FOOD, MEDICINE, DIGITAL, SHIPPING, EXEMPT
- Sale Order and Invoice integration with auto-calculation on confirm
- Internal REST endpoints for external system integration
- Provider-agnostic architecture
@crrodrigueztrujillo crrodrigueztrujillo force-pushed the 18.0-add-l10n_us_sales_tax_engine branch from 8614b75 to 6140ec9 Compare June 1, 2026 14:34
@crrodrigueztrujillo
Copy link
Copy Markdown
Author

Done! All commits squashed into one.

@crrodrigueztrujillo
Copy link
Copy Markdown
Author

Done! Updated to [18.0][ADD] l10n_us_sales_tax_engine: Hybrid US Sales Tax Engine.

@crrodrigueztrujillo
Copy link
Copy Markdown
Author

@usamahassan-rt Great point! California's CDTFA is one of the most complex tax jurisdictions in the US. The architecture is provider-agnostic — adding a CDTFA-specific provider only requires implementing a new class extending ProviderBase. Contributions are very welcome!

@crrodrigueztrujillo
Copy link
Copy Markdown
Author

Thank you for the thorough review @rrebollo and for taking the time despite the volume of changes.

Regarding splitting into multiple addons — we agree it's worth considering as the module grows and we'll evaluate it for a follow-up PR.

On the OCA frameworks (connector, component, queue_job): the tax rate import here is designed for loading government-published flat files (Florida DOR, future state CSVs) on an ad-hoc basis — not a recurring sync flow. Adding connector_importer as a dependency would significantly increase the installation footprint for what is essentially a periodic manual operation. We'd prefer to keep it lightweight in v1 and revisit in a follow-up if the community sees value in it.

All other inline suggestions have been applied — thank you for the detailed feedback!

Copy link
Copy Markdown

@rrebollo rrebollo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review. LGTM!

@jelenapoblet
Copy link
Copy Markdown

@usamahassan-rt Great point! California's CDTFA is one of the most complex tax jurisdictions in the US. The architecture is provider-agnostic — adding a CDTFA-specific provider only requires implementing a new class extending ProviderBase. Contributions are very welcome!

Following @rrebollo recommendation, maybe we could have a sale_tax_engine_base and then create a sale_tax_provider_xxx for each one of them, this way we could allow more contributions to this idea. What do you think ?

@crrodrigueztrujillo
Copy link
Copy Markdown
Author

@jelenapoblet Thank you for the suggestion — we really like the idea of a l10n_us_sales_tax_engine_base + l10n_us_sales_tax_provider_xxx architecture. It aligns well with the provider-agnostic design we already have internally, and would make community contributions much easier.

We're open to restructuring the module this way before merging if that's the direction the OCA community prefers. Could you and @rrebollo confirm if this is a requirement for approval, or a recommendation for a future iteration? That will help us prioritize the refactor accordingly.

@rrebollo
Copy link
Copy Markdown

rrebollo commented Jun 2, 2026

@crrodrigueztrujillo, I don't have merge superpowers — I just made a review. Your contribution already shows a lot of work, and I'm not here to make you do even more.

That said, in my humble opinion, the distributed architecture is much cleaner.

@jelenapoblet
Copy link
Copy Markdown

I think we're alligned @rrebollo , this way we'll have a better architecture and more contributors will be able to participate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

mod:l10n_us_sales_tax_engine Module l10n_us_sales_tax_engine series:18.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants