mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 21:08:12 +00:00
feat(train-scheduling): show coupled/uncoupled wagons on intercity marshalling doc
Marshalling 2 rendered only the final consist after a mid-corridor adjustScheduleConsist call, with no signal that anything changed. Reuses the existing ScheduleWagonAdjustmentLog (already recording every ADD/REMOVE/SWITCH) filtered to the printed stop's yard and to ADD/SWITCH, and prints a Consist changed at this stop box. Origin import/export docs are untouched — the option is only passed from intercityMarshallingDocument.
This commit is contained in:
@@ -1209,6 +1209,32 @@ describe('TrainSchedulingService', () => {
|
|||||||
expect(html).toContain('<span>To load en route</span><strong>1 containers</strong>');
|
expect(html).toContain('<span>To load en route</span><strong>1 containers</strong>');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('prints coupled/switched wagons logged at this stop, and omits the box when there are none', () => {
|
||||||
|
const schedule = {
|
||||||
|
id: 'schedule-1',
|
||||||
|
trainNumber: '8302',
|
||||||
|
direction: 'EXPORT',
|
||||||
|
trainSet: { wagons: [{ ...makeWagon(1, 'W-001', [loadedAllocation]), id: 'slot-1' }] },
|
||||||
|
scheduleBookings: [],
|
||||||
|
};
|
||||||
|
const build = (service as never as {
|
||||||
|
buildExportLoadListHtml: (s: unknown, o?: unknown) => string;
|
||||||
|
}).buildExportLoadListHtml.bind(service);
|
||||||
|
|
||||||
|
const withChanges = build(schedule, {
|
||||||
|
consistChangesAtStop: [
|
||||||
|
{ action: 'ADD', wagonNumber: 'W-1002' },
|
||||||
|
{ action: 'SWITCH', wagonNumber: 'W-0501 → W-1003' },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
expect(withChanges).toContain('Consist changed at this stop');
|
||||||
|
expect(withChanges).toContain('Coupled: W-1002');
|
||||||
|
expect(withChanges).toContain('Uncoupled — replaced: W-0501 → W-1003');
|
||||||
|
|
||||||
|
const withoutChanges = build(schedule, {});
|
||||||
|
expect(withoutChanges).not.toContain('Consist changed at this stop');
|
||||||
|
});
|
||||||
|
|
||||||
it('lists loaded empty containers by number and states they are empty', () => {
|
it('lists loaded empty containers by number and states they are empty', () => {
|
||||||
const schedule = {
|
const schedule = {
|
||||||
id: 'schedule-1',
|
id: 'schedule-1',
|
||||||
|
|||||||
@@ -3558,6 +3558,16 @@ export class TrainSchedulingService {
|
|||||||
: `At ${schedule.originStation?.label ?? schedule.originStation?.code ?? 'origin'} — no checkpoint recorded`;
|
: `At ${schedule.originStation?.label ?? schedule.originStation?.code ?? 'origin'} — no checkpoint recorded`;
|
||||||
|
|
||||||
const { wagons, unassignedBookings } = this.intercityOnBoardView(schedule);
|
const { wagons, unassignedBookings } = this.intercityOnBoardView(schedule);
|
||||||
|
// Couples/switches logged AT THIS STOP — what staff standing here actually
|
||||||
|
// just did to the consist. Bare trims (REMOVE, no replacement) are left
|
||||||
|
// out: nothing new to point staff at for those. Origin adjustments (a
|
||||||
|
// different yard) don't show up on this stop's document.
|
||||||
|
const consistChangesAtStop = last
|
||||||
|
? await this.dataSource.getRepository(ScheduleWagonAdjustmentLog).find({
|
||||||
|
where: { trainScheduleId: scheduleId, yardId: last.yardId, action: In(['ADD', 'SWITCH']) },
|
||||||
|
order: { occurredAt: 'DESC' },
|
||||||
|
})
|
||||||
|
: [];
|
||||||
const html = this.buildExportLoadListHtml(schedule, {
|
const html = this.buildExportLoadListHtml(schedule, {
|
||||||
title: 'Intercity Marshalling Document / Load List (Marshalling 2)',
|
title: 'Intercity Marshalling Document / Load List (Marshalling 2)',
|
||||||
positionLabel,
|
positionLabel,
|
||||||
@@ -3565,6 +3575,7 @@ export class TrainSchedulingService {
|
|||||||
unassignedBookings,
|
unassignedBookings,
|
||||||
emptyContainers: await this.loadedEmptyContainers(scheduleId),
|
emptyContainers: await this.loadedEmptyContainers(scheduleId),
|
||||||
logoImageUrl: await this.logoSettings.getLogoImageUrl(),
|
logoImageUrl: await this.logoSettings.getLogoImageUrl(),
|
||||||
|
consistChangesAtStop,
|
||||||
});
|
});
|
||||||
// Styled table-aware fallback (marshalling grid) — see importLoadListDocument.
|
// Styled table-aware fallback (marshalling grid) — see importLoadListDocument.
|
||||||
const buffer = await this.pdfDocuments.renderTabularDocument(html, 'Intercity marshalling / load list');
|
const buffer = await this.pdfDocuments.renderTabularDocument(html, 'Intercity marshalling / load list');
|
||||||
@@ -3634,6 +3645,10 @@ export class TrainSchedulingService {
|
|||||||
// Slots that couple to the train downstream (slot id → board yard label).
|
// Slots that couple to the train downstream (slot id → board yard label).
|
||||||
// Their cargo renders as TO LOAD AT and stays out of the loaded tallies.
|
// Their cargo renders as TO LOAD AT and stays out of the loaded tallies.
|
||||||
pendingBoardYardLabelBySlot?: Map<string, string>;
|
pendingBoardYardLabelBySlot?: Map<string, string>;
|
||||||
|
// Intercity (Marshalling 2) only: couples/switches logged at the stop
|
||||||
|
// this document is printed at (see ScheduleWagonAdjustmentLog). Origin
|
||||||
|
// import/export docs never pass this, so they render no such box.
|
||||||
|
consistChangesAtStop?: ScheduleWagonAdjustmentLog[];
|
||||||
},
|
},
|
||||||
): string {
|
): string {
|
||||||
const esc = (value: unknown) =>
|
const esc = (value: unknown) =>
|
||||||
@@ -3844,6 +3859,24 @@ export class TrainSchedulingService {
|
|||||||
${opts?.positionLabel ? `<div class="tile"><span>Current position</span><strong>${esc(opts.positionLabel)}</strong></div>` : ''}
|
${opts?.positionLabel ? `<div class="tile"><span>Current position</span><strong>${esc(opts.positionLabel)}</strong></div>` : ''}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
${
|
||||||
|
opts?.consistChangesAtStop?.length
|
||||||
|
? `<div class="notice">
|
||||||
|
<b>Consist changed at this stop:</b>
|
||||||
|
${(() => {
|
||||||
|
const coupled = opts.consistChangesAtStop.filter((row) => row.action === 'ADD');
|
||||||
|
const switched = opts.consistChangesAtStop.filter((row) => row.action === 'SWITCH');
|
||||||
|
return [
|
||||||
|
coupled.length ? `Coupled: ${esc(coupled.map((row) => row.wagonNumber).join(', '))}` : '',
|
||||||
|
switched.length ? `Uncoupled — replaced: ${esc(switched.map((row) => row.wagonNumber).join(', '))}` : '',
|
||||||
|
]
|
||||||
|
.filter(Boolean)
|
||||||
|
.join(' | ');
|
||||||
|
})()}
|
||||||
|
</div>`
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
Reference in New Issue
Block a user