use super::funejson::Value; use super::math_round_div::round_div; use super::money_amount::{money, money_from_value, money_to_value, Money}; // Above this, amount * 10000 is no longer exact as a JavaScript number; the // same limit applies here so every language refuses the same inputs. const MAX_MINOR: i64 = 90_000_000_000; /// Gross and net rental yield in basis points. Each is rounded once, half-up, /// from the exact ratio, never from a rounded percentage. /// /// # Panics /// Panics on mismatched currencies, a value that is not positive, a negative /// rent or cost, or an amount beyond the exact range. pub fn rental_yield(annual_rent: &Money, annual_costs: &Money, property_value: &Money) -> RentalYield { let currency = property_value.currency.as_str(); for other in [annual_rent, annual_costs] { if other.currency != currency { panic!("currency mismatch: {} and {}", other.currency, currency); } } if property_value.minor <= 0 { panic!("propertyValue must be greater than zero, received {}", property_value.minor); } if annual_rent.minor < 0 { panic!("annualRent must not be negative, received {}", annual_rent.minor); } if annual_costs.minor < 0 { panic!("annualCosts must not be negative, received {}", annual_costs.minor); } for m in [annual_rent.minor, annual_costs.minor, property_value.minor] { if m > MAX_MINOR { panic!("amounts must be at most {} minor units", MAX_MINOR); } } let net = annual_rent.minor - annual_costs.minor; RentalYield { gross_basis_points: round_div(annual_rent.minor * 10000, property_value.minor, "half-up"), net_basis_points: round_div(net * 10000, property_value.minor, "half-up"), net_income: money(net, currency), } } pub fn rental_yield_to_value(result: &RentalYield) -> Value { Value::obj(vec![ ("grossBasisPoints", Value::Int(result.gross_basis_points)), ("netBasisPoints", Value::Int(result.net_basis_points)), ("netIncome", money_to_value(&result.net_income)), ]) } pub fn fune_vector(args: &[Value]) -> Value { rental_yield_to_value(&rental_yield( &money_from_value(&args[0]), &money_from_value(&args[1]), &money_from_value(&args[2]), )) }