Functional Weave
Code in Rust

agri.gross-margin@1.0.0

impl/python.py

2,638 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.

import math
from typing import Sequence

from .agri_gross_margin_types import GrossMargin, MarginBasis, MarginLine
from .math_round_div import round_div  ← from math.round-div ^1.0.0 · built alongside by fune
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_sum import sum_money  ← from money.sum ^1.0.0 · built alongside by fune

MAX_MINOR = 900000000000


def gross_margin(
    outputs: Sequence[MarginLine],
    variable_costs: Sequence[MarginLine],
    per: MarginBasis,
    units: float,
    currency: str,
) -> GrossMargin:
    """Gross margin: enterprise output less its variable costs, per hectare or head.

    Each per-unit figure is its own total divided once, half up. Taking output
    per head less costs per head instead can be a penny out: 3 head with 10000
    output and 5000 costs is 3333 - 1667 = 1666 that way, but 5000 / 3 = 1667.
    """
    if per == "hectare":
        if isinstance(units, bool) or not isinstance(units, (int, float)) or not math.isfinite(units) or units <= 0 or units > 10000000:
            raise ValueError("units must be a finite number of hectares greater than 0 and at most 10000000, received %r" % (units,))
        divisor = _round_half_away(units * 10000)
        if divisor < 1:
            raise ValueError("units must be at least 0.0001 hectares, received %r" % (units,))
        scale = 10000
    elif per == "head":
        if isinstance(units, bool) or not isinstance(units, int) or units < 1 or units > 10000000:
            raise ValueError("units must be a whole number of head from 1 to 10000000, received %r" % (units,))
        divisor = units
        scale = 1
    else:
        raise ValueError('unknown basis "%s": use hectare or head' % (per,))

    output = sum_money([line.amount for line in outputs], currency)
    costs = sum_money([line.amount for line in variable_costs], currency)
    margin = subtract_money(output, costs)
    for m in (output, costs, margin):
        if abs(m.minor) > MAX_MINOR:
            raise ValueError("totals must be within 900000000000 minor units either side of zero")

    def per_unit(m: Money) -> Money:
        return money(round_div(m.minor * scale, divisor, "half-up"), currency)

    return GrossMargin(
        output=output,
        variable_costs=costs,
        gross_margin=margin,
        output_per_unit=per_unit(output),
        variable_costs_per_unit=per_unit(costs),
        gross_margin_per_unit=per_unit(margin),
        margin_basis_points=None if output.minor == 0 else round_div(margin.minor * 10000, output.minor, "half-up"),
    )


def _round_half_away(x: float) -> int:
    # Math.round and f64::round agree with this for positive numbers.
    return int(math.floor(x + 0.5))