mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 18:48:11 +00:00
Merge pull request #1152 from Tria-plc/freight_feature/usermanagement
fix wagon cancellation
This commit is contained in:
@@ -8,6 +8,9 @@ import {
|
|||||||
Optional,
|
Optional,
|
||||||
} from "@nestjs/common";
|
} from "@nestjs/common";
|
||||||
import { EventEmitter2, OnEvent } from "@nestjs/event-emitter";
|
import { EventEmitter2, OnEvent } from "@nestjs/event-emitter";
|
||||||
|
import { DataSource } from "typeorm";
|
||||||
|
|
||||||
|
import { TrainSchedule } from '../train-schedules/entities/train-schedule.entity';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
BookingBatchService,
|
BookingBatchService,
|
||||||
@@ -65,6 +68,9 @@ export class BookingTransitionService {
|
|||||||
private readonly notifier: BookingLifecycleNotifierService,
|
private readonly notifier: BookingLifecycleNotifierService,
|
||||||
private readonly events: EventEmitter2,
|
private readonly events: EventEmitter2,
|
||||||
@Optional() private readonly milestoneService?: ClearanceMilestoneService,
|
@Optional() private readonly milestoneService?: ClearanceMilestoneService,
|
||||||
|
// Optional + last so the hand-constructed service in *.spec.ts files keeps
|
||||||
|
// compiling; Nest injects it normally at runtime.
|
||||||
|
@Optional() private readonly dataSource?: DataSource,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
private isPhasedCustoms(booking: Booking): boolean {
|
private isPhasedCustoms(booking: Booking): boolean {
|
||||||
@@ -1271,6 +1277,12 @@ export class BookingTransitionService {
|
|||||||
/** Flat list of physical container numbers on this booking (for the
|
/** Flat list of physical container numbers on this booking (for the
|
||||||
* customer truck-assignment container picker). */
|
* customer truck-assignment container picker). */
|
||||||
containerNumbers: string[];
|
containerNumbers: string[];
|
||||||
|
/** The allocated train, when the booking is placed on a schedule. */
|
||||||
|
trainSchedule?: {
|
||||||
|
trainNumber: string | null;
|
||||||
|
reference: string | null;
|
||||||
|
scheduledDepartureDate: Date | null;
|
||||||
|
} | null;
|
||||||
}
|
}
|
||||||
> {
|
> {
|
||||||
// This enrichment runs AFTER the transition has committed. A failure here
|
// This enrichment runs AFTER the transition has committed. A failure here
|
||||||
@@ -1323,6 +1335,32 @@ export class BookingTransitionService {
|
|||||||
`enrichBookingResponse: batch-offer lookup failed for ${booking.id}: ${(err as Error).message}`,
|
`enrichBookingResponse: batch-offer lookup failed for ${booking.id}: ${(err as Error).message}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
// Allocated train: number + schedule reference for the detail headers
|
||||||
|
// (portal and backoffice). Degrades to null like every fragile field here.
|
||||||
|
let trainSchedule: {
|
||||||
|
trainNumber: string | null;
|
||||||
|
reference: string | null;
|
||||||
|
scheduledDepartureDate: Date | null;
|
||||||
|
} | null = null;
|
||||||
|
if (booking.trainScheduleId && this.dataSource) {
|
||||||
|
try {
|
||||||
|
const s = await this.dataSource.getRepository(TrainSchedule).findOne({
|
||||||
|
where: { id: booking.trainScheduleId },
|
||||||
|
});
|
||||||
|
if (s) {
|
||||||
|
trainSchedule = {
|
||||||
|
trainNumber: s.trainNumber ?? null,
|
||||||
|
reference: s.reference ?? null,
|
||||||
|
scheduledDepartureDate: s.scheduledDepartureDate ?? null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
this.logger.warn(
|
||||||
|
`enrichBookingResponse: train-schedule lookup failed for ${booking.id}: ${(err as Error).message}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Physical container numbers entered at booking time (booking_container
|
// Physical container numbers entered at booking time (booking_container
|
||||||
// units), flattened for the customer truck-assignment container picker.
|
// units), flattened for the customer truck-assignment container picker.
|
||||||
const containerNumbers = (booking.bookingContainers ?? [])
|
const containerNumbers = (booking.bookingContainers ?? [])
|
||||||
@@ -1337,6 +1375,7 @@ export class BookingTransitionService {
|
|||||||
nextStep,
|
nextStep,
|
||||||
activeBatchOffer,
|
activeBatchOffer,
|
||||||
containerNumbers,
|
containerNumbers,
|
||||||
|
trainSchedule,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { LucideIcon } from "lucide-react";
|
import type { LucideIcon } from "lucide-react";
|
||||||
import type { ReactNode } from "react";
|
import type { ReactNode } from "react";
|
||||||
import { Hash, Package, Ship, Weight, Clock } from "lucide-react";
|
import { Hash, Package, Ship, Weight, Clock, TrainFront } from "lucide-react";
|
||||||
import { Group, Stack, Text, Divider } from "@mantine/core";
|
import { Group, Stack, Text, Divider } from "@mantine/core";
|
||||||
|
|
||||||
import { cargoTonsAndItems } from "@/utils/cargoWeight";
|
import { cargoTonsAndItems } from "@/utils/cargoWeight";
|
||||||
@@ -50,6 +50,21 @@ export function BookingFactsCard({ booking }: BookingFactsCardProps) {
|
|||||||
},
|
},
|
||||||
{ icon: Clock, label: "Last Updated", value: formatDate(booking.updatedAt) },
|
{ icon: Clock, label: "Last Updated", value: formatDate(booking.updatedAt) },
|
||||||
];
|
];
|
||||||
|
// Allocated train facts — only once the booking rides a schedule.
|
||||||
|
if (booking.trainSchedule?.trainNumber || booking.trainSchedule?.reference) {
|
||||||
|
facts.splice(1, 0, {
|
||||||
|
icon: TrainFront,
|
||||||
|
label: "Allocated Train",
|
||||||
|
value: [
|
||||||
|
booking.trainSchedule.trainNumber
|
||||||
|
? `Train ${booking.trainSchedule.trainNumber}`
|
||||||
|
: null,
|
||||||
|
booking.trainSchedule.reference ?? null,
|
||||||
|
]
|
||||||
|
.filter(Boolean)
|
||||||
|
.join(" · "),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionCard icon={Hash} title="Booking Details" accent="cyan">
|
<SectionCard icon={Hash} title="Booking Details" accent="cyan">
|
||||||
|
|||||||
@@ -144,4 +144,10 @@ export interface BookingDetailView {
|
|||||||
bookingContainers?: BookingContainerView[];
|
bookingContainers?: BookingContainerView[];
|
||||||
reviewNotes?: BookingReviewNoteView[];
|
reviewNotes?: BookingReviewNoteView[];
|
||||||
files?: BookingFileView[];
|
files?: BookingFileView[];
|
||||||
|
/** The allocated train, present once the booking is placed on a schedule. */
|
||||||
|
trainSchedule?: {
|
||||||
|
trainNumber: string | null;
|
||||||
|
reference: string | null;
|
||||||
|
scheduledDepartureDate: string | null;
|
||||||
|
} | null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,6 +77,12 @@ export type BookingDetail = Freight.IBooking & {
|
|||||||
reference: string;
|
reference: string;
|
||||||
status: string;
|
status: string;
|
||||||
} | null;
|
} | null;
|
||||||
|
/** The allocated train, present once the booking is placed on a schedule. */
|
||||||
|
trainSchedule?: {
|
||||||
|
trainNumber: string | null;
|
||||||
|
reference: string | null;
|
||||||
|
scheduledDepartureDate: string | null;
|
||||||
|
} | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -65,6 +65,12 @@ export function ScheduleCard({
|
|||||||
const service = serviceTypeLabel(booking);
|
const service = serviceTypeLabel(booking);
|
||||||
const equipmentReturn =
|
const equipmentReturn =
|
||||||
booking.equipmentReturn === "WITH_RETURN" ? "With return" : "Without return";
|
booking.equipmentReturn === "WITH_RETURN" ? "With return" : "Without return";
|
||||||
|
const schedule = booking.trainSchedule;
|
||||||
|
const trainLabel = schedule?.trainNumber
|
||||||
|
? `Train ${schedule.trainNumber}${schedule.reference ? ` · ${schedule.reference}` : ""}`
|
||||||
|
: schedule?.reference
|
||||||
|
? `Schedule ${schedule.reference}`
|
||||||
|
: "Track shipment";
|
||||||
const assignedTrain: Row = booking.trainScheduleId
|
const assignedTrain: Row = booking.trainScheduleId
|
||||||
? {
|
? {
|
||||||
label: "Assigned train",
|
label: "Assigned train",
|
||||||
@@ -85,7 +91,7 @@ export function ScheduleCard({
|
|||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<MapPin size={13} /> Track shipment
|
<MapPin size={13} /> {trainLabel}
|
||||||
</button>
|
</button>
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user