Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
from .agri_milk_price_types import MilkContract, MilkPrice, MilkSupply
from .math_round_div import round_div ← from math.round-div ^1.0.0 · built alongside by fune
from .money_amount import money ← from money.amount ^1.0.0 · built alongside by fune
MAX_PRICE = 1000000
MAX_LITRES = 1000000000
def _whole(value: int, name: str, low: int, high: int) -> int:
if isinstance(value, bool) or not isinstance(value, int) or value < low or value > high:
raise ValueError("%s must be a whole number from %d to %d, received %r" % (name, low, high, value))
return value
def milk_price(contract: MilkContract, supply: MilkSupply) -> MilkPrice:
"""Milk price for one period under a buyer's contract.
Prices are thousandths of a penny (or cent) per litre, because contracts
quote to 0.01 or 0.001 ppl. Constituent adjustments are pro rata per 0.1
percentage point and are each rounded to a thousandth, half away from
zero; the payment is litres x price, rounded once to the penny.
"""
money(0, contract.currency)
base = _whole(contract.base_price, "basePrice", 0, MAX_PRICE)
std_fat = _whole(contract.standard_butterfat_basis_points, "standardButterfatBasisPoints", 0, 10000)
fat_value = _whole(contract.butterfat_value, "butterfatValue", -MAX_PRICE, MAX_PRICE)
std_protein = _whole(contract.standard_protein_basis_points, "standardProteinBasisPoints", 0, 10000)
protein_value = _whole(contract.protein_value, "proteinValue", -MAX_PRICE, MAX_PRICE)
litres = _whole(supply.litres, "litres", 0, MAX_LITRES)
fat = _whole(supply.butterfat_basis_points, "butterfatBasisPoints", 0, 10000)
protein = _whole(supply.protein_basis_points, "proteinBasisPoints", 0, 10000)
month = _whole(supply.month, "month", 1, 12)
# 0.1 percentage point is 10 basis points.
fat_adjustment = round_div((fat - std_fat) * fat_value, 10, "half-up")
protein_adjustment = round_div((protein - std_protein) * protein_value, 10, "half-up")
volume_bonus = 0
previous = -1
for i, tier in enumerate(contract.volume_bonuses):
minimum = _whole(tier.minimum_litres, "volumeBonuses[%d].minimumLitres" % i, 0, MAX_LITRES)
bonus = _whole(tier.bonus, "volumeBonuses[%d].bonus" % i, -MAX_PRICE, MAX_PRICE)
if minimum <= previous:
raise ValueError("volumeBonuses must be in strictly ascending order of minimumLitres")
previous = minimum
if litres >= minimum:
volume_bonus = bonus
seasonal = 0
if len(contract.seasonality) == 12:
for i, v in enumerate(contract.seasonality):
_whole(v, "seasonality[%d]" % i, -MAX_PRICE, MAX_PRICE)
seasonal = contract.seasonality[month - 1]
elif len(contract.seasonality) != 0:
raise ValueError("seasonality must have 12 monthly values or none, received %d" % len(contract.seasonality))
price = base + fat_adjustment + protein_adjustment + volume_bonus + seasonal
if price < 0:
raise ValueError("price per litre must not be negative, received %d" % price)
if price > MAX_PRICE:
raise ValueError("price per litre must be at most %d, received %d" % (MAX_PRICE, price))
return MilkPrice(
base_price=base,
butterfat_adjustment=fat_adjustment,
protein_adjustment=protein_adjustment,
volume_bonus=volume_bonus,
seasonal_adjustment=seasonal,
price_per_litre=price,
total=money(round_div(price * litres, 1000, "half-up"), contract.currency),
)