Functional Weave
Code in Python

legal.retainer-drawdown@1.0.1

impl/rust.rs

2,805 bytes · the Rust 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.

use super::funejson::Value;  ← the fune runtime: the JSON value the test vectors use; fune build keeps it only where a signature takes one
use super::money_amount::{money, money_from_value, money_to_value, Money};  ← from money.amount ^1.0.0 · built alongside by fune

/// 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<RetainerApplication> = 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<RetainerBill> = args[1].as_arr().iter().map(retainer_bill_from_value).collect();
    retainer_drawdown_to_value(&retainer_drawdown(&money_from_value(&args[0]), &bills))
}