Skip to content

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:

  1. Gathers the tax context — channel, account, location, and exemption flags.
  2. Runs every registered TaxStrategy in parallel.
  3. Each strategy returns zero or more tax lines per order line.
  4. 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:

  1. Create a tax rate entry with jurisdiction (country + optional state/city).
  2. Set the percentage rate (e.g., 8.25 for 8.25%).
  3. 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-leveltax_exempt flag on the account. Exempts all orders from all locations under that account.
  • Location-leveltax_exempt flag 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:

  1. Order lines are created with their discounted amounts.
  2. resolve_all runs and writes tax lines to each order line.
  3. tax_total is computed as the sum of all tax line amounts.
  4. grand_total is 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.