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_add::{add_money, subtract_money}; ← from money.add ^1.0.0 · built alongside by fune
use super::money_amount::{money, money_from_value, money_to_value}; ← from money.amount ^1.0.0 · built alongside by fune
use super::money_convert::{convert_money, exchange_rate_from_value, ExchangeRate}; ← from money.convert ^1.0.0 · built alongside by fune
/// Revalue foreign-currency balances at the closing rates and report the
/// unrealised gain (positive) or loss (negative) on each and in total.
///
/// # Panics
/// Panics on a balance already in the functional currency, a booked value in
/// another currency, or a missing or duplicated rate.
pub fn fx_revaluation(balances: &[ForeignBalance], rates: &[ExchangeRate], functional_currency: &str) -> FxRevaluation {
let mut net = money(0, functional_currency);
let mut lines: Vec<RevaluedBalance> = Vec::with_capacity(balances.len());
for item in balances {
let foreign = item.balance.currency.as_str();
if foreign == functional_currency {
panic!("account {} is already in {}", item.account, functional_currency);
}
if item.booked_value.currency != functional_currency {
panic!("booked value of account {} must be in {}", item.account, functional_currency);
}
let matching: Vec<&ExchangeRate> = rates
.iter()
.filter(|r| r.base == foreign && r.quote == functional_currency)
.collect();
if matching.is_empty() {
panic!("no period-end rate from {} to {}", foreign, functional_currency);
}
if matching.len() > 1 {
panic!("more than one period-end rate from {} to {}", foreign, functional_currency);
}
let revalued_value = convert_money(&item.balance, matching[0], "half-up");
let gain_loss = subtract_money(&revalued_value, &item.booked_value);
net = add_money(&net, &gain_loss);
lines.push(RevaluedBalance {
account: item.account.clone(),
balance: item.balance.clone(),
booked_value: item.booked_value.clone(),
revalued_value,
gain_loss,
});
}
FxRevaluation {
lines,
net_gain_loss: net,
}
}
pub fn foreign_balance_from_value(v: &Value) -> ForeignBalance {
ForeignBalance {
account: v.get("account").as_str().to_string(),
balance: money_from_value(v.get("balance")),
booked_value: money_from_value(v.get("bookedValue")),
}
}
pub fn fx_revaluation_to_value(result: &FxRevaluation) -> Value {
Value::obj(vec![
(
"lines",
Value::Arr(
result
.lines
.iter()
.map(|l| {
Value::obj(vec![
("account", Value::str(&l.account)),
("balance", money_to_value(&l.balance)),
("bookedValue", money_to_value(&l.booked_value)),
("revaluedValue", money_to_value(&l.revalued_value)),
("gainLoss", money_to_value(&l.gain_loss)),
])
})
.collect(),
),
),
("netGainLoss", money_to_value(&result.net_gain_loss)),
])
}
pub fn fune_vector(args: &[Value]) -> Value {
let balances: Vec<ForeignBalance> = args[0].as_arr().iter().map(foreign_balance_from_value).collect();
let rates: Vec<ExchangeRate> = args[1].as_arr().iter().map(exchange_rate_from_value).collect();
fx_revaluation_to_value(&fx_revaluation(&balances, &rates, args[2].as_str()))
}