finance.depreciation-reducing-balance@1.0.0
impl/rust.rs
2,566 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::finance_depreciation_straight_line::{depreciation_period_to_value, DepreciationPeriod}; ← from finance.depreciation-straight-line ^1.0.0 · built alongside by fune
use super::money_add::subtract_money; ← from money.add ^1.0.0 · built alongside by fune
use super::money_amount::{money_from_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
/// A reducing-balance depreciation schedule, year by year.
///
/// Each charge is the rate applied to the opening value, rounded once. The
/// last year writes off down to the residual value, and no year may go below it.
///
/// # Panics
/// Panics if `years` is below 1, the rate is outside 0..=10000, either amount
/// is negative, the residual value exceeds the cost, or the currencies differ.
pub fn reducing_balance_depreciation(
cost: &Money,
residual_value: &Money,
rate_basis_points: i64,
years: i64,
) -> Vec<DepreciationPeriod> {
if years < 1 {
panic!("years must be at least 1, received {}", years);
}
if !(0..=10000).contains(&rate_basis_points) {
panic!("rate must be 0 to 10000 basis points, received {}", rate_basis_points);
}
if cost.minor < 0 {
panic!("cost must not be negative");
}
if residual_value.minor < 0 {
panic!("residual value must not be negative");
}
// subtract_money also refuses a cost and residual value in different currencies.
if subtract_money(cost, residual_value).minor < 0 {
panic!("residual value must not exceed cost");
}
let mut schedule: Vec<DepreciationPeriod> = Vec::with_capacity(years as usize);
let mut opening_value = cost.clone();
for year in 1..=years {
let headroom = subtract_money(&opening_value, residual_value);
let mut charge = if year == years {
headroom.clone()
} else {
apply_rate(&opening_value, rate_basis_points, "half-up")
};
if charge.minor > headroom.minor {
charge = headroom;
}
let closing_value = subtract_money(&opening_value, &charge);
schedule.push(DepreciationPeriod {
year,
opening_value: opening_value.clone(),
charge,
closing_value: closing_value.clone(),
});
opening_value = closing_value;
}
schedule
}
pub fn fune_vector(args: &[Value]) -> Value {
Value::Arr(
reducing_balance_depreciation(
&money_from_value(&args[0]),
&money_from_value(&args[1]),
args[2].as_i64(),
args[3].as_i64(),
)
.iter()
.map(depreciation_period_to_value)
.collect(),
)
}