Functional Weave
Code in Rust

finance.early-payment-discount@1.0.0

impl/typescript.ts

1,658 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 { paymentDueDate } from "./finance_payment_terms_due_date.ts";  ← from finance.payment-terms-due-date ^1.0.0 · built alongside by fune
import { type PaymentTerms } from "./finance_payment_terms_due_date_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
import { type EarlyPaymentDiscount } from "./finance_early_payment_discount_types.ts";

/**
 * The settlement discount open on `paymentDate`, and what is left to pay.
 *
 * The window is inclusive and counted in calendar days from the invoice date,
 * so under 2/10 the tenth day after the invoice still earns the discount.
 */
export function earlyPaymentDiscount(
  invoiceTotal: Money,
  invoiceDate: string,
  terms: PaymentTerms,
  paymentDate: string,
): EarlyPaymentDiscount {
  if (invoiceTotal.minor < 0) {
    throw new RangeError("invoice total must not be negative");
  }
  // Validates the terms, including a discount window that outlasts the due date.
  const dueDate = paymentDueDate(invoiceDate, terms);
  // Validates the payment date; ISO dates then compare as strings.
  addDays(paymentDate, 0);

  const offered = terms.discountBasisPoints > 0;
  const discountDeadline = offered ? addDays(invoiceDate, terms.discountDays) : null;
  const available = discountDeadline !== null && paymentDate <= discountDeadline;
  const discount = available
    ? applyRate(invoiceTotal, terms.discountBasisPoints, "half-up")
    : money(0, invoiceTotal.currency);

  return {
    available,
    discount,
    amountToPay: subtractMoney(invoiceTotal, discount),
    discountDeadline,
    dueDate,
  };
}