use super::funejson::Value; use super::money_amount::{money, money_from_value, money_to_value, Money}; /// Apply money on account to bills in the order given. /// /// # Panics /// Panics on a negative amount on account, a negative bill or mixed currencies. pub fn retainer_drawdown(on_account: &Money, bills: &[RetainerBill]) -> RetainerDrawdown { let currency = on_account.currency.as_str(); if on_account.minor < 0 { panic!("onAccount must not be negative, received {}", on_account.minor); } let mut left = on_account.minor; let mut applied = 0; let mut outstanding = 0; let mut lines: Vec = Vec::new(); for bill in bills { if bill.amount.currency != currency { panic!("currency mismatch: {} and {}", currency, bill.amount.currency); } if bill.amount.minor < 0 { panic!("bill \"{}\" must not be negative, received {}", bill.reference, bill.amount.minor); } let take = left.min(bill.amount.minor); left -= take; applied += take; outstanding += bill.amount.minor - take; lines.push(RetainerApplication { reference: bill.reference.clone(), billed: bill.amount.clone(), applied: money(take, currency), outstanding: money(bill.amount.minor - take, currency), }); } RetainerDrawdown { bills: lines, applied: money(applied, currency), outstanding: money(outstanding, currency), balance: money(left, currency), } } pub fn retainer_bill_from_value(v: &Value) -> RetainerBill { RetainerBill { reference: v.get("reference").as_str().to_string(), amount: money_from_value(v.get("amount")) } } pub fn retainer_drawdown_to_value(d: &RetainerDrawdown) -> Value { Value::obj(vec![ ( "bills", Value::Arr( d.bills .iter() .map(|b| { Value::obj(vec![ ("reference", Value::str(&b.reference)), ("billed", money_to_value(&b.billed)), ("applied", money_to_value(&b.applied)), ("outstanding", money_to_value(&b.outstanding)), ]) }) .collect(), ), ), ("applied", money_to_value(&d.applied)), ("outstanding", money_to_value(&d.outstanding)), ("balance", money_to_value(&d.balance)), ]) } pub fn fune_vector(args: &[Value]) -> Value { let bills: Vec = args[1].as_arr().iter().map(retainer_bill_from_value).collect(); retainer_drawdown_to_value(&retainer_drawdown(&money_from_value(&args[0]), &bills)) }