Tax Calculation¶
Vectis computes taxes through a multi-strategy system that runs all registered tax strategies simultaneously. This supports scenarios where multiple tax types apply to a single order (e.g., sales tax + excise tax).
How Tax Resolution Works¶
During checkout, after order lines are created, the tax engine calls resolve_all which:
- Gathers the tax context — channel, account, location, and exemption flags.
- Runs every registered
TaxStrategyin parallel. - Each strategy returns zero or more tax lines per order line.
- Tax lines are stored as JSONB on the order line and rolled up into the order's
tax_total.
graph LR
OL[Order Line] --> R[resolve_all]
R --> S1[BasicPercentageTaxStrategy]
R --> S2[ExciseIQ Extension]
S1 --> TL1["Tax Line: Sales 8.25%"]
S2 --> TL2["Tax Line: Excise $1.50/unit"]
TL1 --> OL
TL2 --> OL Built-in: BasicPercentageTaxStrategy¶
The default tax strategy performs jurisdiction lookup from the tax_rates table:
- Matches the shipping address to a jurisdiction (country, state/province, city).
- Applies the configured percentage rate to the discounted line amount.
- Supports tax-inclusive and tax-exclusive pricing modes.
Setting Up Tax Rates¶
In the admin under Settings → Tax Rates:
- Create a tax rate entry with jurisdiction (country + optional state/city).
- Set the percentage rate (e.g.,
8.25for 8.25%). - Assign a tax category if you need different rates for different product types.
Tip
Tax rates stack by specificity. A state-level rate of 6% plus a city-level rate of 2.25% yields 8.25% for that city. Configure from broadest to most specific.
Extension: ExciseIQ¶
For industries requiring excise tax (alcohol, tobacco, fuel), the ExciseIQ extension registers an additional tax strategy that:
- Calculates per-unit excise amounts based on product attributes and jurisdiction.
- Returns excise tax lines alongside any sales tax lines from the basic strategy.
ExciseIQ is activated per-channel in the admin extensions panel.
Per-Line Tax Detail¶
Each order line stores a tax_lines JSONB array. Every entry contains:
| Field | Description |
|---|---|
strategy | Which tax strategy produced this line |
amount | The tax amount for this line |
rate | The effective tax rate (percentage or per-unit) |
jurisdiction | The jurisdiction that sourced the rate |
description | Human-readable label (e.g., "TX State Sales Tax") |
This granularity supports tax reporting, jurisdiction-level breakdowns, and audit trails.
Tax Exemption¶
B2B accounts and locations can be marked as tax-exempt:
- Account-level —
tax_exemptflag on the account. Exempts all orders from all locations under that account. - Location-level —
tax_exemptflag on a specific location. Exempts only orders shipping to that location.
When an exempt buyer checks out, the tax context carries the exemption flag and strategies return zero tax.
Warning
Tax exemption is binary — the buyer is either fully exempt or fully taxed. Partial exemptions (e.g., exempt on some product categories) require a custom tax strategy.
Tax Context¶
The tax engine builds a context object containing the channel, account, location, shipping address, exemption flags, and line items (with post-discount amounts). Each strategy uses whichever fields it needs — the basic strategy uses the shipping address; ExciseIQ also inspects product attributes.
Checkout Integration¶
Tax calculation happens after promotions and shipping:
- Order lines are created with their discounted amounts.
resolve_allruns and writes tax lines to each order line.tax_totalis computed as the sum of all tax line amounts.grand_totalis updated:subtotal - discount_total + tax_total + shipping_total.
Note
Tax is always calculated on the post-discount amount. A $100 item with a 20% discount is taxed on $80.
Admin Panel¶
From Settings → Tax in the admin:
- Create and manage tax rates by jurisdiction.
- Assign tax categories to products with special rates.
- Enable/disable tax extensions per channel.
- View per-order and per-line tax breakdowns in the order detail view.