mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
100 lines
2.9 KiB
TypeScript
100 lines
2.9 KiB
TypeScript
import type { ContainerPlacementInput } from './utils/wagon-plan.util';
|
|
|
|
export type ContainerUnitForPlacement = {
|
|
bookingId: string;
|
|
bookingReference?: string | null;
|
|
bookingContainerId: string;
|
|
unitIndex: number;
|
|
label: string;
|
|
teuSlots?: number;
|
|
sizeFt?: number;
|
|
containerNumber?: string | null;
|
|
};
|
|
|
|
export function placeholderContainerNumber(unit: ContainerUnitForPlacement): string {
|
|
const ref = unit.bookingReference ?? unit.bookingId.slice(0, 8);
|
|
return `TBD-${ref}-${unit.unitIndex + 1}`;
|
|
}
|
|
|
|
export function isPlaceholderContainerNumber(value: string | null | undefined): boolean {
|
|
return Boolean(value?.trim().startsWith('TBD-'));
|
|
}
|
|
|
|
export function resolveContainerNumber(unit: ContainerUnitForPlacement): string {
|
|
const trimmed = unit.containerNumber?.trim();
|
|
return trimmed || placeholderContainerNumber(unit);
|
|
}
|
|
|
|
export function autoFillPlacements(
|
|
units: ContainerUnitForPlacement[],
|
|
containerSlots: number[],
|
|
): ContainerPlacementInput[] {
|
|
if (!units.length || !containerSlots.length) return [];
|
|
|
|
const placements: ContainerPlacementInput[] = [];
|
|
const MAX_TEU_PER_WAGON = 2;
|
|
let currentSlotIndex = 0;
|
|
let teuInCurrentSlot = 0;
|
|
|
|
for (const unit of units) {
|
|
const teu = unit.teuSlots ?? (unit.sizeFt && unit.sizeFt >= 40 ? 2 : 1);
|
|
|
|
if (teuInCurrentSlot > 0 && teuInCurrentSlot + teu > MAX_TEU_PER_WAGON) {
|
|
currentSlotIndex += 1;
|
|
teuInCurrentSlot = 0;
|
|
}
|
|
|
|
const sequenceNo =
|
|
containerSlots[Math.min(currentSlotIndex, containerSlots.length - 1)] ??
|
|
containerSlots[containerSlots.length - 1] ??
|
|
containerSlots[0];
|
|
|
|
placements.push({
|
|
bookingContainerId: unit.bookingContainerId,
|
|
unitIndex: unit.unitIndex,
|
|
sequenceNo,
|
|
containerNumber: resolveContainerNumber(unit),
|
|
});
|
|
|
|
teuInCurrentSlot += teu;
|
|
}
|
|
|
|
return placements;
|
|
}
|
|
|
|
export function findMissingContainerNumberIssues(
|
|
units: ContainerUnitForPlacement[],
|
|
placements: ContainerPlacementInput[],
|
|
): Array<{ bookingId: string; issue: string }> {
|
|
const issues: Array<{ bookingId: string; issue: string }> = [];
|
|
const byUnit = new Map(
|
|
placements.map((p) => [`${p.bookingContainerId}:${p.unitIndex}`, p]),
|
|
);
|
|
|
|
for (const unit of units) {
|
|
const placement = byUnit.get(`${unit.bookingContainerId}:${unit.unitIndex}`);
|
|
if (!placement?.containerNumber?.trim()) {
|
|
issues.push({
|
|
bookingId: unit.bookingId,
|
|
issue: `Missing container number for ${unit.label}`,
|
|
});
|
|
}
|
|
}
|
|
|
|
return issues;
|
|
}
|
|
|
|
export function placementsForBookings(
|
|
placements: ContainerPlacementInput[],
|
|
bookingIds: Set<string>,
|
|
units: ContainerUnitForPlacement[],
|
|
): ContainerPlacementInput[] {
|
|
const unitBookingIds = new Map(
|
|
units.map((u) => [`${u.bookingContainerId}:${u.unitIndex}`, u.bookingId]),
|
|
);
|
|
return placements.filter((p) => {
|
|
const bookingId = unitBookingIds.get(`${p.bookingContainerId}:${p.unitIndex}`);
|
|
return bookingId ? bookingIds.has(bookingId) : false;
|
|
});
|
|
}
|