mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
fix wagon cancellation
This commit is contained in:
@@ -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,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 (
|
||||
<SectionCard icon={Hash} title="Booking Details" accent="cyan">
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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,
|
||||
}}
|
||||
>
|
||||
<MapPin size={13} /> Track shipment
|
||||
<MapPin size={13} /> {trainLabel}
|
||||
</button>
|
||||
),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user