feat: add per-ton cargo loading limits and update related services

This commit is contained in:
Marshal
2026-08-03 19:16:28 +00:00
parent 9afc281d21
commit 488c2465be
14 changed files with 394 additions and 21 deletions

View File

@@ -71,6 +71,7 @@ import {
bookingCargoTons,
bulkItemsFitFor,
bulkItemWagonsRequired,
bulkTonsPerWagon,
bookingGrossWeightTons,
deriveTrainCapacityFromLocomotive,
sizePartialOfferWagons,
@@ -4100,8 +4101,15 @@ export class BookingBatchService implements OnModuleInit {
const capacityTons = this.dimsFor(booking, wagonDims).capacityTons;
const cargoTons = bookingCargoTons(booking);
// PER_TON cargo may cap tons per wagon below the rating (sugar 50T on a 70T
// wagon), so divide by the cap where one is configured for this type.
const tonsPerWagon = bulkTonsPerWagon(
booking.cargoType,
booking.cargoType?.wagonTypes?.[0]?.id,
capacityTons,
);
const byWeight =
cargoTons > 0 && capacityTons > 0 ? Math.ceil(cargoTons / capacityTons) : 0;
cargoTons > 0 && tonsPerWagon > 0 ? Math.ceil(cargoTons / tonsPerWagon) : 0;
// Break-bulk (PER_ITEM): indivisible items can need more wagons than raw
// tonnage suggests (floor items-per-wagon loses the fractional capacity).
@@ -4169,6 +4177,13 @@ export class BookingBatchService implements OnModuleInit {
.filter((o) => o.wagonTypeId && (stockByTypeId.get(o.wagonTypeId) ?? 0) > 0)
.map((o) => {
const wagonTypeId = o.wagonTypeId as string;
// Each type sized on its OWN per-wagon tonnage cap, not just its rating
// — a type capped lower swallows less per wagon.
const tonsPerWagon = bulkTonsPerWagon(
booking.cargoType,
wagonTypeId,
o.dims.capacityTons,
);
const wagonsIfAlone = Math.max(
1,
bulkItemWagonsRequired(
@@ -4176,8 +4191,8 @@ export class BookingBatchService implements OnModuleInit {
o.dims.capacityTons,
bulkItemsFitFor(booking.cargoType, wagonTypeId),
) ||
(o.dims.capacityTons > 0
? Math.ceil(bookingCargoTons(booking) / o.dims.capacityTons)
(tonsPerWagon > 0
? Math.ceil(bookingCargoTons(booking) / tonsPerWagon)
: total),
);
return {