Functional Weave
Code in TypeScript

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(),
    )
}