Functional Weave
Code in Rust

charity.fundraising-ratio@1.0.0

impl/python.py

1,991 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 .charity_fundraising_ratio_types import FundraisingRatios
from .math_round_div import round_div  ← from math.round-div ^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_currency_digits import currency_digits  ← from money.currency-digits ^1.0.0 · built alongside by fune


def _check(name: str, currency: str, amount: Money) -> None:
    if amount.currency != currency:
        raise ValueError("currency mismatch: %s and %s" % (amount.currency, currency))
    if amount.minor < 0:
        raise ValueError("%s must not be negative, received %d" % (name, amount.minor))


def fundraising_ratios(
    fundraising_costs: Money,
    funds_raised: Money,
    charitable_spend: Money,
    total_expenditure: Money,
) -> FundraisingRatios:
    """Cost to raise £1 and the share of spending that went on the charity's
    purposes. Each ratio is divided once from the integer amounts and rounded
    half up.
    """
    currency = fundraising_costs.currency
    _check("fundraisingCosts", currency, fundraising_costs)
    _check("fundsRaised", currency, funds_raised)
    _check("charitableSpend", currency, charitable_spend)
    _check("totalExpenditure", currency, total_expenditure)
    if funds_raised.minor == 0:
        raise ValueError("fundsRaised must be positive to work out a cost to raise")
    if total_expenditure.minor == 0:
        raise ValueError("totalExpenditure must be positive to work out a charitable spend ratio")
    if charitable_spend.minor > total_expenditure.minor:
        raise ValueError(
            "charitableSpend of %d is more than totalExpenditure of %d" % (charitable_spend.minor, total_expenditure.minor)
        )
    unit = 10 ** currency_digits(currency)
    return FundraisingRatios(
        cost_to_raise_one=money(round_div(fundraising_costs.minor * unit, funds_raised.minor, "half-up"), currency),
        cost_ratio_basis_points=round_div(fundraising_costs.minor * 10000, funds_raised.minor, "half-up"),
        charitable_spend_basis_points=round_div(charitable_spend.minor * 10000, total_expenditure.minor, "half-up"),
    )