Functional Weave
Code in Rust

logistics.duty-estimate@1.0.1

impl/python.py

2,076 bytes · the Python 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.

from .finance_tax_vat_rate import vat_rate  ← from finance.tax.vat-rate ^1.0.0 · built alongside by fune
from .math_round_div import RoundingMode  ← from math.round-div ^1.0.0 · built alongside by fune
from .money_add import add_money  ← from money.add ^1.0.0 · built alongside by fune
from .money_amount import Money  ← from money.amount ^1.0.0 · built alongside by fune
from .money_apply_rate import apply_rate  ← from money.apply-rate ^1.0.0 · built alongside by fune
from .logistics_duty_estimate_types import DutyEstimate


def _non_negative(name: str, amount: Money) -> None:
    if amount.minor < 0:
        raise ValueError("%s must not be negative, received %d" % (name, amount.minor))


def duty_estimate(
    goods: Money,
    freight: Money,
    insurance: Money,
    duty_basis_points: int,
    vat_additions: Money,
    jurisdiction: str,
    vat_category: str,
    import_date: str,
    rounding: RoundingMode,
) -> DutyEstimate:
    """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
    import_date."""
    _non_negative("goods", goods)
    _non_negative("freight", freight)
    _non_negative("insurance", insurance)
    _non_negative("vatAdditions", vat_additions)
    if isinstance(duty_basis_points, bool) or not isinstance(duty_basis_points, int):
        raise TypeError("dutyBasisPoints must be an integer, received %r" % (duty_basis_points,))
    if duty_basis_points < 0:
        raise ValueError("dutyBasisPoints must not be negative, received %d" % duty_basis_points)

    # CIF: duty is charged on what it cost to get the goods to the border.
    customs_value = add_money(add_money(goods, freight), insurance)
    duty = apply_rate(customs_value, duty_basis_points, rounding)
    # VAT is charged on the duty too, and on costs after the border.
    vat_value = add_money(add_money(customs_value, duty), vat_additions)
    rate = vat_rate(jurisdiction, vat_category, import_date)
    import_vat = apply_rate(vat_value, rate.basis_points, rounding)
    return DutyEstimate(
        customs_value=customs_value,
        duty_basis_points=duty_basis_points,
        duty=duty,
        vat_value=vat_value,
        vat_basis_points=rate.basis_points,
        import_vat=import_vat,
        total_payable=add_money(duty, import_vat),
    )