Functional Weave
Code in TypeScript

finance.markup-price@1.0.0

impl/typescript.ts

1,567 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 RoundingMode, 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 { type PricingBasis } from "./finance_markup_price_types.ts";

/**
 * The selling price that hits a target margin or markup on `cost`.
 *
 * Margin divides by the price and markup by the cost, so the same 5000 basis
 * points means 200.00 or 150.00 on a cost of 100.00; the basis is explicit.
 */
export function markupPrice(cost: Money, basisPoints: number, basis: PricingBasis, mode: RoundingMode): Money {
  if (!Number.isInteger(basisPoints)) {
    throw new TypeError(`basisPoints must be an integer, received ${basisPoints}`);
  }
  if (cost.minor < 0) {
    throw new RangeError(`cost must not be negative, received ${cost.minor}`);
  }

  let numerator: number;
  let denominator: number;
  if (basis === "markup") {
    if (basisPoints < -10000) {
      throw new RangeError(`a markup of ${basisPoints} basis points gives a negative price`);
    }
    numerator = cost.minor * (10000 + basisPoints);
    denominator = 10000;
  } else if (basis === "margin") {
    if (basisPoints >= 10000) {
      throw new RangeError(`a margin of ${basisPoints} basis points has no finite price`);
    }
    numerator = cost.minor * 10000;
    denominator = 10000 - basisPoints;
  } else {
    throw new RangeError(`unknown pricing basis "${basis}"`);
  }

  if (!Number.isSafeInteger(numerator)) {
    throw new RangeError("the price calculation exceeds 2^53 - 1");
  }
  return money(roundDiv(numerator, denominator, mode), cost.currency);
}