Functional Weave
Code in Python

retail.shipping-rate@1.0.0

impl/python.py

3,085 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 re
from typing import Optional, Sequence

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_compare import compare_money  ← from money.compare ^1.0.0 · built alongside by fune
from .retail_volumetric_weight import chargeable_weight  ← from retail.volumetric-weight ^1.0.0 · built alongside by fune
from .retail_shipping_rate_types import ShippingBand, Parcel, ShippingQuote

_ISO_DATE = re.compile(r"^\d{4}-\d{2}-\d{2}$")


def _whole(value: object) -> bool:
    return isinstance(value, int) and not isinstance(value, bool)


def _chargeable_in(band: ShippingBand, parcel: Parcel) -> int:
    if band.volumetric_divisor is None:
        return round_div(parcel.actual_grams, band.round_up_to_grams, "up") * band.round_up_to_grams
    return chargeable_weight(
        parcel.length_mm,
        parcel.width_mm,
        parcel.height_mm,
        parcel.actual_grams,
        band.volumetric_divisor,
        band.round_up_to_grams,
    ).chargeable_grams


def shipping_rate(
    bands: Sequence[ShippingBand],
    service: str,
    zone: str,
    parcel: Parcel,
    basket_total: Money,
    on_date: str,
) -> ShippingQuote:
    """The delivery charge for a parcel: the smallest band on the rate card in
    force on the order date that takes it, free when the basket reaches the
    band's threshold.
    """
    if not isinstance(on_date, str) or not _ISO_DATE.match(on_date):
        raise ValueError('onDate must be an ISO date (YYYY-MM-DD), received "%s"' % (on_date,))
    for d in (parcel.length_mm, parcel.width_mm, parcel.height_mm):
        if not _whole(d) or d < 1:
            raise ValueError("dimensions must be 1 mm or more, received %r" % (d,))
    if not _whole(parcel.actual_grams) or parcel.actual_grams < 0:
        raise ValueError("actualGrams must not be negative, received %r" % (parcel.actual_grams,))
    longest = max(parcel.length_mm, parcel.width_mm, parcel.height_mm)

    best: Optional[ShippingBand] = None
    best_grams = 0
    for band in bands:
        if band.service != service or band.zone != zone:
            continue
        if on_date < band.valid_from or (band.valid_to is not None and on_date > band.valid_to):
            continue
        if band.max_length_mm is not None and longest > band.max_length_mm:
            continue
        grams = _chargeable_in(band, parcel)
        if grams > band.max_grams:
            continue
        if (
            best is None
            or band.max_grams < best.max_grams
            or (band.max_grams == best.max_grams and compare_money(band.price, best.price) < 0)
        ):
            best = band
            best_grams = grams
    if best is None:
        raise ValueError(
            'no shipping band for service "%s" to zone "%s" on %s fits this parcel' % (service, zone, on_date)
        )

    free = best.free_over is not None and compare_money(basket_total, best.free_over) >= 0
    return ShippingQuote(
        service=service,
        zone=zone,
        chargeable_grams=best_grams,
        band_max_grams=best.max_grams,
        standard_price=best.price,
        price=money(0, best.price.currency) if free else best.price,
        free=free,
    )