from .insurance_sum_insured_average_types import AverageSettlement from .math_round_div import RoundingMode, round_div from .money_amount import Money, assert_same_currency, money def average_clause_settlement( loss: Money, sum_insured: Money, value_at_risk: Money, condition_basis_points: int, mode: RoundingMode ) -> AverageSettlement: """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. """ assert_same_currency(loss, sum_insured) assert_same_currency(loss, value_at_risk) if value_at_risk.minor <= 0: raise ValueError("valueAtRisk must be more than zero, received %d" % (value_at_risk.minor,)) if loss.minor < 0: raise ValueError("loss must not be negative, received %d" % (loss.minor,)) if sum_insured.minor < 0: raise ValueError("sumInsured must not be negative, received %d" % (sum_insured.minor,)) if loss.minor > value_at_risk.minor: raise ValueError("loss must not exceed the value at risk") cbp = condition_basis_points if isinstance(cbp, bool) or not isinstance(cbp, int) or cbp < 1 or cbp > 10000: raise ValueError("conditionBasisPoints must be from 1 to 10000, received %s" % (cbp,)) average_applied = sum_insured.minor * 10000 < value_at_risk.minor * cbp if average_applied: payout = round_div(loss.minor * sum_insured.minor, value_at_risk.minor, mode) else: payout = loss.minor payout = min(payout, loss.minor, sum_insured.minor) c = loss.currency return AverageSettlement( payout=money(payout, c), average_applied=average_applied, insured_proportion_basis_points=min(round_div(sum_insured.minor * 10000, value_at_risk.minor, "down"), 10000), shortfall=money(loss.minor - payout, c), )