insurance.sum-insured-average@1.0.1
impl/typescript.ts
2,377 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, assertSameCurrency, money } from "./money_amount.ts"; ← from money.amount ^1.0.0 · built alongside by fune
import { type AverageSettlement } from "./insurance_sum_insured_average_types.ts";
/**
* Settle a claim under an average clause.
*
* A property insured for less than it is worth is paid only the share of the
* loss that the sum insured bears to the value at risk: insured for 75% of
* its value, it is paid 75% of any loss. With a special condition of average
* the clause only applies once the sum insured falls below that share of the
* value. The payout never exceeds the loss or the sum insured.
*/
export function averageClauseSettlement(
loss: Money,
sumInsured: Money,
valueAtRisk: Money,
conditionBasisPoints: number,
mode: RoundingMode
): AverageSettlement {
assertSameCurrency(loss, sumInsured);
assertSameCurrency(loss, valueAtRisk);
if (valueAtRisk.minor <= 0) {
throw new RangeError(`valueAtRisk must be more than zero, received ${valueAtRisk.minor}`);
}
if (loss.minor < 0) throw new RangeError(`loss must not be negative, received ${loss.minor}`);
if (sumInsured.minor < 0) throw new RangeError(`sumInsured must not be negative, received ${sumInsured.minor}`);
if (loss.minor > valueAtRisk.minor) throw new RangeError("loss must not exceed the value at risk");
if (!Number.isInteger(conditionBasisPoints) || conditionBasisPoints < 1 || conditionBasisPoints > 10000) {
throw new RangeError(`conditionBasisPoints must be from 1 to 10000, received ${conditionBasisPoints}`);
}
const averageApplied = sumInsured.minor * 10000 < valueAtRisk.minor * conditionBasisPoints;
let payout = loss.minor;
if (averageApplied) {
// A loss and a sum insured in pence multiply past 2^53, so divide in bigint
// and round the remainder the way roundDiv would.
const wide = BigInt(loss.minor) * BigInt(sumInsured.minor);
const value = BigInt(valueAtRisk.minor);
payout = Number(wide / value) + roundDiv(Number(wide % value), valueAtRisk.minor, mode);
}
payout = Math.min(payout, loss.minor, sumInsured.minor);
const c = loss.currency;
return {
payout: money(payout, c),
averageApplied,
insuredProportionBasisPoints: Math.min(roundDiv(sumInsured.minor * 10000, valueAtRisk.minor, "down"), 10000),
shortfall: money(loss.minor - payout, c),
};
}