Functional Weave
Code in Rust

finance.depreciation-reducing-balance@1.0.0

impl/typescript.ts

1,870 bytes · the TypeScript 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.

import { type DepreciationPeriod } from "./finance_depreciation_straight_line_types.ts";
import { subtractMoney } from "./money_add.ts";  ← from money.add ^1.0.0 · built alongside by fune
import { type Money, money } from "./money_amount.ts";  ← from money.amount ^1.0.0 · built alongside by fune
import { applyRate } from "./money_apply_rate.ts";  ← 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.
 */
export function reducingBalanceDepreciation(
  cost: Money,
  residualValue: Money,
  rateBasisPoints: number,
  years: number,
): readonly DepreciationPeriod[] {
  if (!Number.isInteger(years) || years < 1) {
    throw new RangeError(`years must be at least 1, received ${years}`);
  }
  if (!Number.isInteger(rateBasisPoints) || rateBasisPoints < 0 || rateBasisPoints > 10000) {
    throw new RangeError(`rate must be 0 to 10000 basis points, received ${rateBasisPoints}`);
  }
  if (cost.minor < 0) {
    throw new RangeError("cost must not be negative");
  }
  if (residualValue.minor < 0) {
    throw new RangeError("residual value must not be negative");
  }
  // subtractMoney also refuses a cost and residual value in different currencies.
  if (subtractMoney(cost, residualValue).minor < 0) {
    throw new RangeError("residual value must not exceed cost");
  }

  const schedule: DepreciationPeriod[] = [];
  let openingValue = cost;
  for (let year = 1; year <= years; year += 1) {
    const headroom = subtractMoney(openingValue, residualValue);
    let charge = year === years ? headroom : applyRate(openingValue, rateBasisPoints, "half-up");
    if (charge.minor > headroom.minor) charge = headroom;
    const closingValue = subtractMoney(openingValue, charge);
    schedule.push({ year, openingValue, charge, closingValue });
    openingValue = closingValue;
  }
  return schedule;
}