mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 18:48:11 +00:00
add goverment booking
This commit is contained in:
@@ -1475,7 +1475,9 @@ export class BookingBatchService implements OnModuleInit {
|
||||
const [schedules, total] = await this.trainSchedulesRepository.findAndCount({
|
||||
where,
|
||||
relations: {
|
||||
trainSet: { locomotive: true, train: true },
|
||||
// locomotives (plural) too — the caps SUM the whole set's pull; the
|
||||
// single legacy column alone under-reports a two-loco train by half.
|
||||
trainSet: { locomotive: true, locomotives: { locomotive: true }, train: true },
|
||||
originStation: true,
|
||||
destinationStation: true,
|
||||
// Yards supply the route's display name for `routeName` below;
|
||||
@@ -1538,7 +1540,21 @@ export class BookingBatchService implements OnModuleInit {
|
||||
};
|
||||
});
|
||||
|
||||
board.push(this.buildScheduleSummary(s, items));
|
||||
board.push(
|
||||
this.buildScheduleSummary(
|
||||
s,
|
||||
items,
|
||||
new Map(
|
||||
bookings.map((b) => [
|
||||
b.id,
|
||||
{
|
||||
originYardId: b.originYardId ?? null,
|
||||
destinationYardId: b.destinationYardId ?? null,
|
||||
},
|
||||
]),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return { items: board, meta: buildPaginationMeta(total, page, pageSize) };
|
||||
@@ -1853,47 +1869,63 @@ export class BookingBatchService implements OnModuleInit {
|
||||
: null;
|
||||
const round2 = (value: number) => Math.round(value * 100) / 100;
|
||||
|
||||
// Per-leg committed weight: a booking holds weight only on the edges it
|
||||
// rides, so the meter compares the HEAVIEST single edge against the pull
|
||||
// limit. Whole-route bookings (or yards missing from the stop list) load
|
||||
// every edge — never under-reported.
|
||||
// Per-leg committed usage: a booking holds capacity only on the edges it
|
||||
// rides, so every meter compares the HEAVIEST single edge against its cap
|
||||
// — weight, wagons and length alike. Whole-route bookings (or yards
|
||||
// missing from the stop list) load every edge — never under-reported.
|
||||
const stops = legCtx?.stops ?? [];
|
||||
let usedWeightTons = round2(
|
||||
committed.reduce((sum, i) => sum + i.weightTons, 0),
|
||||
);
|
||||
let allocatedWagons = allocated.reduce((sum, i) => sum + i.wagons, 0);
|
||||
let allocatedLengthMeters = round2(
|
||||
allocated.reduce((sum, i) => sum + i.lengthMeters, 0),
|
||||
);
|
||||
let legUsage: BatchBoardSchedule["capacity"]["legUsage"] = null;
|
||||
if (legCtx && stops.length > 2) {
|
||||
const stopIndex = new Map(stops.map((yardId, i) => [yardId, i]));
|
||||
const edges = new Array<number>(stops.length - 1).fill(0);
|
||||
for (const item of committed) {
|
||||
const yards = legCtx.yardsByBookingId.get(item.id);
|
||||
const edgeCount = stops.length - 1;
|
||||
const legOf = (bookingId: string): { from: number; to: number } => {
|
||||
const yards = legCtx.yardsByBookingId.get(bookingId);
|
||||
const from = yards?.originYardId
|
||||
? stopIndex.get(yards.originYardId)
|
||||
: undefined;
|
||||
const to = yards?.destinationYardId
|
||||
? stopIndex.get(yards.destinationYardId)
|
||||
: undefined;
|
||||
const leg =
|
||||
from != null && to != null && from < to
|
||||
? { from, to }
|
||||
: { from: 0, to: edges.length };
|
||||
for (let e = leg.from; e < leg.to; e += 1) edges[e] += item.weightTons;
|
||||
return from != null && to != null && from < to
|
||||
? { from, to }
|
||||
: { from: 0, to: edgeCount };
|
||||
};
|
||||
const weightEdges = new Array<number>(edgeCount).fill(0);
|
||||
for (const item of committed) {
|
||||
const leg = legOf(item.id);
|
||||
for (let e = leg.from; e < leg.to; e += 1) weightEdges[e] += item.weightTons;
|
||||
}
|
||||
const wagonEdges = new Array<number>(edgeCount).fill(0);
|
||||
const lengthEdges = new Array<number>(edgeCount).fill(0);
|
||||
for (const item of allocated) {
|
||||
const leg = legOf(item.id);
|
||||
for (let e = leg.from; e < leg.to; e += 1) {
|
||||
wagonEdges[e] += item.wagons;
|
||||
lengthEdges[e] += item.lengthMeters;
|
||||
}
|
||||
}
|
||||
const label = (yardId: string) =>
|
||||
legCtx.labelByYardId.get(yardId) ?? yardId;
|
||||
legUsage = edges.map((weight, i) => ({
|
||||
legUsage = weightEdges.map((weight, i) => ({
|
||||
from: label(stops[i]),
|
||||
to: label(stops[i + 1]),
|
||||
usedWeightTons: round2(weight),
|
||||
}));
|
||||
usedWeightTons = round2(Math.max(0, ...edges));
|
||||
usedWeightTons = round2(Math.max(0, ...weightEdges));
|
||||
allocatedWagons = Math.max(0, ...wagonEdges);
|
||||
allocatedLengthMeters = round2(Math.max(0, ...lengthEdges));
|
||||
}
|
||||
|
||||
return {
|
||||
allocatedWagons: allocated.reduce((sum, i) => sum + i.wagons, 0),
|
||||
allocatedLengthMeters: round2(
|
||||
allocated.reduce((sum, i) => sum + i.lengthMeters, 0),
|
||||
),
|
||||
allocatedWagons,
|
||||
allocatedLengthMeters,
|
||||
maxLengthMeters: caps ? caps.maxLengthMeters : null,
|
||||
usedWeightTons,
|
||||
maxWeightTons: caps ? caps.maxWeightTons : null,
|
||||
@@ -1919,11 +1951,46 @@ export class BookingBatchService implements OnModuleInit {
|
||||
return new Map(yards.map((y) => [y.id, y.label ?? y.code]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Corridor stops + labels from the already-loaded route graph (milestones
|
||||
* with yards) — the list flow must not fire a query per schedule row.
|
||||
*/
|
||||
private stopsFromGraph(s: TrainSchedule): {
|
||||
stops: string[];
|
||||
labelByYardId: Map<string, string>;
|
||||
} {
|
||||
const milestones = [...(s.route?.milestones ?? [])].sort(
|
||||
(a, b) => a.sequenceNo - b.sequenceNo,
|
||||
);
|
||||
const stops: string[] = [];
|
||||
const labelByYardId = new Map<string, string>();
|
||||
const push = (yardId?: string | null, label?: string | null) => {
|
||||
if (!yardId || labelByYardId.has(yardId)) return;
|
||||
stops.push(yardId);
|
||||
labelByYardId.set(yardId, label ?? yardId);
|
||||
};
|
||||
if (milestones.length >= 2) {
|
||||
for (const m of milestones) push(m.yardId, m.yard?.label ?? m.yard?.code);
|
||||
} else {
|
||||
push(s.originStationId, s.originStation?.label ?? s.originStation?.code);
|
||||
push(
|
||||
s.destinationStationId,
|
||||
s.destinationStation?.label ?? s.destinationStation?.code,
|
||||
);
|
||||
}
|
||||
return { stops, labelByYardId };
|
||||
}
|
||||
|
||||
private buildScheduleSummary(
|
||||
s: TrainSchedule,
|
||||
items: BatchBoardBooking[],
|
||||
yardsByBookingId: Map<
|
||||
string,
|
||||
{ originYardId: string | null; destinationYardId: string | null }
|
||||
>,
|
||||
): BatchBoardSchedule {
|
||||
const loco = trainSetLocomotiveLimits(s.trainSet);
|
||||
const { stops, labelByYardId } = this.stopsFromGraph(s);
|
||||
|
||||
return {
|
||||
scheduleId: s.id,
|
||||
@@ -1966,9 +2033,9 @@ export class BookingBatchService implements OnModuleInit {
|
||||
}
|
||||
: null,
|
||||
capacity: this.computeBoardCapacity(items, loco, s.maxWagons ?? null, {
|
||||
stops: [],
|
||||
labelByYardId: new Map(),
|
||||
yardsByBookingId: new Map(),
|
||||
stops,
|
||||
labelByYardId,
|
||||
yardsByBookingId,
|
||||
trainLengthMeters: this.builtTrainLengthOf(s),
|
||||
}),
|
||||
counts: {
|
||||
|
||||
Reference in New Issue
Block a user