insurance.mid-term-adjustment@1.0.0
impl/python.py
1,992 bytes · the Python 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.
from .dates_days_between import days_between ← from dates.days-between ^1.0.0 · built alongside by fune
from .insurance_mid_term_adjustment_types import MidTermAdjustment
from .math_round_div import RoundingMode, round_div ← from math.round-div ^1.0.0 · built alongside by fune
from .money_amount import Money, assert_same_currency, money ← from money.amount ^1.0.0 · built alongside by fune
def mid_term_adjustment(
old_premium: Money,
new_premium: Money,
inception_date: str,
expiry_date: str,
change_date: str,
admin_fee: Money,
mode: RoundingMode,
) -> MidTermAdjustment:
"""The additional or return premium for a change part-way through a policy term.
The difference between the two full-term premiums is pro-rated over the
days left, with one rounding. Pro-rating the old and new premiums
separately and subtracting rounds twice and can be a penny out.
"""
assert_same_currency(old_premium, new_premium)
assert_same_currency(old_premium, admin_fee)
if old_premium.minor < 0 or new_premium.minor < 0:
raise ValueError("premiums must not be negative")
if admin_fee.minor < 0:
raise ValueError("adminFee must not be negative, received %d" % (admin_fee.minor,))
total_days = days_between(inception_date, expiry_date)
if total_days <= 0:
raise ValueError(
"expiryDate must be after inceptionDate, received %s to %s" % (inception_date, expiry_date)
)
remaining_days = days_between(change_date, expiry_date)
if remaining_days < 0 or remaining_days > total_days:
raise ValueError("changeDate must be from inceptionDate to expiryDate, received %s" % (change_date,))
change = round_div((new_premium.minor - old_premium.minor) * remaining_days, total_days, mode)
currency = old_premium.currency
return MidTermAdjustment(
total_days=total_days,
remaining_days=remaining_days,
premium_change=money(change, currency),
admin_fee=admin_fee,
amount_due=money(change + admin_fee.minor, currency),
kind="additional" if change > 0 else "return" if change < 0 else "none",
)