This commit is contained in:
mats committed 2026-06-28 17:52:49 +02:00
1 parent e706f7d907
commit 21bcb63440
42 files changed
+5903

No files matched your search

+62
View File
@@ -0,0 +1,62 @@
// Package tax provides the tax computation seam: a Provider interface
// (mirroring PaymentProvider and ShippingProvider patterns), the shared Compute
// formula, and a stateless Static provider for dev/test.
//
// SCALE: all tax rates are integer **basis points of a percent** — rate × 100,
// so 25% = 2500, 12.5% = 1250, 8.1% = 810. This is the single platform-wide
// scale (Price.VatRates, CartItem.Tax, OrderLine.tax_rate, the payment-provider
// wire). Integer basis points support fractional VAT rates (Ireland 13.5%,
// France 5.5%, Finland 25.5%) exactly without ever using a float.
package tax
// Provider computes taxes for orders and line items.
type Provider interface {
// Name returns the provider name for identification (logging, metrics).
Name() string
// Compute computes the VAT portion from a gross (inc-VAT) total and tax
// rate. Both total and return value are in minor currency units (öre).
// rateBp is basis points of a percent (2500 = 25%, 1250 = 12.5%).
//
// Ex-VAT-first integer math: exVat = total*10000/(10000+rateBp); tax = total - exVat.
// When rateBp <= 0 the result is 0 (untaxed / zero-rated items).
Compute(total int64, rateBp int) int64
// DefaultTaxRate returns the default VAT rate for a country in basis points
// (2500 = 25%). Used for deliveries and items where no explicit rate was
// recorded at add-to-cart time. Returns 0 if the country is unknown/untaxed.
DefaultTaxRate(country string) int
}
// Compute returns the VAT portion of an inc-VAT total using integer (cent)
// arithmetic only, ex-VAT-first so exVat + tax == total exactly and the result
// matches the payment-provider convention (no per-line rounding drift):
//
// exVat = total * 10000 / (10000 + rateBp)
// tax = total - exVat
//
// rateBp is basis points of a percent (2500 = 25%, 1250 = 12.5%) — the single
// platform-wide rate scale. When rateBp <= 0 the result is 0 (untaxed).
func Compute(total int64, rateBp int) int64 {
if rateBp <= 0 {
return 0
}
exVat := total * 10000 / int64(10000+rateBp)
return total - exVat
}
// Static is a stateless, always-available Provider that simply runs the
// formula without any country-specific rates. Use for local dev, tests,
// and as a no-dependency default.
type Static struct{}
var _ Provider = (*Static)(nil)
// NewStatic returns a new Static provider.
func NewStatic() *Static { return &Static{} }
func (p *Static) Name() string { return "static" }
func (p *Static) Compute(total int64, taxRate int) int64 {
return Compute(total, taxRate)
}
func (p *Static) DefaultTaxRate(_ string) int { return 0 }