Docs
/
tax / VAT rules, discounts & subscription proration

tax

Tax, VAT and pricing-rules capability pack: US state sales tax and international VAT/GST/consumption tax from a built-in reference rate table (salesTax, vat, listRates), add tax net-to-gross...

tax — tax / VAT rules, discounts & subscription proration

A pure Leumas2 domain adapter pack (zero npm deps, Node built-ins only). It is the reusable rules engine for consumption tax, discounts, and subscription proration. All money math runs through cent-accurate rounding to avoid IEEE-754 float drift, and results are plain JSON.

What it does

ToolPurpose
salesTaxUS state sales tax (or explicit rate) net → gross, from the built-in table
vatInternational VAT/GST; inclusive:true backs tax out of a gross amount
addTaxnet → gross given a rate
removeTaxgross → net (back out the tax)
compoundTaxstack multiple rates — sequential (tax-on-tax) or parallel (state+county+city)
discountapply ONE discount: percent, fixed, or coupon (with optional min floor)
tieredPricegraduated bracket pricing (graduated) or single-tier flat (flat)
volumeDiscountbulk per-unit discount by quantity breaks
prorationprorate a mid-cycle subscription change by remaining-period fraction (charge/credit)
marginPricecost-plus pricing — margin (% of price) or markup (% of cost)
listRatesdump the reference rate table (us / intl / coupons / all) or one region

Rate table

data/rates.json is a static reference table: US 50 states + DC (combined state-level base sales tax), 30+ countries (standard national VAT/GST/consumption tax), and a small coupon catalog. Rates are decimal fractions (0.0725 = 7.25%). These are indicative reference values for estimation, not tax advice — for filing, use an authoritative source. Pass an explicit rate to bypass the table.

Rates accept either form: a decimal fraction (0.2) or a percent (20) — any value > 1 is read as a percent.

Usage

import tax from '@leumas/adapter-tax'; // or the registry: registry.run('tax', 'salesTax', {...})

tax.adapters.salesTax({ amount: 100, region: 'CA' });
// → { net: 100, rate: 0.0725, tax: 7.25, gross: 107.25, region: 'US-CA', regionName: 'California', taxType: 'sales' }

tax.adapters.vat({ amount: 120, region: 'GB', inclusive: true });
// → { inclusive: true, net: 100, tax: 20, gross: 120, rate: 0.2, ... }

tax.adapters.compoundTax({ amount: 100, rates: [0.05, { rate: 0.07, label: 'PST' }], mode: 'sequential' });

tax.adapters.discount({ amount: 80, coupon: 'SAVE20' });
// → { original: 80, kind: 'coupon:percent', discount: 16, final: 64, ... }

tax.adapters.tieredPrice({ quantity: 250, tiers: [{ upTo: 100, price: 1 }, { upTo: 200, price: 0.8 }, { upTo: null, price: 0.5 }] });

tax.adapters.proration({ amount: 30, periodStart: '2026-01-01', periodEnd: '2026-02-01', changeDate: '2026-01-16', direction: 'charge' });

tax.adapters.marginPrice({ cost: 70, marginPercent: 30, mode: 'margin' }); // → price 100

Every tool takes ONE args object (maps 1:1 onto an HTTP POST body) and throws TypeError/RangeError on bad input; unknown region/coupon lookups throw a status: 404 error.

DRY boundary (respect it)

  • finance owns money-over-time math: compound interest, loan amortization, TVM / NPV / IRR.
  • invoice owns billing documents: line items → a rendered invoice, invoice numbers, late fees.
  • tax (this pack) owns tax rules, discount rules, and subscription proration — the

numbers you compute before they land in an invoice line or a finance model.

Where they touch (an invoice line carries a taxRate/discount), invoice does its own inline math; this pack is the standalone engine you call to derive tax and discount figures — and a natural companion to PassNode for prorating plan/seat changes mid-cycle.

Source shared/engines/adapters/domain/tax/README.md (no-git)markdownjson
Generated from the Leumas repository. Every page cites the file it came from.leumas.techllms.txt