Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
from typing import Optional, Tuple
from .logistics_container_fit_data import CONTAINERS ← this capability’s own data, compiled from data/containers.json into the same file by fune build
from .logistics_container_fit_types import ContainerFit
def _whole(value: object) -> bool:
return isinstance(value, int) and not isinstance(value, bool)
def container_fit(
container: str,
length_mm: int,
width_mm: int,
height_mm: int,
carton_grams: int,
keep_upright: bool,
max_payload_kg: Optional[int],
) -> ContainerFit:
"""How many identical cartons fit in a container or trailer: the best block
stow over the allowed orientations that pass the door, capped by payload."""
for d in (length_mm, width_mm, height_mm):
if not _whole(d) or d < 1:
raise ValueError("carton dimensions must be 1 mm or more, received %r" % (d,))
if not _whole(carton_grams) or carton_grams < 1:
raise ValueError("cartonGrams must be 1 or more, received %r" % (carton_grams,))
spec = next((c for c in CONTAINERS if c.code == container), None)
if spec is None:
raise ValueError(
'unknown container "%s": expected %s' % (container, ", ".join(c.code for c in CONTAINERS))
)
payload_kg = spec.max_payload_kg
if max_payload_kg is not None:
if not _whole(max_payload_kg) or max_payload_kg < 1:
raise ValueError("maxPayloadKg must be 1 or more, received %r" % (max_payload_kg,))
if max_payload_kg > spec.max_payload_kg:
raise ValueError(
"maxPayloadKg must not exceed %d kg for %s, received %d"
% (spec.max_payload_kg, container, max_payload_kg)
)
payload_kg = max_payload_kg
l, w, h = length_mm, width_mm, height_mm
# Upright first (as given, then turned on the floor), then the four tipped ones.
orientations = (
[(l, w, h), (w, l, h)]
if keep_upright
else [(l, w, h), (w, l, h), (l, h, w), (h, l, w), (w, h, l), (h, w, l)]
)
best: Optional[Tuple[int, int, int, Tuple[int, int, int]]] = None
best_count = 0
for o in orientations:
a, b, c = o
if a > spec.length_mm or b > spec.width_mm or c > spec.height_mm:
continue
# End-loaded containers: the carton's cross-section has to pass the door.
if spec.door_width_mm is not None and b > spec.door_width_mm:
continue
if spec.door_height_mm is not None and c > spec.door_height_mm:
continue
along = spec.length_mm // a
across = spec.width_mm // b
layers = spec.height_mm // c
count = along * across * layers
if best is None or count > best_count:
best = (along, across, layers, o)
best_count = count
if best is None:
raise ValueError("carton does not fit in %s in any allowed orientation" % container)
weight_limit = payload_kg * 1000 // carton_grams
cartons = min(best_count, weight_limit)
space = spec.length_mm * spec.width_mm * spec.height_mm
along, across, layers, placed = best
return ContainerFit(
container=container,
cartons=cartons,
space_limit=best_count,
weight_limit=weight_limit,
limited_by="weight" if weight_limit < best_count else "space",
along_length=along,
across_width=across,
layers=layers,
placed_length_mm=placed[0],
placed_width_mm=placed[1],
placed_height_mm=placed[2],
cargo_grams=cartons * carton_grams,
volume_used_basis_points=cartons * l * w * h * 10000 // space,
)