Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
import re
from typing import List, Optional
from .finance_tax_vat_rate_data import VAT_RULES ← this capability’s own data, compiled from data/vat-rules.json into the same file by fune build
from .finance_tax_vat_rate_types import VatRate
ISO_DATE = re.compile(r"^\d{4}-\d{2}-\d{2}$")
def vat_rate(jurisdiction: str, category: str, on_date: str) -> VatRate:
"""The VAT rate in force for a jurisdiction and category on a given date.
The date matters. A credit note against a 2009 invoice has to use the rate
that applied in 2009, not the one that applies today, and a system that
hardcodes 0.20 cannot do that at all.
ISO dates compare correctly as strings, so this needs no date library.
"""
if not isinstance(on_date, str) or not ISO_DATE.match(on_date):
raise ValueError('on_date must be an ISO date (YYYY-MM-DD), received "%s"' % (on_date,))
best: Optional[VatRate] = None
for rule in VAT_RULES:
if rule.jurisdiction != jurisdiction or rule.category != category:
continue
if on_date < rule.valid_from:
continue
if rule.valid_to is not None and on_date > rule.valid_to:
continue
if best is None or rule.valid_from > best.valid_from:
best = VatRate(
jurisdiction=rule.jurisdiction,
category=rule.category,
basis_points=rule.basis_points,
valid_from=rule.valid_from,
valid_to=rule.valid_to,
)
if best is None:
raise ValueError("no VAT rule for %s/%s on %s" % (jurisdiction, category, on_date))
return best
def vat_categories(jurisdiction: str, on_date: str) -> List[str]:
"""Every category this registry knows a rate for, for a jurisdiction and date."""
seen = set()
for rule in VAT_RULES:
if rule.jurisdiction != jurisdiction:
continue
if on_date < rule.valid_from:
continue
if rule.valid_to is not None and on_date > rule.valid_to:
continue
seen.add(rule.category)
return sorted(seen)