Functional Weave
Code in Python

retail.oss-vat@1.0.1

impl/typescript.ts

3,975 bytes · the TypeScript implementation · view raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

import { type Money, money } from "./money_amount.ts";  ← from money.amount ^1.0.0 · built alongside by fune
import { applyRate } from "./money_apply_rate.ts";  ← from money.apply-rate ^1.0.0 · built alongside by fune
import { OSS_RULES, OSS_RULES_HISTORY } from "./retail_oss_vat_data.ts";  ← this capability’s own data, compiled from data/oss-rules.json into the same file by fune build
import { type OssVat } from "./retail_oss_vat_types.ts";

const ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
const COUNTRY = /^[A-Z]{2}$/;

// The EU writes Greece as EL in VAT matters; ISO 3166 says GR. Accept both.
function country(code: string, name: string): string {
  if (!COUNTRY.test(code)) throw new RangeError(`${name} must be an ISO 3166-1 alpha-2 code, received "${code}"`);
  return code === "EL" ? "GR" : code;
}

function isMember(code: string): boolean {
  return OSS_RULES.some((r) => r.rule === "standard-rate" && r.country === code);
}

function lookup(rule: string, where: string, onDate: string): number {
  let best: { validFrom: string; value: number } | null = null;
  for (const r of OSS_RULES) {
    if (r.rule !== rule || r.country !== where) continue;
    if (onDate < r.validFrom || (r.validTo !== null && onDate > r.validTo)) continue;
    if (best === null || r.validFrom > best.validFrom) best = { validFrom: r.validFrom, value: r.value };
  }
  if (best !== null) return best.value;
  // A history=current build carries only the rules still in force; answering
  // an older date with today's rate is the failure the dates exist to prevent.
  if (OSS_RULES_HISTORY !== "full") {
    let earliest: string | null = null;
    for (const r of OSS_RULES) {
      if (r.rule === rule && r.country === where && (earliest === null || r.validFrom < earliest)) earliest = r.validFrom;
    }
    if (earliest !== null && onDate < earliest) {
      throw new RangeError(
        `no OSS rule "${rule}" for ${where} on ${onDate}: this build was installed with history=${OSS_RULES_HISTORY}, ` +
          `so it only carries rules from ${earliest}. Reinstall with history=full for older supplies.`,
      );
    }
  }
  throw new RangeError(`no OSS rule "${rule}" for ${where} on ${onDate}`);
}

/**
 * VAT on a business-to-consumer sale to another EU member state: the seller's
 * own rate while its cross-border sales stay within EUR 10,000 (and it has not
 * opted in), the customer's state's rate through the One Stop Shop once they
 * exceed it, and always the customer's for sellers outside the EU.
 */
export function ossVat(
  net: Money,
  sellerCountry: string,
  customerCountry: string,
  euSalesPreviousYear: Money,
  euSalesThisYear: Money,
  optedIn: boolean,
  onDate: string,
): OssVat {
  if (!ISO_DATE.test(onDate)) throw new RangeError(`onDate must be an ISO date (YYYY-MM-DD), received "${onDate}"`);
  const seller = country(sellerCountry, "sellerCountry");
  const customer = country(customerCountry, "customerCountry");
  if (!isMember(customer)) throw new RangeError(`customer country "${customerCountry}" is not an EU member state`);
  for (const [name, amount] of [
    ["euSalesPreviousYear", euSalesPreviousYear],
    ["euSalesThisYear", euSalesThisYear],
  ] as const) {
    if (amount.currency !== "EUR") throw new RangeError(`${name} must be in EUR, received ${amount.currency}`);
    if (amount.minor < 0) throw new RangeError(`${name} must not be negative, received ${amount.minor}`);
  }

  const threshold = lookup("distance-selling-threshold", "EU", onDate);
  const thresholdExceeded = euSalesPreviousYear.minor > threshold || euSalesThisYear.minor > threshold;

  let scheme: string;
  let taxCountry: string;
  if (seller === customer) {
    scheme = "domestic";
    taxCountry = customer;
  } else if (isMember(seller) && !thresholdExceeded && !optedIn) {
    scheme = "origin";
    taxCountry = seller;
  } else {
    scheme = "oss";
    taxCountry = customer;
  }

  const basisPoints = lookup("standard-rate", taxCountry, onDate);
  const vat = applyRate(net, basisPoints, "half-up");
  return {
    taxCountry,
    scheme,
    basisPoints,
    thresholdExceeded,
    net,
    vat,
    gross: money(net.minor + vat.minor, net.currency),
  };
}