use super::funejson::Value; use super::dates_add_days::add_days; use super::finance_payment_terms_due_date::{payment_due_date, payment_terms_from_value, PaymentTerms}; use super::money_add::subtract_money; use super::money_amount::{money, money_from_value, money_to_value, Money}; use super::money_apply_rate::apply_rate; /// The settlement discount open on `payment_date`, and what is left to pay. /// /// The window is inclusive and counted in calendar days from the invoice date, /// so under 2/10 the tenth day after the invoice still earns the discount. /// /// # Panics /// Panics on a negative total, malformed dates or invalid terms. pub fn early_payment_discount( invoice_total: &Money, invoice_date: &str, terms: &PaymentTerms, payment_date: &str, ) -> EarlyPaymentDiscount { if invoice_total.minor < 0 { panic!("invoice total must not be negative"); } // Validates the terms, including a discount window that outlasts the due date. let due_date = payment_due_date(invoice_date, terms); // Validates the payment date; ISO dates then compare as strings. add_days(payment_date, 0); let deadline = if terms.discount_basis_points > 0 { Some(add_days(invoice_date, terms.discount_days)) } else { None }; let available = match &deadline { Some(last) => payment_date <= last.as_str(), None => false, }; let discount = if available { apply_rate(invoice_total, terms.discount_basis_points, "half-up") } else { money(0, &invoice_total.currency) }; EarlyPaymentDiscount { available, amount_to_pay: subtract_money(invoice_total, &discount), discount, discount_deadline: deadline, due_date, } } pub fn early_payment_discount_to_value(d: &EarlyPaymentDiscount) -> Value { Value::obj(vec![ ("available", Value::Bool(d.available)), ("discount", money_to_value(&d.discount)), ("amountToPay", money_to_value(&d.amount_to_pay)), ( "discountDeadline", match &d.discount_deadline { Some(date) => Value::str(date), None => Value::Null, }, ), ("dueDate", Value::str(&d.due_date)), ]) } pub fn fune_vector(args: &[Value]) -> Value { early_payment_discount_to_value(&early_payment_discount( &money_from_value(&args[0]), args[1].as_str(), &payment_terms_from_value(&args[2]), args[3].as_str(), )) }