Merge pull request #1439 from Tria-plc/credit-invoice

feat(train-scheduling): log leg-slot board/alight events at checkpoints
This commit is contained in:
Hagernesh Tadesse
2026-08-28 14:18:10 +03:00
committed by GitHub

View File

@@ -5007,6 +5007,76 @@ export class TrainSchedulingService {
await manager.getRepository(ScheduleWagonAdjustmentLog).save(coupleLogRows);
}
}
// Leg slots (booking legs boarding/alighting mid-corridor — see
// stampSlotLegs) reaching their board/alight yard here: logged same as
// planned couples/cuts above, so the marshalling document can show
// what coupled ALREADY LOADED / uncoupled WITH cargo at this stop.
// Purely observational — their physical wagon was already pinned to
// the slot at schedule-build time (assignPhysicalWagonsToSlots), so
// nothing here changes wagon state, only the log. Dedupe against
// existing rows (not a wagon-state flag, unlike the couple/cut blocks
// above) since passedYardIds re-includes earlier stops on every call.
const legSlotsHere = (schedule.trainSet?.wagons ?? []).filter(
(slot) =>
slot.physicalWagonId &&
((slot.boardYardId && passedYardIds.includes(slot.boardYardId)) ||
(slot.alightYardId && passedYardIds.includes(slot.alightYardId))),
);
if (legSlotsHere.length && builtTrainId) {
const legWagonIds = [
...new Set(legSlotsHere.map((slot) => slot.physicalWagonId!)),
];
const legWagonById = new Map(
(
await manager.getRepository(Wagon).find({ where: { id: In(legWagonIds) } })
).map((w) => [w.id, w]),
);
const alreadyLogged = new Set(
(
await manager.getRepository(ScheduleWagonAdjustmentLog).find({
where: {
trainScheduleId: scheduleId,
wagonId: In(legWagonIds),
action: In(['ADD', 'REMOVE']),
},
})
).map((row) => `${row.wagonId}:${row.action}:${row.yardId}`),
);
const legLogRows: ScheduleWagonAdjustmentLog[] = [];
for (const slot of legSlotsHere) {
const wagon = legWagonById.get(slot.physicalWagonId!);
if (!wagon) continue;
const events: Array<{ action: 'ADD' | 'REMOVE'; yardId: string }> = [];
if (slot.boardYardId && passedYardIds.includes(slot.boardYardId)) {
events.push({ action: 'ADD', yardId: slot.boardYardId });
}
if (slot.alightYardId && passedYardIds.includes(slot.alightYardId)) {
events.push({ action: 'REMOVE', yardId: slot.alightYardId });
}
for (const { action, yardId } of events) {
const key = `${wagon.id}:${action}:${yardId}`;
if (alreadyLogged.has(key)) continue;
alreadyLogged.add(key);
legLogRows.push(
manager.getRepository(ScheduleWagonAdjustmentLog).create({
trainScheduleId: scheduleId,
trainId: builtTrainId,
action,
wagonId: wagon.id,
wagonNumber: wagon.wagonNumber,
adjustedByUserId: null,
yardId,
occurredAt,
}),
);
}
}
if (legLogRows.length) {
await manager.getRepository(ScheduleWagonAdjustmentLog).save(legLogRows);
}
}
await manager
.getRepository(Wagon)
.createQueryBuilder()