This commit is contained in:
natib21
2026-07-04 02:26:19 +00:00
parent 5cda247711
commit 2e31fd12e1
6 changed files with 48 additions and 12 deletions

View File

@@ -208,6 +208,7 @@ export class FirstMileService {
originYard: true,
destinationYard: true,
cargoType: true,
bookingContainers: { containerType: true, units: true },
},
vehicle: true,
vehicleAssignments: { vehicle: true },
@@ -255,6 +256,7 @@ export class FirstMileService {
originYard: true,
destinationYard: true,
cargoType: true,
bookingContainers: { containerType: true, units: true },
},
vehicle: true,
vehicleAssignments: { vehicle: true },

View File

@@ -170,7 +170,7 @@ export class LastMileService {
const [data, total] = await this.lastMileRepository.findAndCount({
where,
relations: {
booking: { company: true, serviceType: true, originYard: true, destinationYard: true, cargoType: true, bookingContainers: { containerType: true } },
booking: { company: true, serviceType: true, originYard: true, destinationYard: true, cargoType: true, bookingContainers: { containerType: true, units: true } },
vehicle: true,
vehicleAssignments: { vehicle: true },
},
@@ -195,7 +195,7 @@ export class LastMileService {
async findById(id: string): Promise<LastMile> {
const record = await this.lastMileRepository.findById(id, {
relations: {
booking: { company: true, serviceType: true, originYard: true, destinationYard: true, cargoType: true, bookingContainers: { containerType: true } },
booking: { company: true, serviceType: true, originYard: true, destinationYard: true, cargoType: true, bookingContainers: { containerType: true, units: true } },
vehicle: true,
vehicleAssignments: { vehicle: true },
},

View File

@@ -116,11 +116,25 @@ const vehicleLabel = (record: FirstMileRecord) => {
const isAssigned = (record: FirstMileRecord) =>
Boolean(record.vehicleId) || Boolean(record.vehicleAssignments?.length);
/** Container numbers on a booking, in line order (skips lines without one). */
const bookingContainerNumbers = (record: FirstMileRecord): string[] =>
(record.booking?.bookingContainers ?? [])
.map((c) => c.containerNumber)
.filter((n): n is string => Boolean(n));
/** Real per-physical-container numbers on a booking, in order. Prefers each
* line's `units` (the actual numbers) over the line-level number (often a
* "TBD-…" placeholder). One entry per physical container, for per-truck prefill. */
const bookingContainerNumbers = (record: FirstMileRecord): string[] => {
const out: string[] = [];
const real = (n?: string | null): n is string =>
Boolean(n) && !/^TBD/i.test(n!.trim());
for (const c of record.booking?.bookingContainers ?? []) {
const units = [...(c.units ?? [])].sort(
(a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0),
);
if (units.length) {
for (const u of units) if (real(u.containerNumber)) out.push(u.containerNumber!);
} else if (real(c.containerNumber)) {
out.push(c.containerNumber!);
}
}
return out;
};
/** Progress stages of the first-mile pickup workflow, for the detail stepper. */
const computeFirstMileSteps = (record: FirstMileRecord): LastMileStepState[] => {

View File

@@ -128,11 +128,25 @@ const requiredVehicles = (record: LastMileRecord) => {
return n > 0 ? Math.ceil(n / CONTAINERS_PER_VEHICLE) : 0;
};
/** Container numbers on a booking, in line order (skips lines without one). */
const bookingContainerNumbers = (record: LastMileRecord): string[] =>
(record.booking?.bookingContainers ?? [])
.map((c) => c.containerNumber)
.filter((n): n is string => Boolean(n));
/** Real per-physical-container numbers on a booking, in order. Prefers each
* line's `units` (the actual numbers) over the line-level number (often a
* "TBD-…" placeholder). One entry per physical container, for per-truck prefill. */
const bookingContainerNumbers = (record: LastMileRecord): string[] => {
const out: string[] = [];
const real = (n?: string | null): n is string =>
Boolean(n) && !/^TBD/i.test(n!.trim());
for (const c of record.booking?.bookingContainers ?? []) {
const units = [...(c.units ?? [])].sort(
(a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0),
);
if (units.length) {
for (const u of units) if (real(u.containerNumber)) out.push(u.containerNumber!);
} else if (real(c.containerNumber)) {
out.push(c.containerNumber!);
}
}
return out;
};
/** Container badges for a booking: the container number when known, else the
* type × quantity. */

View File

@@ -30,6 +30,9 @@ export interface FirstMileBooking {
containerNumber?: string | null;
containerSize?: string | null;
containerType?: { id: string; name?: string; label?: string; code?: string } | null;
/** Physical containers under this line — their real numbers (line-level
* containerNumber is often a TBD placeholder). */
units?: Array<{ id: string; containerNumber?: string | null; sortOrder?: number }>;
}>;
}

View File

@@ -30,6 +30,9 @@ export interface LastMileBooking {
containerNumber?: string | null;
containerSize?: string | null;
containerType?: { id: string; name?: string; label?: string; code?: string } | null;
/** Physical containers under this line — their real numbers (line-level
* containerNumber is often a TBD placeholder). */
units?: Array<{ id: string; containerNumber?: string | null; sortOrder?: number }>;
}>;
}