finance.early-payment-discount@1.0.0
impl/python.py
1,646 bytes · the Python 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.
from .dates_add_days import add_days ← from dates.add-days ^1.0.0 · built alongside by fune
from .finance_early_payment_discount_types import EarlyPaymentDiscount
from .finance_payment_terms_due_date import payment_due_date ← from finance.payment-terms-due-date ^1.0.0 · built alongside by fune
from .finance_payment_terms_due_date_types import PaymentTerms
from .money_add import subtract_money ← from money.add ^1.0.0 · built alongside by fune
from .money_amount import Money, money ← from money.amount ^1.0.0 · built alongside by fune
from .money_apply_rate import apply_rate ← from money.apply-rate ^1.0.0 · built alongside by fune
def early_payment_discount(
invoice_total: Money, invoice_date: str, terms: PaymentTerms, payment_date: str
) -> EarlyPaymentDiscount:
"""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.
"""
if invoice_total.minor < 0:
raise ValueError("invoice total must not be negative")
# Validates the terms, including a discount window that outlasts the due date.
due_date = payment_due_date(invoice_date, terms)
# Validates the payment date; ISO dates then compare as strings.
add_days(payment_date, 0)
offered = terms.discount_basis_points > 0
deadline = add_days(invoice_date, terms.discount_days) if offered else None
available = deadline is not None and payment_date <= deadline
discount = (
apply_rate(invoice_total, terms.discount_basis_points, "half-up")
if available
else money(0, invoice_total.currency)
)
return EarlyPaymentDiscount(
available=available,
discount=discount,
amount_to_pay=subtract_money(invoice_total, discount),
discount_deadline=deadline,
due_date=due_date,
)