mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-28 00:50:56 +00:00
Boarding report added
This commit is contained in:
@@ -53,6 +53,12 @@ export class ReportsController {
|
||||
return this.service.getSeatStatusReport(scheduleId);
|
||||
}
|
||||
|
||||
@Get("boarding")
|
||||
@ApiOperation({ summary: "Boarding report for a schedule — boarded vs not-boarded passengers" })
|
||||
getBoardingReport(@Query('scheduleId') scheduleId: string) {
|
||||
return this.service.getBoardingReport(scheduleId);
|
||||
}
|
||||
|
||||
@Get("payments")
|
||||
@ApiOperation({ summary: "Payments collected for a schedule" })
|
||||
getPaymentsReport(@Query('scheduleId') scheduleId: string) {
|
||||
|
||||
@@ -1022,6 +1022,119 @@ export class ReportsService {
|
||||
return { total: rows.length, rows };
|
||||
}
|
||||
|
||||
async getBoardingReport(scheduleId: string) {
|
||||
const schedule = await this.prisma.trainSchedule.findUnique({
|
||||
where: { id: scheduleId },
|
||||
select: {
|
||||
id: true,
|
||||
departureAt: true,
|
||||
arrivalAt: true,
|
||||
train: { select: { number: true, name: true } },
|
||||
originStation: { select: { name: true } },
|
||||
destinationStation: { select: { name: true } },
|
||||
},
|
||||
});
|
||||
if (!schedule) return null;
|
||||
|
||||
const tickets = await this.prisma.ticket.findMany({
|
||||
where: {
|
||||
OR: [
|
||||
{ scheduleId, booking: { status: { in: ['CONFIRMED', 'BOARDED'] } } },
|
||||
{ leg: 2, booking: { returnScheduleId: scheduleId, status: { in: ['CONFIRMED', 'BOARDED'] } } },
|
||||
{ scheduleId: null, leg: 1, booking: { scheduleId, status: { in: ['CONFIRMED', 'BOARDED'] } } },
|
||||
],
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
bookingRef: true,
|
||||
passengerName: true,
|
||||
boardedAt: true,
|
||||
validatorId: true,
|
||||
status: true,
|
||||
booking: {
|
||||
select: {
|
||||
status: true,
|
||||
originStationId: true,
|
||||
destinationStationId: true,
|
||||
},
|
||||
},
|
||||
seat: {
|
||||
select: {
|
||||
seatNumber: true,
|
||||
bedPosition: true,
|
||||
coach: {
|
||||
select: {
|
||||
number: true,
|
||||
coachType: { select: { name: true, seatClasses: { select: { name: true, bedPosition: true } } } },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
orderBy: [{ seat: { coach: { number: 'asc' } } }, { seat: { seatNumber: 'asc' } }],
|
||||
});
|
||||
|
||||
const stationIds = [...new Set(
|
||||
tickets.flatMap(t => [t.booking.originStationId, t.booking.destinationStationId]).filter(Boolean) as string[],
|
||||
)];
|
||||
const stations = stationIds.length > 0
|
||||
? await this.prisma.station.findMany({ where: { id: { in: stationIds } }, select: { id: true, name: true } })
|
||||
: [];
|
||||
const stationName = new Map(stations.map(s => [s.id, s.name]));
|
||||
|
||||
const resolveSeatClass = (seat: any): string | null => {
|
||||
const classes = seat?.coach?.coachType?.seatClasses ?? [];
|
||||
const matched = seat?.bedPosition
|
||||
? classes.find((sc: any) => sc.bedPosition?.toLowerCase() === seat.bedPosition.toLowerCase())
|
||||
: null;
|
||||
return (matched ?? classes[0])?.name ?? seat?.coach?.coachType?.name ?? null;
|
||||
};
|
||||
|
||||
const rows = tickets.map(t => ({
|
||||
bookingRef: t.bookingRef,
|
||||
passengerName: t.passengerName,
|
||||
coachNumber: t.seat?.coach?.number ?? null,
|
||||
seatNumber: t.seat?.seatNumber ?? null,
|
||||
seatClassName: resolveSeatClass(t.seat),
|
||||
origin: t.booking.originStationId ? (stationName.get(t.booking.originStationId) ?? null) : null,
|
||||
destination: t.booking.destinationStationId ? (stationName.get(t.booking.destinationStationId) ?? null) : null,
|
||||
boarded: !!t.boardedAt,
|
||||
boardedAt: t.boardedAt ?? null,
|
||||
validatorId: t.validatorId ?? null,
|
||||
bookingStatus: t.booking.status,
|
||||
}));
|
||||
|
||||
const boardedCount = rows.filter(r => r.boarded).length;
|
||||
const notBoardedCount = rows.length - boardedCount;
|
||||
|
||||
const byCoach = new Map<string, { coachNumber: string; total: number; boarded: number }>();
|
||||
for (const r of rows) {
|
||||
const key = r.coachNumber ?? 'Unknown';
|
||||
if (!byCoach.has(key)) byCoach.set(key, { coachNumber: key, total: 0, boarded: 0 });
|
||||
byCoach.get(key)!.total++;
|
||||
if (r.boarded) byCoach.get(key)!.boarded++;
|
||||
}
|
||||
|
||||
return {
|
||||
schedule: {
|
||||
id: schedule.id,
|
||||
trainName: (schedule.train as any)?.name ?? (schedule.train as any)?.number,
|
||||
origin: (schedule.originStation as any)?.name,
|
||||
destination: (schedule.destinationStation as any)?.name,
|
||||
departureAt: schedule.departureAt,
|
||||
arrivalAt: schedule.arrivalAt,
|
||||
},
|
||||
summary: {
|
||||
total: rows.length,
|
||||
boardedCount,
|
||||
notBoardedCount,
|
||||
boardingRate: rows.length > 0 ? +((boardedCount / rows.length) * 100).toFixed(1) : 0,
|
||||
},
|
||||
byCoach: [...byCoach.values()].sort((a, b) => a.coachNumber.localeCompare(b.coachNumber)),
|
||||
rows,
|
||||
};
|
||||
}
|
||||
|
||||
async getReport(reportId: string) {
|
||||
return this.prisma.operationalReport.findUnique({
|
||||
where: { id: reportId },
|
||||
|
||||
Reference in New Issue
Block a user