use super::funejson::Value; use super::finance_depreciation_straight_line::{depreciation_period_to_value, DepreciationPeriod}; use super::money_add::subtract_money; use super::money_amount::{money_from_value, Money}; use super::money_apply_rate::apply_rate; /// 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 { 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 = 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(), ) }