enhance shipment form and booking process

This commit is contained in:
Marshal
2026-07-22 17:25:01 +00:00
parent ef840241c0
commit 5709801590
26 changed files with 1413 additions and 330 deletions

View File

@@ -86,6 +86,27 @@ function num(value: unknown, fallback = 0): number {
return Number.isFinite(n) ? n : fallback;
}
/**
* Cargo tons of a booking: the stored VGM total when present, else the sum of
* its container lines (quantity × VGM per unit). The portal's container flow
* stores per-line VGM and leaves `cargoTotalWeightVgm` at 0 — reading the
* total alone made every such booking weigh only its tare.
*/
export function bookingCargoTons(booking: {
cargoTotalWeightVgm?: number | string | null;
bookingContainers?: Array<{
quantity?: number | null;
vgmPerUnitTons?: number | string | null;
}> | null;
}): number {
const total = num(booking.cargoTotalWeightVgm);
if (total > 0) return total;
return (booking.bookingContainers ?? []).reduce(
(sum, line) => sum + num(line.quantity) * num(line.vgmPerUnitTons),
0,
);
}
/** Gross weight of one loaded wagon: it hauls itself plus its cargo. */
export function grossWagonWeightTons(slot: Pick<ConsistSlot, 'tareWeightTons' | 'cargoTons'>): number {
return num(slot.tareWeightTons) + num(slot.cargoTons);
@@ -260,11 +281,34 @@ export function minLocomotiveLimits(
};
}
function minConfigured(values: Array<number | string | null | undefined>): number {
function minConfigured(values: Array<number | null | undefined>): number {
const configured = values.filter((v) => v != null).map((v) => num(v));
return configured.length ? Math.min(...configured) : 0;
}
/**
* Effective limits for a whole train set: min across its linked locomotives,
* falling back to the legacy single `locomotive` column for sets created
* before multi-loco support. Null when the set has no locomotive at all.
*/
export function trainSetLocomotiveLimits(
trainSet?: {
locomotive?: LocomotiveLimits | null;
locomotives?: Array<{ locomotive?: LocomotiveLimits | null }> | null;
} | null,
): LocomotiveLimits | null {
if (!trainSet) return null;
const linked = (trainSet.locomotives ?? [])
.map((link) => link.locomotive)
.filter((l): l is LocomotiveLimits => Boolean(l));
const pool = linked.length
? linked
: trainSet.locomotive
? [trainSet.locomotive]
: [];
return minLocomotiveLimits(pool);
}
/** Per-booking train length from wagon count and freight-specific wagon type length. */
export function bookingTrainLengthMeters(
freightType: string | null | undefined,