Report figures correction updates

This commit is contained in:
Stephanos A
2026-07-18 20:16:24 +03:00
parent 554baf2595
commit 4805a54bf7
7 changed files with 77 additions and 20 deletions

View File

@@ -13,8 +13,8 @@ export class DashboardService {
async getBackofficeStats() {
const [totalBookings, totalPackageBookings, totalTickets, totalPassengers, revenueRows, packageRevenueRows] =
await Promise.all([
this.prisma.booking.count(),
this.prisma.booking.count({ where: { packageId: { not: null } } }),
this.prisma.booking.count({ where: { status: { in: ['CONFIRMED', 'BOARDED'] } } }),
this.prisma.booking.count({ where: { status: { in: ['CONFIRMED', 'BOARDED'] }, packageId: { not: null } } }),
this.prisma.ticket.count(),
this.prisma.passenger.count(),
this.prisma.$queryRaw<{ currency: string; total: bigint }[]>`

View File

@@ -95,13 +95,18 @@ export class ReportsService {
where: { departureAt: { gte: dateFrom, lte: dateTo } },
include: {
coachAssignments: { include: { coach: { include: { seats: true } } } },
bookings: { include: { seats: { where: { scheduleId: schedule.id } } } },
bookings: {
where: { status: { in: ['CONFIRMED', 'BOARDED'] } },
include: { seats: true },
},
},
});
const tripData = schedules.map(schedule => {
const totalSeats = schedule.coachAssignments.reduce((sum, a) => sum + a.coach.seats.length, 0);
const bookedSeats = schedule.bookings.reduce((sum, b) => sum + b.seats.length, 0);
const bookedSeats = schedule.bookings.reduce(
(sum, b) => sum + b.seats.filter((s: any) => s.scheduleId === schedule.id).length, 0,
);
const occupancyRate = totalSeats > 0 ? (bookedSeats / totalSeats) * 100 : 0;
return { scheduleId: schedule.id, departureAt: schedule.departureAt, totalSeats, bookedSeats, occupancyRate: +occupancyRate.toFixed(2) };
});

View File

@@ -29,6 +29,16 @@ import { PASSENGER_PERMS } from "../../seed/passenger-permissions.registry";
export class SeatsController {
constructor(private service: SeatsService) {}
// ── Blocked Seats ─────────────────────────────────────────────────────────
@Get('blocks')
@PassengerStaff([PASSENGER_PERMS.seats.manage, PASSENGER_PERMS.admin])
@ApiBearerAuth('IAM-auth')
@ApiOperation({ summary: 'List all blocked seats with reason and coach info' })
@ApiResponse({ status: 200, description: 'Blocked seat records' })
getBlockedSeats() {
return this.service.getBlockedSeats();
}
// ── Coach Availability ────────────────────────────────────────────────────
@Get('coaches/:scheduleId')
@SetMetadata('isPublic', true)

View File

@@ -598,6 +598,26 @@ export class SeatsService {
await this.prisma.journey.deleteMany({ where: { bookingId } as any });
}
async getBlockedSeats() {
const blocks = await this.prisma.seatBlock.findMany({
include: {
seat: { include: { coach: { select: { number: true } } } },
},
orderBy: { blockedAt: 'desc' },
});
return blocks.map(b => ({
id: b.id,
seatId: b.seatId,
seatNumber: b.seat.seatNumber,
coachNumber: b.seat.coach.number,
scheduleId: b.scheduleId,
reason: b.reason,
blockedBy: b.blockedBy,
blockedAt: b.blockedAt,
unblockAt: b.unblockAt,
}));
}
async getCoachesWithAvailability(scheduleId: string, originStationId?: string, destinationStationId?: string) {
const schedule = await this.prisma.trainSchedule.findUnique({
where: { id: scheduleId },