Functional Weave
Code in Rust

payroll.redundancy-pay@1.0.1

impl/typescript.ts

2,473 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 { addDays } from "./dates_add_days.ts";  ← from dates.add-days ^1.0.0 · built alongside by fune
import { addMonths } from "./dates_add_months.ts";  ← from dates.add-months ^1.0.0 · built alongside by fune
import { age } from "./dates_age.ts";  ← from dates.age ^1.0.0 · built alongside by fune
import { lengthOfService } from "./hr_length_of_service.ts";  ← from hr.length-of-service ^1.0.0 · built alongside by fune
import { roundDiv } from "./math_round_div.ts";  ← from math.round-div ^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 { WEEK_PAY_CAPS, WEEK_PAY_CAPS_HISTORY } from "./payroll_redundancy_pay_data.ts";  ← this capability’s own data, compiled from data/week-pay-caps.json into the same file by fune build
import { type RedundancyPay } from "./payroll_redundancy_pay_types.ts";

function weekPayCap(relevantDate: string): number {
  for (const row of WEEK_PAY_CAPS) {
    if (relevantDate >= row.validFrom && (row.validTo === null || relevantDate <= row.validTo)) return row.capMinor;
  }
  if (WEEK_PAY_CAPS_HISTORY !== "full") {
    let earliest: string | null = null;
    for (const row of WEEK_PAY_CAPS) if (earliest === null || row.validFrom < earliest) earliest = row.validFrom;
    if (earliest !== null && relevantDate < earliest) {
      throw new RangeError(
        `no statutory week's pay cap for ${relevantDate}: this build was installed with history=${WEEK_PAY_CAPS_HISTORY}, ` +
          `so it only carries caps from ${earliest}. Reinstall with history=full for older dismissals.`,
      );
    }
  }
  throw new RangeError(`no statutory week's pay cap for ${relevantDate}`);
}

/**
 * ERA 1996 s.162 redundancy pay. Years are reckoned backwards from the
 * relevant date and each is priced by the age on its first day, so the rate
 * steps up only for years spent wholly at 22 or 41 and over.
 */
export function statutoryRedundancyPay(birthDate: string, startDate: string, relevantDate: string, weeklyPay: Money): RedundancyPay {
  if (weeklyPay.minor < 0) throw new RangeError(`weeklyPay must not be negative, received ${weeklyPay.minor}`);
  const cap = weekPayCap(relevantDate);
  const weeklyPayUsed = money(Math.min(weeklyPay.minor, cap), weeklyPay.currency);
  const serviceYears = lengthOfService(startDate, relevantDate).years;
  const eligible = serviceYears >= 2;
  const yearsCounted = eligible ? Math.min(serviceYears, 20) : 0;
  let halfWeeks = 0;
  for (let k = 1; k <= yearsCounted; k++) {
    const firstDay = addDays(addMonths(relevantDate, -12 * k), 1);
    const ageThen = age(birthDate, firstDay);
    halfWeeks += ageThen >= 41 ? 3 : ageThen >= 22 ? 2 : 1;
  }
  const amount = money(roundDiv(halfWeeks * weeklyPayUsed.minor, 2, "half-up"), weeklyPay.currency);
  return { eligible, serviceYears, yearsCounted, halfWeeks, weeklyPayUsed, amount };
}