Functional Weave
Code in Rust

insurance.mid-term-adjustment@1.0.1

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",
    )