mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-02 06:53:38 +00:00
feat: add per-ton cargo loading limits and update related services
This commit is contained in:
@@ -152,8 +152,98 @@ export function bulkItemWagonsRequired(
|
||||
type ItemFitCargoType = {
|
||||
wagonTypes?: Array<{ id: string; capacityTons?: number | string | null }> | null;
|
||||
itemsPerWagonMap?: Record<string, number> | null;
|
||||
tonsPerWagonMap?: Record<string, number> | null;
|
||||
} | null;
|
||||
|
||||
/**
|
||||
* Tons of THIS cargo one wagon of this type may carry: the cargo type's
|
||||
* configured loading limit when set, else the wagon's full rated capacity.
|
||||
* Sugar capped at 50T rides 50T on a 70T wagon, so 200T needs 4 wagons and each
|
||||
* is loaded to 50 — both the count and the fill follow from this one number.
|
||||
*
|
||||
* The configured cap is CLAMPED to the rated capacity rather than trusted: the
|
||||
* cargo-types service rejects a cap above capacity at save time, but a wagon
|
||||
* type edited DOWN afterwards would leave a stale cap that overloads the wagon.
|
||||
* Clamping here means no call site can ever load past the physical rating.
|
||||
*/
|
||||
export function bulkTonsPerWagon(
|
||||
cargoType: ItemFitCargoType | undefined,
|
||||
wagonTypeId: string | null | undefined,
|
||||
capacityTons: number | string | null | undefined,
|
||||
): number {
|
||||
const capacity = num(capacityTons);
|
||||
const cap = wagonTypeId ? num(cargoType?.tonsPerWagonMap?.[wagonTypeId]) : 0;
|
||||
if (!(cap > 0)) return capacity;
|
||||
return capacity > 0 ? Math.min(cap, capacity) : cap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wagons a PER_TON bulk booking needs on one wagon type, respecting the cargo
|
||||
* type's per-wagon loading limit: 200T of sugar capped at 50T → 4 wagons even
|
||||
* though the wagon is rated 70T. Returns 0 when there is no tonnage or no
|
||||
* usable per-wagon figure, so callers can fall back as before.
|
||||
*/
|
||||
export function bulkTonWagonsRequired(
|
||||
booking: Parameters<typeof bookingCargoTons>[0],
|
||||
cargoType: ItemFitCargoType | undefined,
|
||||
wagonTypeId: string | null | undefined,
|
||||
capacityTons: number | string | null | undefined,
|
||||
): number {
|
||||
const perWagon = bulkTonsPerWagon(cargoType, wagonTypeId, capacityTons);
|
||||
const tons = bookingCargoTons(booking);
|
||||
if (!(perWagon > 0) || !(tons > 0)) return 0;
|
||||
return Math.max(1, Math.ceil(tons / perWagon));
|
||||
}
|
||||
|
||||
/**
|
||||
* Best (fewest-wagon) PER_TON count across the cargo type's allowed wagon
|
||||
* types, each sized on its OWN loading limit — the tonnage twin of
|
||||
* {@link bulkItemWagonsForAllowedTypes}, for the call sites that have no single
|
||||
* wagon type fixed yet. Falls back to `fallbackCapacityTons` when the cargo
|
||||
* type has no usable allowed types.
|
||||
*/
|
||||
export function bulkTonWagonsForAllowedTypes(
|
||||
booking: Parameters<typeof bookingCargoTons>[0],
|
||||
cargoType: ItemFitCargoType | undefined,
|
||||
fallbackCapacityTons: number,
|
||||
): number {
|
||||
const allowed = (cargoType?.wagonTypes ?? []).filter((wt) => num(wt.capacityTons) > 0);
|
||||
if (!allowed.length) {
|
||||
return bulkTonWagonsRequired(booking, cargoType, null, fallbackCapacityTons);
|
||||
}
|
||||
let best = 0;
|
||||
for (const wagonType of allowed) {
|
||||
const wagons = bulkTonWagonsRequired(
|
||||
booking,
|
||||
cargoType,
|
||||
wagonType.id,
|
||||
wagonType.capacityTons,
|
||||
);
|
||||
if (wagons > 0 && (best === 0 || wagons < best)) best = wagons;
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wagons a BULK booking needs, whichever way its cargo is measured: PER_ITEM
|
||||
* sizes by indivisible items, everything else by tonnage under the cargo type's
|
||||
* per-wagon loading limit. One call so no site has to remember both paths.
|
||||
*/
|
||||
export function bulkWagonsForAllowedTypes(
|
||||
booking: Parameters<typeof bookingCargoTons>[0] & {
|
||||
freightType?: string | null;
|
||||
cargoTotalWeightVgm?: number | string | null;
|
||||
bulkTotalWeightTons?: number | string | null;
|
||||
},
|
||||
cargoType: ItemFitCargoType | undefined,
|
||||
fallbackCapacityTons: number,
|
||||
): number {
|
||||
return (
|
||||
bulkItemWagonsForAllowedTypes(booking, cargoType, fallbackCapacityTons) ||
|
||||
bulkTonWagonsForAllowedTypes(booking, cargoType, fallbackCapacityTons)
|
||||
);
|
||||
}
|
||||
|
||||
/** Configured whole-items fit of one wagon type for a cargo type; null if unset. */
|
||||
export function bulkItemsFitFor(
|
||||
cargoType: ItemFitCargoType | undefined,
|
||||
|
||||
Reference in New Issue
Block a user