From fc7f40a373112a9acc3a378ad11a7624c6e904da Mon Sep 17 00:00:00 2001 From: Marshal Date: Fri, 7 Aug 2026 07:18:12 +0000 Subject: [PATCH] fix wagon cancellation --- .../bookings/booking-transition.service.ts | 39 +++++++++++++++++++ .../bookings/detail/BookingFactsCard.tsx | 17 +++++++- .../bookings/detail/booking-detail.styles.ts | 6 +++ .../BookingDetailPage/booking-detail-types.ts | 6 +++ .../components/ScheduleCard.tsx | 8 +++- 5 files changed, 74 insertions(+), 2 deletions(-) diff --git a/apps/edr-freight-api/src/modules/bookings/booking-transition.service.ts b/apps/edr-freight-api/src/modules/bookings/booking-transition.service.ts index ae0791965..7cc92be87 100644 --- a/apps/edr-freight-api/src/modules/bookings/booking-transition.service.ts +++ b/apps/edr-freight-api/src/modules/bookings/booking-transition.service.ts @@ -8,6 +8,9 @@ import { Optional, } from "@nestjs/common"; import { EventEmitter2, OnEvent } from "@nestjs/event-emitter"; +import { DataSource } from "typeorm"; + +import { TrainSchedule } from '../train-schedules/entities/train-schedule.entity'; import { BookingBatchService, @@ -65,6 +68,9 @@ export class BookingTransitionService { private readonly notifier: BookingLifecycleNotifierService, private readonly events: EventEmitter2, @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 { @@ -1271,6 +1277,12 @@ export class BookingTransitionService { /** Flat list of physical container numbers on this booking (for the * customer truck-assignment container picker). */ 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 @@ -1323,6 +1335,32 @@ export class BookingTransitionService { `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 // units), flattened for the customer truck-assignment container picker. const containerNumbers = (booking.bookingContainers ?? []) @@ -1337,6 +1375,7 @@ export class BookingTransitionService { nextStep, activeBatchOffer, containerNumbers, + trainSchedule, }; } } diff --git a/apps/edr-freight-web/backoffice/src/components/bookings/detail/BookingFactsCard.tsx b/apps/edr-freight-web/backoffice/src/components/bookings/detail/BookingFactsCard.tsx index 15e81bd42..f9f8d1414 100644 --- a/apps/edr-freight-web/backoffice/src/components/bookings/detail/BookingFactsCard.tsx +++ b/apps/edr-freight-web/backoffice/src/components/bookings/detail/BookingFactsCard.tsx @@ -1,6 +1,6 @@ import type { LucideIcon } from "lucide-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 { cargoTonsAndItems } from "@/utils/cargoWeight"; @@ -50,6 +50,21 @@ export function BookingFactsCard({ booking }: BookingFactsCardProps) { }, { 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 ( diff --git a/apps/edr-freight-web/backoffice/src/components/bookings/detail/booking-detail.styles.ts b/apps/edr-freight-web/backoffice/src/components/bookings/detail/booking-detail.styles.ts index d3d3e3bc1..c32ab38b2 100644 --- a/apps/edr-freight-web/backoffice/src/components/bookings/detail/booking-detail.styles.ts +++ b/apps/edr-freight-web/backoffice/src/components/bookings/detail/booking-detail.styles.ts @@ -144,4 +144,10 @@ export interface BookingDetailView { bookingContainers?: BookingContainerView[]; reviewNotes?: BookingReviewNoteView[]; 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; } diff --git a/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/booking-detail-types.ts b/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/booking-detail-types.ts index 406aa9366..95bc57640 100644 --- a/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/booking-detail-types.ts +++ b/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/booking-detail-types.ts @@ -77,6 +77,12 @@ export type BookingDetail = Freight.IBooking & { reference: string; status: string; } | null; + /** The allocated train, present once the booking is placed on a schedule. */ + trainSchedule?: { + trainNumber: string | null; + reference: string | null; + scheduledDepartureDate: string | null; + } | null; }; /** diff --git a/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/ScheduleCard.tsx b/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/ScheduleCard.tsx index ab11da3a0..0d8df5cee 100644 --- a/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/ScheduleCard.tsx +++ b/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/ScheduleCard.tsx @@ -65,6 +65,12 @@ export function ScheduleCard({ const service = serviceTypeLabel(booking); const equipmentReturn = 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 ? { label: "Assigned train", @@ -85,7 +91,7 @@ export function ScheduleCard({ fontSize: 13, }} > - Track shipment + {trainLabel} ), }