Functional Weave
Code in Rust

retail.oss-vat@1.0.1

impl/rust.rs

5,440 bytes · the Rust 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.

use super::funejson::Value;  ← the fune runtime: the JSON value the test vectors use; fune build keeps it only where a signature takes one
use super::money_amount::{money, money_from_value, money_to_value, Money};  ← from money.amount ^1.0.0 · built alongside by fune
use super::money_apply_rate::apply_rate;  ← from money.apply-rate ^1.0.0 · built alongside by fune
use super::retail_oss_vat_data::{OSS_RULES, OSS_RULES_HISTORY};  ← this capability’s own data, compiled from data/oss-rules.json into the same file by fune build

fn is_iso_date(value: &str) -> bool {
    let bytes = value.as_bytes();
    bytes.len() == 10
        && bytes[4] == b'-'
        && bytes[7] == b'-'
        && bytes
            .iter()
            .enumerate()
            .all(|(i, b)| i == 4 || i == 7 || b.is_ascii_digit())
}

// The EU writes Greece as EL in VAT matters; ISO 3166 says GR. Accept both.
fn country(code: &str, name: &str) -> String {
    if code.len() != 2 || !code.bytes().all(|b| b.is_ascii_uppercase()) {
        panic!("{} must be an ISO 3166-1 alpha-2 code, received \"{}\"", name, code);
    }
    if code == "EL" {
        "GR".to_string()
    } else {
        code.to_string()
    }
}

fn is_member(code: &str) -> bool {
    OSS_RULES.iter().any(|r| r.rule == "standard-rate" && r.country == code)
}

fn lookup(rule: &str, place: &str, on_date: &str) -> i64 {
    let mut best: Option<(&str, i64)> = None;
    for r in OSS_RULES {
        if r.rule != rule || r.country != place {
            continue;
        }
        if on_date < r.valid_from {
            continue;
        }
        if let Some(to) = r.valid_to {
            if on_date > to {
                continue;
            }
        }
        if best.map_or(true, |(from, _)| r.valid_from > from) {
            best = Some((r.valid_from, r.value));
        }
    }
    if let Some((_, value)) = best {
        return 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 mut earliest: Option<&str> = None;
        for r in OSS_RULES {
            if r.rule == rule && r.country == place && earliest.map_or(true, |e| r.valid_from < e) {
                earliest = Some(r.valid_from);
            }
        }
        if let Some(earliest) = earliest {
            if on_date < earliest {
                panic!(
                    "no OSS rule \"{}\" for {} on {}: this build was installed with history={}, so it only carries rules from {}. Reinstall with history=full for older supplies.",
                    rule, place, on_date, OSS_RULES_HISTORY, earliest
                );
            }
        }
    }
    panic!("no OSS rule \"{}\" for {} on {}", rule, place, on_date)
}

/// 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.
///
/// # Panics
/// Panics on a malformed date or country code, a customer outside the EU,
/// threshold totals not in EUR, or a date no rule covers.
pub fn oss_vat(
    net: &Money,
    seller_country: &str,
    customer_country: &str,
    eu_sales_previous_year: &Money,
    eu_sales_this_year: &Money,
    opted_in: bool,
    on_date: &str,
) -> OssVat {
    if !is_iso_date(on_date) {
        panic!("onDate must be an ISO date (YYYY-MM-DD), received \"{}\"", on_date);
    }
    let seller = country(seller_country, "sellerCountry");
    let customer = country(customer_country, "customerCountry");
    if !is_member(&customer) {
        panic!("customer country \"{}\" is not an EU member state", customer_country);
    }
    for (name, amount) in [
        ("euSalesPreviousYear", eu_sales_previous_year),
        ("euSalesThisYear", eu_sales_this_year),
    ] {
        if amount.currency != "EUR" {
            panic!("{} must be in EUR, received {}", name, amount.currency);
        }
        if amount.minor < 0 {
            panic!("{} must not be negative, received {}", name, amount.minor);
        }
    }

    let threshold = lookup("distance-selling-threshold", "EU", on_date);
    let threshold_exceeded =
        eu_sales_previous_year.minor > threshold || eu_sales_this_year.minor > threshold;

    let (scheme, tax_country) = if seller == customer {
        ("domestic", customer)
    } else if is_member(&seller) && !threshold_exceeded && !opted_in {
        ("origin", seller)
    } else {
        ("oss", customer)
    };

    let basis_points = lookup("standard-rate", &tax_country, on_date);
    let vat = apply_rate(net, basis_points, "half-up");
    OssVat {
        tax_country,
        scheme: scheme.to_string(),
        basis_points,
        threshold_exceeded,
        net: net.clone(),
        gross: money(net.minor + vat.minor, &net.currency),
        vat,
    }
}

pub fn oss_vat_to_value(o: &OssVat) -> Value {
    Value::obj(vec![
        ("taxCountry", Value::str(&o.tax_country)),
        ("scheme", Value::str(&o.scheme)),
        ("basisPoints", Value::Int(o.basis_points)),
        ("thresholdExceeded", Value::Bool(o.threshold_exceeded)),
        ("net", money_to_value(&o.net)),
        ("vat", money_to_value(&o.vat)),
        ("gross", money_to_value(&o.gross)),
    ])
}

pub fn fune_vector(args: &[Value]) -> Value {
    oss_vat_to_value(&oss_vat(
        &money_from_value(&args[0]),
        args[1].as_str(),
        args[2].as_str(),
        &money_from_value(&args[3]),
        &money_from_value(&args[4]),
        args[5].as_bool(),
        args[6].as_str(),
    ))
}