mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 06:28:12 +00:00
mile
This commit is contained in:
@@ -1,8 +1,19 @@
|
||||
import { IsArray, IsUUID } from 'class-validator';
|
||||
import { IsArray, IsOptional, IsString, IsUUID, ValidateNested } from 'class-validator';
|
||||
import { Type } from 'class-transformer';
|
||||
|
||||
/** Replace the full set of vehicles assigned to a last-mile delivery. */
|
||||
export class LastMileVehicleInput {
|
||||
@IsUUID()
|
||||
vehicleId!: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
containerNumber?: string;
|
||||
}
|
||||
|
||||
/** Replace the full set of vehicles (with their container numbers) on a delivery. */
|
||||
export class SetVehiclesDto {
|
||||
@IsArray()
|
||||
@IsUUID('4', { each: true })
|
||||
vehicleIds!: string[];
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => LastMileVehicleInput)
|
||||
vehicles!: LastMileVehicleInput[];
|
||||
}
|
||||
|
||||
@@ -27,4 +27,9 @@ export class LastMileVehicleAssignment extends BaseEntity {
|
||||
@ManyToOne(() => Vehicle, { nullable: false, eager: false })
|
||||
@JoinColumn({ name: 'vehicle_id' })
|
||||
vehicle?: Vehicle;
|
||||
|
||||
/** Container this truck carries — auto-filled from the booking's container
|
||||
* number when known, else entered manually at assignment time. */
|
||||
@Column({ name: 'container_number', type: 'varchar', nullable: true })
|
||||
containerNumber?: string | null;
|
||||
}
|
||||
|
||||
@@ -145,6 +145,6 @@ export class LastMileController {
|
||||
@Param('id', ParseUUIDPipe) id: string,
|
||||
@Body() dto: SetVehiclesDto,
|
||||
) {
|
||||
return this.lastMileService.setVehicles(id, dto.vehicleIds);
|
||||
return this.lastMileService.setVehicles(id, dto.vehicles);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,19 +362,37 @@ export class LastMileService {
|
||||
* for each added/removed vehicle. The first vehicle is mirrored onto the legacy
|
||||
* `vehicleId` column for back-compat with single-vehicle readers.
|
||||
*/
|
||||
async setVehicles(id: string, vehicleIds: string[]): Promise<LastMile> {
|
||||
async setVehicles(
|
||||
id: string,
|
||||
inputs: Array<{ vehicleId: string; containerNumber?: string | null }>,
|
||||
): Promise<LastMile> {
|
||||
const existing = await this.findById(id);
|
||||
const desired = [...new Set(vehicleIds.filter(Boolean))];
|
||||
// Dedupe by vehicleId, keeping the container number; preserve order.
|
||||
const desiredMap = new Map<string, string | null>();
|
||||
for (const inp of inputs) {
|
||||
if (inp.vehicleId) desiredMap.set(inp.vehicleId, inp.containerNumber ?? null);
|
||||
}
|
||||
const desired = [...desiredMap.keys()];
|
||||
const desiredSet = new Set(desired);
|
||||
|
||||
const manager = this.dataSource.manager;
|
||||
const current = await manager.find(LastMileVehicleAssignment, {
|
||||
where: { lastMileId: id },
|
||||
});
|
||||
const currentIds = current.map((a) => a.vehicleId);
|
||||
const currentSet = new Set(currentIds);
|
||||
const desiredSet = new Set(desired);
|
||||
const added = desired.filter((v) => !currentSet.has(v));
|
||||
const removed = currentIds.filter((v) => !desiredSet.has(v));
|
||||
const junctionSet = new Set(current.map((a) => a.vehicleId));
|
||||
// Fold the legacy vehicleId into the release set — a vehicle assigned via the
|
||||
// old single-vehicle path has no junction row but must still be freed.
|
||||
const releaseIds = [...new Set(
|
||||
current.map((a) => a.vehicleId).concat(existing.vehicleId ? [existing.vehicleId] : []),
|
||||
)];
|
||||
const added = desired.filter((v) => !junctionSet.has(v));
|
||||
const removed = releaseIds.filter((v) => !desiredSet.has(v));
|
||||
// Vehicles that stay but whose container number changed.
|
||||
const changed = current.filter(
|
||||
(a) =>
|
||||
desiredMap.has(a.vehicleId) &&
|
||||
(a.containerNumber ?? null) !== (desiredMap.get(a.vehicleId) ?? null),
|
||||
);
|
||||
|
||||
await this.dataSource.transaction(async (tx) => {
|
||||
if (removed.length) {
|
||||
@@ -384,7 +402,18 @@ export class LastMileService {
|
||||
});
|
||||
}
|
||||
for (const vehicleId of added) {
|
||||
await tx.insert(LastMileVehicleAssignment, { lastMileId: id, vehicleId });
|
||||
await tx.insert(LastMileVehicleAssignment, {
|
||||
lastMileId: id,
|
||||
vehicleId,
|
||||
containerNumber: desiredMap.get(vehicleId) ?? null,
|
||||
});
|
||||
}
|
||||
for (const row of changed) {
|
||||
await tx.update(
|
||||
LastMileVehicleAssignment,
|
||||
{ lastMileId: id, vehicleId: row.vehicleId },
|
||||
{ containerNumber: desiredMap.get(row.vehicleId) ?? null },
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user