mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 07:10:57 +00:00
Merge pull request #448 from Tria-plc/freight/feature/first_mile_invoice
fix
This commit is contained in:
@@ -208,6 +208,7 @@ export class FirstMileService {
|
|||||||
originYard: true,
|
originYard: true,
|
||||||
destinationYard: true,
|
destinationYard: true,
|
||||||
cargoType: true,
|
cargoType: true,
|
||||||
|
bookingContainers: { containerType: true, units: true },
|
||||||
},
|
},
|
||||||
vehicle: true,
|
vehicle: true,
|
||||||
vehicleAssignments: { vehicle: true },
|
vehicleAssignments: { vehicle: true },
|
||||||
@@ -255,6 +256,7 @@ export class FirstMileService {
|
|||||||
originYard: true,
|
originYard: true,
|
||||||
destinationYard: true,
|
destinationYard: true,
|
||||||
cargoType: true,
|
cargoType: true,
|
||||||
|
bookingContainers: { containerType: true, units: true },
|
||||||
},
|
},
|
||||||
vehicle: true,
|
vehicle: true,
|
||||||
vehicleAssignments: { vehicle: true },
|
vehicleAssignments: { vehicle: true },
|
||||||
|
|||||||
@@ -170,7 +170,7 @@ export class LastMileService {
|
|||||||
const [data, total] = await this.lastMileRepository.findAndCount({
|
const [data, total] = await this.lastMileRepository.findAndCount({
|
||||||
where,
|
where,
|
||||||
relations: {
|
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,
|
vehicle: true,
|
||||||
vehicleAssignments: { vehicle: true },
|
vehicleAssignments: { vehicle: true },
|
||||||
},
|
},
|
||||||
@@ -195,7 +195,7 @@ export class LastMileService {
|
|||||||
async findById(id: string): Promise<LastMile> {
|
async findById(id: string): Promise<LastMile> {
|
||||||
const record = await this.lastMileRepository.findById(id, {
|
const record = await this.lastMileRepository.findById(id, {
|
||||||
relations: {
|
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,
|
vehicle: true,
|
||||||
vehicleAssignments: { vehicle: true },
|
vehicleAssignments: { vehicle: true },
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -116,11 +116,25 @@ const vehicleLabel = (record: FirstMileRecord) => {
|
|||||||
const isAssigned = (record: FirstMileRecord) =>
|
const isAssigned = (record: FirstMileRecord) =>
|
||||||
Boolean(record.vehicleId) || Boolean(record.vehicleAssignments?.length);
|
Boolean(record.vehicleId) || Boolean(record.vehicleAssignments?.length);
|
||||||
|
|
||||||
/** Container numbers on a booking, in line order (skips lines without one). */
|
/** Real per-physical-container numbers on a booking, in order. Prefers each
|
||||||
const bookingContainerNumbers = (record: FirstMileRecord): string[] =>
|
* line's `units` (the actual numbers) over the line-level number (often a
|
||||||
(record.booking?.bookingContainers ?? [])
|
* "TBD-…" placeholder). One entry per physical container, for per-truck prefill. */
|
||||||
.map((c) => c.containerNumber)
|
const bookingContainerNumbers = (record: FirstMileRecord): string[] => {
|
||||||
.filter((n): n is string => Boolean(n));
|
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. */
|
/** Progress stages of the first-mile pickup workflow, for the detail stepper. */
|
||||||
const computeFirstMileSteps = (record: FirstMileRecord): LastMileStepState[] => {
|
const computeFirstMileSteps = (record: FirstMileRecord): LastMileStepState[] => {
|
||||||
|
|||||||
@@ -128,11 +128,25 @@ const requiredVehicles = (record: LastMileRecord) => {
|
|||||||
return n > 0 ? Math.ceil(n / CONTAINERS_PER_VEHICLE) : 0;
|
return n > 0 ? Math.ceil(n / CONTAINERS_PER_VEHICLE) : 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Container numbers on a booking, in line order (skips lines without one). */
|
/** Real per-physical-container numbers on a booking, in order. Prefers each
|
||||||
const bookingContainerNumbers = (record: LastMileRecord): string[] =>
|
* line's `units` (the actual numbers) over the line-level number (often a
|
||||||
(record.booking?.bookingContainers ?? [])
|
* "TBD-…" placeholder). One entry per physical container, for per-truck prefill. */
|
||||||
.map((c) => c.containerNumber)
|
const bookingContainerNumbers = (record: LastMileRecord): string[] => {
|
||||||
.filter((n): n is string => Boolean(n));
|
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
|
/** Container badges for a booking: the container number when known, else the
|
||||||
* type × quantity. */
|
* type × quantity. */
|
||||||
|
|||||||
@@ -30,6 +30,9 @@ export interface FirstMileBooking {
|
|||||||
containerNumber?: string | null;
|
containerNumber?: string | null;
|
||||||
containerSize?: string | null;
|
containerSize?: string | null;
|
||||||
containerType?: { id: string; name?: string; label?: string; code?: 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 }>;
|
||||||
}>;
|
}>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,9 @@ export interface LastMileBooking {
|
|||||||
containerNumber?: string | null;
|
containerNumber?: string | null;
|
||||||
containerSize?: string | null;
|
containerSize?: string | null;
|
||||||
containerType?: { id: string; name?: string; label?: string; code?: 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 }>;
|
||||||
}>;
|
}>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user