impl/typescript.ts
1,973 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 { vatRate } from "./finance_tax_vat_rate.ts"; ← from finance.tax.vat-rate ^1.0.0 · built alongside by fune
import { type RoundingMode } from "./math_round_div.ts"; ← from math.round-div ^1.0.0 · built alongside by fune
import { addMoney } from "./money_add.ts"; ← from money.add ^1.0.0 · built alongside by fune
import { type 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 { type DutyEstimate } from "./logistics_duty_estimate_types.ts";
function nonNegative(name: string, amount: Money): void {
if (amount.minor < 0) throw new RangeError(`${name} must not be negative, received ${amount.minor}`);
}
/**
* Import duty on the CIF customs value, then import VAT on the customs value
* plus duty plus the VAT-only additions, at the rate in force on importDate.
*/
export function dutyEstimate(
goods: Money,
freight: Money,
insurance: Money,
dutyBasisPoints: number,
vatAdditions: Money,
jurisdiction: string,
vatCategory: string,
importDate: string,
rounding: RoundingMode,
): DutyEstimate {
nonNegative("goods", goods);
nonNegative("freight", freight);
nonNegative("insurance", insurance);
nonNegative("vatAdditions", vatAdditions);
if (!Number.isInteger(dutyBasisPoints)) {
throw new TypeError(`dutyBasisPoints must be an integer, received ${dutyBasisPoints}`);
}
if (dutyBasisPoints < 0) throw new RangeError(`dutyBasisPoints must not be negative, received ${dutyBasisPoints}`);
// CIF: duty is charged on what it cost to get the goods to the border.
const customsValue = addMoney(addMoney(goods, freight), insurance);
const duty = applyRate(customsValue, dutyBasisPoints, rounding);
// VAT is charged on the duty too, and on costs after the border.
const vatValue = addMoney(addMoney(customsValue, duty), vatAdditions);
const rate = vatRate(jurisdiction, vatCategory, importDate);
const importVat = applyRate(vatValue, rate.basisPoints, rounding);
return {
customsValue,
dutyBasisPoints,
duty,
vatValue,
vatBasisPoints: rate.basisPoints,
importVat,
totalPayable: addMoney(duty, importVat),
};
}