From 950d539e373458ff96b5729a78179044d45c363b Mon Sep 17 00:00:00 2001 From: Marshal Date: Fri, 31 Jul 2026 12:28:37 +0000 Subject: [PATCH] fix issue --- .../train-scheduling.service.ts | 55 ++++++++++++++++++- .../trainScheduling/ScheduleHistoryPanel.tsx | 9 ++- .../src/services/trainBuilder.service.ts | 2 +- 3 files changed, 62 insertions(+), 4 deletions(-) diff --git a/apps/edr-freight-api/src/modules/train-scheduling/train-scheduling.service.ts b/apps/edr-freight-api/src/modules/train-scheduling/train-scheduling.service.ts index 3ad36cc41..0648ac12c 100644 --- a/apps/edr-freight-api/src/modules/train-scheduling/train-scheduling.service.ts +++ b/apps/edr-freight-api/src/modules/train-scheduling/train-scheduling.service.ts @@ -6417,7 +6417,60 @@ export class TrainSchedulingService { action: 'BOOKING_REMOVED', yardLabel: null, })); - return [...wagonRows, ...bookingRows].sort( + // Per-booking journey events (load at boarding yard / unload at alighting + // yard) — sourced from the booking's own loaded_at/arrived_at stamps, so a + // multi-stop train's disjoint legs (a→b loads then unloads at b while a→c + // rides through) each show as their own row. Append-only: these columns are + // only ever set once per booking, never cleared, so rows never disappear. + const journeyRows: HistoryRow[] = ( + await this.dataSource.query( + `SELECT b.id, + b.reference AS "subject", + COALESCE(oy.label, oy.code) AS "yardLabel", + COALESCE(u.username, u.email) AS "actor", + b.loaded_at AS "occurredAt" + FROM freight.bookings b + JOIN freight.train_schedule_bookings tsb + ON tsb.booking_id = b.id AND tsb.train_schedule_id = $1 AND tsb.deleted_at IS NULL + LEFT JOIN freight.yards oy ON oy.id = b.origin_yard_id + LEFT JOIN iam.users u ON u.id = b.loaded_by_user_id + WHERE b.loaded_at IS NOT NULL + AND b.deleted_at IS NULL + ORDER BY b.loaded_at DESC + LIMIT 200`, + [scheduleId], + ) + ).map((r: Omit) => ({ + ...r, + kind: 'BOOKING' as const, + action: 'BOOKING_LOADED', + note: null, + })); + const unloadRows: HistoryRow[] = ( + await this.dataSource.query( + `SELECT b.id, + b.reference AS "subject", + COALESCE(dy.label, dy.code) AS "yardLabel", + COALESCE(u.username, u.email) AS "actor", + b.arrived_at AS "occurredAt" + FROM freight.bookings b + JOIN freight.train_schedule_bookings tsb + ON tsb.booking_id = b.id AND tsb.train_schedule_id = $1 AND tsb.deleted_at IS NULL + LEFT JOIN freight.yards dy ON dy.id = b.destination_yard_id + LEFT JOIN iam.users u ON u.id = b.arrived_by_user_id + WHERE b.arrived_at IS NOT NULL + AND b.deleted_at IS NULL + ORDER BY b.arrived_at DESC + LIMIT 200`, + [scheduleId], + ) + ).map((r: Omit) => ({ + ...r, + kind: 'BOOKING' as const, + action: 'BOOKING_UNLOADED', + note: null, + })); + return [...wagonRows, ...bookingRows, ...journeyRows, ...unloadRows].sort( (a, b) => new Date(b.occurredAt).getTime() - new Date(a.occurredAt).getTime(), ); } diff --git a/apps/edr-freight-web/backoffice/src/components/trainScheduling/ScheduleHistoryPanel.tsx b/apps/edr-freight-web/backoffice/src/components/trainScheduling/ScheduleHistoryPanel.tsx index 49029615f..729c7a5d4 100644 --- a/apps/edr-freight-web/backoffice/src/components/trainScheduling/ScheduleHistoryPanel.tsx +++ b/apps/edr-freight-web/backoffice/src/components/trainScheduling/ScheduleHistoryPanel.tsx @@ -13,7 +13,9 @@ import { History, MapPin, Minus, + PackageCheck, PackageMinus, + PackageOpen, Plus, User, } from "lucide-react"; @@ -29,6 +31,8 @@ const ACTION_META: Record< REMOVE: { label: "Wagon trimmed", color: "red", icon: Minus }, SWITCH: { label: "Wagon switched", color: "blue", icon: ArrowLeftRight }, BOOKING_REMOVED: { label: "Booking removed", color: "orange", icon: PackageMinus }, + BOOKING_LOADED: { label: "Booking loaded", color: "edr-green", icon: PackageCheck }, + BOOKING_UNLOADED: { label: "Booking unloaded", color: "blue", icon: PackageOpen }, }; /** @@ -57,8 +61,9 @@ export default function ScheduleHistoryPanel({ scheduleId }: { scheduleId: strin Change history - Wagons coupled, trimmed or switched — and bookings removed — after - this train was scheduled, newest first. + Wagons coupled, trimmed or switched, bookings loaded/unloaded per + yard, and bookings removed — after this train was scheduled, + newest first. diff --git a/apps/edr-freight-web/backoffice/src/services/trainBuilder.service.ts b/apps/edr-freight-web/backoffice/src/services/trainBuilder.service.ts index 1d61788f6..3d2891415 100644 --- a/apps/edr-freight-web/backoffice/src/services/trainBuilder.service.ts +++ b/apps/edr-freight-web/backoffice/src/services/trainBuilder.service.ts @@ -278,7 +278,7 @@ export interface AdjustConsistPayload { export interface ScheduleHistoryEntry { id: string; kind: "WAGON" | "BOOKING"; - action: "ADD" | "REMOVE" | "SWITCH" | "BOOKING_REMOVED"; + action: "ADD" | "REMOVE" | "SWITCH" | "BOOKING_REMOVED" | "BOOKING_LOADED" | "BOOKING_UNLOADED"; subject: string | null; yardLabel: string | null; actor: string | null;