use super::funejson::Value; use super::finance_tax_vat_rate::vat_rate; use super::money_add::add_money; use super::money_amount::{money_from_value, money_to_value, Money}; use super::money_apply_rate::apply_rate; fn non_negative(name: &str, amount: &Money) { if amount.minor < 0 { panic!("{} must not be negative, received {}", name, 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 import_date. /// /// # Panics /// Panics on a negative amount or duty rate, mixed currencies, an unknown /// rounding mode, or no VAT rule for the jurisdiction, category and date. #[allow(clippy::too_many_arguments)] pub fn duty_estimate( goods: &Money, freight: &Money, insurance: &Money, duty_basis_points: i64, vat_additions: &Money, jurisdiction: &str, vat_category: &str, import_date: &str, rounding: &str, ) -> DutyEstimate { non_negative("goods", goods); non_negative("freight", freight); non_negative("insurance", insurance); non_negative("vatAdditions", vat_additions); if duty_basis_points < 0 { panic!("dutyBasisPoints must not be negative, received {}", duty_basis_points); } // CIF: duty is charged on what it cost to get the goods to the border. let customs_value = add_money(&add_money(goods, freight), insurance); let duty = apply_rate(&customs_value, duty_basis_points, rounding); // VAT is charged on the duty too, and on costs after the border. let vat_value = add_money(&add_money(&customs_value, &duty), vat_additions); let rate = vat_rate(jurisdiction, vat_category, import_date); let import_vat = apply_rate(&vat_value, rate.basis_points, rounding); DutyEstimate { total_payable: add_money(&duty, &import_vat), customs_value, duty_basis_points, duty, vat_value, vat_basis_points: rate.basis_points, import_vat, } } pub fn duty_estimate_to_value(e: &DutyEstimate) -> Value { Value::obj(vec![ ("customsValue", money_to_value(&e.customs_value)), ("dutyBasisPoints", Value::Int(e.duty_basis_points)), ("duty", money_to_value(&e.duty)), ("vatValue", money_to_value(&e.vat_value)), ("vatBasisPoints", Value::Int(e.vat_basis_points)), ("importVat", money_to_value(&e.import_vat)), ("totalPayable", money_to_value(&e.total_payable)), ]) } pub fn fune_vector(args: &[Value]) -> Value { duty_estimate_to_value(&duty_estimate( &money_from_value(&args[0]), &money_from_value(&args[1]), &money_from_value(&args[2]), args[3].as_i64(), &money_from_value(&args[4]), args[5].as_str(), args[6].as_str(), args[7].as_str(), args[8].as_str(), )) }