Tax & compliance
Advanced VAT Configuration
Generated from docs/plan/core/advanced-vat-configuration/PLAN.md in the AstroBaaS repository. Nothing described below is implemented — it is the written plan for it.
Core-free VAT system that supports compound tax (tax on tax), fixed product tax (FPT), customer-group tax classes, and rounding strategies. Handles complex scenarios like UK fuel duty (excise tax + VAT on the excise), EU reverse-charge setups, and luxury tax overlays. This cannot be paid because merchants in many jurisdictions have no choice: the law requires these configurations.
The problem
I need compound tax (tax on tax), fixed product tax, and per-customer-group tax classes, but AstroBaaS only supports flat rates per class. UK fuel duty (excise + VAT on excise), EU reverse-charge overlays, and luxury-tax scenarios are impossible to model.
What it does
- Tax class entity: each product can belong to a custom tax class (default ‘standard’, or ‘reduced’, ‘zero’, ‘luxury’, ‘fuel’, etc.)
- Per-tax-class configuration: base rate (%), then optional fixed tax (EUR/item), then optional compound tax (rate on the base + fixed)
- Customer groups: merchants can define customer groups (e.g., ‘B2B’, ‘Wholesale’, ‘Registered Disabled’) and assign custom tax rates per group and tax class
- Rounding strategy: per-line, per-order, or half-up / truncate / banker’s rounding, configurable per region
- Compound tax calculation: for each line item, calculate base tax, then calculate compound tax on base + fixed, then add them
- Tax display: invoice and receipt show itemized tax breakdown (base rate, fixed, compound, total per item and per order)
- Tax exemption override: admin can manually zero-out tax on a specific line or order (with reason logged)
What it deliberately does NOT do
Each boundary carries its reason. A boundary without a reason gets crossed by the next person who reads this.
- No automated tax brackets (progressive tax based on price tiers) — merchant must list each bracket manually (reason: tax brackets are jurisdiction-specific and rarely change; static config is fine)
- No invoice splitting for tax (e.g., ‘this tax is paid to Tax Authority A, this to Authority B’) — one tax per line (reason: that is accounting software’s job; AstroBaaS stops at calculating and displaying the amount)
Data model
Product gains tax_class (string, default ‘standard’). New TaxClass entity: {id, name, base_rate (%), fixed_tax (integer cents), compound_tax (%)}. New CustomerGroup entity: {id, name}. Customer gains customer_group_id (reference). Settings gain tax_rounding_strategy (enum: line | order | half_up | truncate | bankers). One migration to create default tax classes.
API
- POST /api/tax-classes { name, base_rate, fixed_tax, compound_tax } → TaxClass
- GET /api/tax-classes (list all)
- PUT /api/tax-classes/:id { name, … }
- POST /api/customer-groups { name } → CustomerGroup
- GET /api/customer-groups (list all)
- PUT /api/settings/tax-rounding { strategy: ‘line’ | ‘order’ | … }
Every route added here must also appear in src/pages/openapi.json.ts — a test
fails the build if it does not.
Admin
Products table/editor gains ‘Tax Class’ dropdown. Customers table/editor gains ‘Customer Group’ dropdown. Settings → Tax → Advanced Configuration: shows tax class editor (create, edit, delete classes with base rate, fixed, compound fields) and customer groups editor. Tax dashboard shows examples: ‘Fuel (excise + VAT): base 20% VAT on GBP 1.50/liter excise = 30p tax’ to guide merchants.
The seam — why this is core
Core owns the tax calculation engine (takes product, customer, tax class, customer group as inputs → outputs tax amount). Merchants own creating tax classes and customer groups. Accountants own ensuring the configuration matches actual laws (AstroBaaS does not validate legality).
Tax compliance seam. Complex VAT scenarios (UK VAT on fuel, EU reverse-charge setups, luxury-tax overlays) are legal requirements in many jurisdictions. This cannot be paid.
Dependencies
- Product entity (core)
- Customer entity (core)
- Checkout tax calculation (core)
- Settings (core)
Acceptance checks
Each of these must be able to fail. Before claiming this is done, break the code deliberately and watch each one go red.
- Fuel tax class: 20% VAT, GBP 1.50 fixed excise, 20% compound tax on fixed. Checkout line (1 liter fuel) calculates: base = 0%, fixed = 150p, compound = 30p → total tax = 180p
- Customer group ‘Wholesale’ with custom rate 10% for ‘standard’ tax class. Wholesale customer checkout applies 10% instead of 20%
- Luxury tax class: 20% base + 5% luxury overlay (compound). Item price EUR 100: base tax = EUR 20, luxury tax = EUR 1 (5% of 20) → total EUR 21
- Rounding strategy ‘per order’: line items calculate tax, then rounding is applied once to the total (not per line)
- Tax display on invoice shows itemized breakdown: line 1 (EUR 100, standard 20%, tax EUR 20), line 2 (EUR 100, fuel with fixed + compound, tax EUR X)
Risks
Merchants misconfigure tax classes and charge wrong amount; AstroBaaS cannot validate legality, only calculate. Rounding strategy matters: EUR 10.55 * 20% = EUR 2.11 (banker’s) or EUR 2.10 (truncate); one penny difference across millions of orders is significant. Compound tax on compound tax (three-tier) is not supported; merchants must use core approach only. Tax class/customer group assignment is manual; bulk update is error-prone.
Commercial context
| Suggested price | Free |
| Rival anchor | Magento ships compound tax, FPT, customer-group tax classes, and three rounding strategies free. |
The anchor is what the nearest equivalent charges on Shopify or Magento today. It is context for a pricing decision, not the decision.
Generated from the commerce plan. See docs/COMMERCE-PLAN.md for the full
catalogue and ../../AI-GUIDE.md for how to work on this repository.