fix issue

This commit is contained in:
Marshal
2026-07-31 12:28:37 +00:00
parent 7e85c16141
commit 950d539e37
3 changed files with 62 additions and 4 deletions

View File

@@ -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<HistoryRow, 'kind' | 'action' | 'note'>) => ({
...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<HistoryRow, 'kind' | 'action' | 'note'>) => ({
...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(),
);
}

View File

@@ -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
</Text>
<Text size="sm" c="dimmed">
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.
</Text>
</Stack>
</Group>

View File

@@ -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;