Functional Weave
Code in TypeScript

finance.proration@1.0.0

README.md

1,382 bytes · view raw

# finance.proration

This is the mid-cycle upgrade, downgrade and cancellation calculation. It is
usually written as two independent roundings - round(amount * used / total) for
the charge and round(amount * unused / total) for the credit - and those two
numbers do not always add back up to the amount. 9.99 over a two-day period
splits as 4.995 each way, which two half-up roundings turn into 5.00 and 5.00: a
penny invented out of nothing, on a line that a customer can see.

So the split is one call to money.allocate over the ratios [usedDays,
unusedDays]. used + unused equals amount exactly, for every input, including
negative amounts. The largest-remainder rule gives the odd minor unit to the
used side on a tie, which also means the same inputs always split the same way -
important when a credit note has to match the invoice it reverses.

Both ends are defined rather than special-cased: usedDays of 0 gives the whole
amount as unused, usedDays equal to totalDays gives the whole amount as used.
totalDays of zero or below, a negative usedDays, and a usedDays past the end of
the period are all errors, because each of them means the caller's period
arithmetic is wrong and a silently clamped answer would hide it.

Days are the unit here, but nothing in the arithmetic is date-specific: seconds
or hours work the same way, as long as both arguments use the same unit.