Functional Weave
Code in TypeScript

banking.bacs-processing-date@1.0.0

impl/typescript.ts

1,977 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 { addBusinessDays } from "./dates_add_business_days.ts";  ← from dates.add-business-days ^1.0.0 · built alongside by fune
import { bankHolidays } from "./dates_bank_holidays.ts";  ← from dates.bank-holidays ^1.0.0 · built alongside by fune
import { isWeekday } from "./dates_day_of_week.ts";  ← from dates.day-of-week ^1.0.0 · built alongside by fune
import { type BacsCycle } from "./banking_bacs_processing_date_types.ts";

function holidaysFor(years: readonly number[]): string[] {
  const out: string[] = [];
  for (const year of years) {
    for (const holiday of bankHolidays("england-and-wales", year)) out.push(holiday.date);
  }
  return out;
}

function cycleWith(submissionIso: string, afterCutoff: boolean, holidays: readonly string[]): BacsCycle {
  const processingDay = isWeekday(submissionIso) && !holidays.includes(submissionIso);
  const inputDay = processingDay && !afterCutoff ? submissionIso : addBusinessDays(submissionIso, 1, holidays);
  return {
    inputDay,
    processingDay: addBusinessDays(inputDay, 1, holidays),
    entryDay: addBusinessDays(inputDay, 2, holidays),
  };
}

/**
 * The Bacs cycle a file joins. Bacs works on processing days - Monday to
 * Friday except England and Wales bank holidays - and a file joins the cycle
 * whose input day is the day it arrives, if that is a processing day and it
 * arrived before the 22:30 deadline, or the next processing day otherwise.
 * Processing is the next processing day and entry the one after.
 */
export function bacsProcessingDates(submissionIso: string, afterCutoff: boolean): BacsCycle {
  // isWeekday validates the date before its year is read.
  isWeekday(submissionIso);
  const year = Number(submissionIso.slice(0, 4));
  // Only reach for next year's calendar when the cycle really runs into it,
  // so a December submission in the last published year still works as long
  // as its cycle ends inside that year.
  let cycle = cycleWith(submissionIso, afterCutoff, holidaysFor([year]));
  if (cycle.entryDay.slice(0, 4) !== submissionIso.slice(0, 4)) {
    cycle = cycleWith(submissionIso, afterCutoff, holidaysFor([year, year + 1]));
  }
  return cycle;
}