Functional Weave
Code in TypeScript

legal.court-fee@1.0.2

impl/typescript.ts

2,144 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 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
import { ISSUE_FEES, ISSUE_FEES_HISTORY } from "./legal_court_fee_data.ts";  ← this capability’s own data, compiled from data/issue-fees.json into the same file by fune build
import { type FilingChannel } from "./legal_court_fee_types.ts";

const ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;

/** The fee to issue a money claim, from the bands in force on the issue date. */
export function courtFee(claim: Money, channel: FilingChannel, onDate: string): Money {
  if (claim.currency !== "GBP") {
    throw new RangeError(`court fees are set for claims in GBP, received ${claim.currency}`);
  }
  if (claim.minor <= 0) {
    throw new RangeError("claim must be greater than zero");
  }
  if (channel !== "paper" && channel !== "online") {
    throw new RangeError(`unknown filing channel "${channel}": expected paper or online`);
  }
  if (!ISO_DATE.test(onDate)) {
    throw new RangeError(`onDate must be an ISO date (YYYY-MM-DD), received "${onDate}"`);
  }
  let inForce = 0;
  let earliest: string | null = null;
  for (const row of ISSUE_FEES) {
    if (row.channel !== channel) continue;
    if (earliest === null || row.validFrom < earliest) earliest = row.validFrom;
    if (onDate < row.validFrom || (row.validTo !== null && onDate > row.validTo)) continue;
    inForce += 1;
    if (claim.minor <= row.overMinor || (row.upToMinor !== null && claim.minor > row.upToMinor)) continue;
    if (row.feeMinor !== null) return money(row.feeMinor, "GBP");
    // gov.uk: "round down the result to the nearest 1 pence".
    return applyRate(claim, row.basisPoints as number, "down");
  }
  if (inForce > 0) {
    throw new RangeError(`a claim of ${claim.minor} pence cannot be issued ${channel} on ${onDate}: online claims are limited to GBP 100,000`);
  }
  if (ISSUE_FEES_HISTORY !== "full" && earliest !== null && onDate < earliest) {
    throw new RangeError(
      `no ${channel} court fee on ${onDate}: this build was installed with history=${ISSUE_FEES_HISTORY}, so it only carries fees from ${earliest}. Reinstall with history=full for older claims.`,
    );
  }
  throw new RangeError(`no ${channel} court fee in force on ${onDate}`);
}