Skip to content

feat: rewrite custom tax model and add tax categories - #1212

Merged
gaspb merged 17 commits into
mainfrom
feat/tax-model
Aug 27, 2026
Merged

gaspb merged 17 commits into
mainfrom
feat/tax-model

Conversation

@gaspb

@gaspb gaspb commented Jul 10, 2026

Copy link
Copy Markdown
Member

No description provided.

gaspb added 14 commits August 25, 2026 22:10
- cargo fmt --all (module ordering + import wrapping)
- replace ProductRow::update_fee_structure's 8 positional args with a
  ProductRowPatch AsChangeset, matching the RowPatch convention used by the
  other tables; the store now sends only the fields it actually patches
- add the new tax_category_id / default_tax_category_id / tax_provider_id
  fields to the integration test fixtures
- name the non-taxable category key (NONTAXABLE_CATEGORY_KEY) instead of
  matching a literal, and cover it with a unit test
- drop a needless product_ids clone in the tax pipeline
A product could reference any tax_category row by id, including another
tenant's custom category once those become insertable. Product create and
update now check the category is built-in or owned by the tenant.

Replaces the unused, unscoped TaxCategoryRow::get_by_id.
Categories were an inert catalog: only the hardcoded nontaxable key read
them, and nothing tied them to the settings where tax code, country,
region and rate are defined. Products reached those rates only through
per-product product_custom_tax wiring.

A custom tax can now target a tax category. Invoicing resolves a line's
custom taxes as the union of the taxes wired to its product and the taxes
targeting its resolved category, deduped by id. Existing setups keep
tax_category_id NULL and behave exactly as before.

The settings dialog gains a category picker next to the tax code and
rules, so classifying a product is enough to pick up its rates.
Rates are stored and applied as fractions (tax = amount * rate), but the
settings screen labelled the input "Rate (%)" and rendered stored values
with a % suffix. Entering 20 for 20% therefore configured a 2000% tax.

The form and the table now convert between the two, so what is typed and
displayed matches the label. Stored values keep their meaning.
…ctor

main's payment connector factory matches ConnectorProviderEnum exhaustively;
Kintsugi is a tax provider, so it joins Hubspot/Pennylane as unsupported for
payment operations. Also restores tax_category_id on the add-on Product built
in the portal checkout, which main's rewrite of that block predates.
@gaspb gaspb changed the title feat: prepare tax model for connector feat: rewrite custom tax model and add tax categories Aug 27, 2026
@gaspb
gaspb merged commit a87280f into main Aug 27, 2026
9 checks passed
@gaspb
gaspb deleted the feat/tax-model branch August 27, 2026 21:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant