Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
import { allocate } from "./money_allocate.ts"; ← from money.allocate ^1.0.0 · built alongside by fune
import type { Money } from "./money_amount.ts"; ← from money.amount ^1.0.0 · built alongside by fune
import { type ProrationSplit } from "./finance_proration_types.ts";
/**
* Split a period's charge into the part used and the part not used.
*
* The mid-cycle upgrade, downgrade and cancellation calculation. Written the
* obvious way - one rounding for the charge and another for the credit - the
* two halves do not reliably add back up: 9.99 over two days is 4.995 each
* way, and two half-up roundings produce 5.00 and 5.00, a penny invented on a
* line the customer can see.
*
* One call to money.allocate does the whole split instead, so used + unused is
* the original amount for every input, credits included.
*/
export function prorate(amount: Money, totalDays: number, usedDays: number): ProrationSplit {
if (!Number.isInteger(totalDays) || totalDays <= 0) {
throw new RangeError(`total days must be greater than zero, received ${totalDays}`);
}
if (!Number.isInteger(usedDays) || usedDays < 0) {
throw new RangeError(`used days must not be negative, received ${usedDays}`);
}
if (usedDays > totalDays) {
// Clamping here would turn a bug in the caller's period arithmetic into a
// plausible invoice, which is far more expensive to find later.
throw new RangeError(`used days must not exceed total days, received ${usedDays} of ${totalDays}`);
}
// totalDays > 0 guarantees the ratios do not sum to zero, so allocate is safe
// even when one side is zero: [0, n] and [n, 0] are both well defined.
const [used, unused] = allocate(amount, [usedDays, totalDays - usedDays]);
return { total: amount, used, unused };
}