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::finance_invoice_calculate::{calculate_invoice, invoice_line_from_value, invoice_to_value, Invoice, InvoiceLine}; ← from finance.invoice.calculate ^1.0.0 · built alongside by fune
use super::finance_invoice_line_total::line_total; ← from finance.invoice.line-total ^1.0.0 · built alongside by fune
use super::money_amount::{money, money_from_value}; ← from money.amount ^1.0.0 · built alongside by fune
/// A credit note against an invoice, with VAT at the original tax point.
///
/// Every credit becomes a negative invoice line and the whole note is
/// calculated by finance.invoice.calculate at the original date, so the VAT
/// rates, rounding and grouping are the invoice's own.
///
/// # Panics
/// Panics on an empty or malformed credit, a line out of range, or credits
/// exceeding what a line was invoiced for.
pub fn calculate_credit_note(
original_lines: &[InvoiceLine],
credits: &[CreditRequest],
jurisdiction: &str,
original_tax_point: &str,
) -> Invoice {
if credits.is_empty() {
panic!("a credit note needs at least one line");
}
let mut credited = vec![0i64; original_lines.len()];
let mut lines: Vec<InvoiceLine> = Vec::with_capacity(credits.len());
for credit in credits {
let n = credit.line;
if n < 1 || n as usize > original_lines.len() {
panic!("credit refers to line {}, but the invoice has {} lines", n, original_lines.len());
}
let original = &original_lines[n as usize - 1];
if original.quantity <= 0 {
panic!("line {} of the invoice is not a sale that can be credited", n);
}
let line = match (&credit.quantity, &credit.net) {
(Some(quantity), None) => {
if *quantity <= 0 {
panic!("credit quantity for line {} must be greater than zero", n);
}
InvoiceLine {
quantity: -quantity,
..original.clone()
}
}
(None, Some(net)) => {
if net.currency != original.unit_price.currency {
panic!("credit for line {} must be in {}", n, original.unit_price.currency);
}
if net.minor <= 0 {
panic!("credit amount for line {} must be greater than zero", n);
}
InvoiceLine {
description: original.description.clone(),
unit_price: money(-net.minor, &net.currency),
quantity: 1,
discount_basis_points: 0,
tax_category: original.tax_category.clone(),
}
}
_ => panic!("credit for line {} needs exactly one of quantity and net", n),
};
let slot = n as usize - 1;
credited[slot] -= line_total(&line.unit_price, line.quantity, line.discount_basis_points).minor;
let invoiced = line_total(&original.unit_price, original.quantity, original.discount_basis_points).minor;
if credited[slot] > invoiced {
panic!("credits against line {} exceed what it was invoiced for", n);
}
lines.push(line);
}
calculate_invoice(&lines, jurisdiction, original_tax_point)
}
pub fn credit_request_from_value(v: &Value) -> CreditRequest {
CreditRequest {
line: v.get("line").as_i64(),
quantity: if v.get("quantity").is_null() { None } else { Some(v.get("quantity").as_i64()) },
net: if v.get("net").is_null() { None } else { Some(money_from_value(v.get("net"))) },
}
}
pub fn fune_vector(args: &[Value]) -> Value {
let originals: Vec<InvoiceLine> = args[0].as_arr().iter().map(invoice_line_from_value).collect();
let credits: Vec<CreditRequest> = args[1].as_arr().iter().map(credit_request_from_value).collect();
invoice_to_value(&calculate_credit_note(&originals, &credits, args[2].as_str(), args[3].as_str()))
}