use super::funejson::Value; use super::money_amount::{assert_same_currency, money, money_from_value, money_to_value, Money}; /// The claim payout after the excess, capped at the policy limit. /// /// The excess is the compulsory and voluntary excess together, and a loss /// smaller than it pays nothing. By default the limit caps what is paid after /// the excess; with `excess_within_limit` the excess is taken off the loss /// after the limit, so it erodes the limit. /// /// # Panics /// Panics on mixed currencies or a negative amount. pub fn apply_excess( loss: &Money, compulsory_excess: &Money, voluntary_excess: &Money, policy_limit: Option<&Money>, excess_within_limit: bool, ) -> ExcessSettlement { assert_same_currency(loss, compulsory_excess); assert_same_currency(loss, voluntary_excess); if let Some(limit) = policy_limit { assert_same_currency(loss, limit); } if loss.minor < 0 { panic!("loss must not be negative, received {}", loss.minor); } if compulsory_excess.minor < 0 || voluntary_excess.minor < 0 { panic!("excess must not be negative"); } if let Some(limit) = policy_limit { if limit.minor < 0 { panic!("policyLimit must not be negative, received {}", limit.minor); } } let excess = compulsory_excess.minor + voluntary_excess.minor; let mut limit_applied = false; let payout = if excess_within_limit { let mut covered = loss.minor; if let Some(limit) = policy_limit { if limit.minor < covered { covered = limit.minor; limit_applied = true; } } (covered - excess).max(0) } else { let mut p = (loss.minor - excess).max(0); if let Some(limit) = policy_limit { if limit.minor < p { p = limit.minor; limit_applied = true; } } p }; let c = &loss.currency; ExcessSettlement { total_excess: money(excess, c), excess_applied: money(excess.min(loss.minor), c), payout: money(payout, c), limit_applied, uninsured: money(loss.minor - payout, c), } } pub fn excess_settlement_to_value(s: &ExcessSettlement) -> Value { Value::obj(vec![ ("totalExcess", money_to_value(&s.total_excess)), ("excessApplied", money_to_value(&s.excess_applied)), ("payout", money_to_value(&s.payout)), ("limitApplied", Value::Bool(s.limit_applied)), ("uninsured", money_to_value(&s.uninsured)), ]) } pub fn fune_vector(args: &[Value]) -> Value { let limit = if args[3].is_null() { None } else { Some(money_from_value(&args[3])) }; excess_settlement_to_value(&apply_excess( &money_from_value(&args[0]), &money_from_value(&args[1]), &money_from_value(&args[2]), limit.as_ref(), args[4].as_bool(), )) }