mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-28 16:00:56 +00:00
feat: coach utilization report with schedule filtering and export functionality
This commit is contained in:
@@ -229,10 +229,11 @@ export class FleetController {
|
||||
}
|
||||
|
||||
@Get('coaches/utilization')
|
||||
@ApiOperation({ summary: 'Coach utilization report — seats, bookings, and assignment history per coach' })
|
||||
@ApiOperation({ summary: 'Coach utilization report — seats, bookings, and assignment history per coach for a selected schedule' })
|
||||
@ApiQuery({ name: 'scheduleId', required: false, description: 'Optional schedule UUID to scope the utilization report to that schedule.' })
|
||||
@ApiResponse({ status: 200, description: 'Coach utilization data' })
|
||||
getCoachUtilization() {
|
||||
return this.service.getCoachUtilization();
|
||||
getCoachUtilization(@Query('scheduleId') scheduleId?: string) {
|
||||
return this.service.getCoachUtilization(scheduleId);
|
||||
}
|
||||
|
||||
@Get('coaches/:id')
|
||||
|
||||
@@ -822,12 +822,35 @@ export class FleetService {
|
||||
};
|
||||
}
|
||||
|
||||
async getCoachUtilization() {
|
||||
async getCoachUtilization(scheduleId?: string) {
|
||||
const where = scheduleId ? { scheduleId } : {};
|
||||
|
||||
const coaches = await this.prisma.coach.findMany({
|
||||
where: scheduleId
|
||||
? {
|
||||
assignments: {
|
||||
some: { scheduleId },
|
||||
},
|
||||
}
|
||||
: {},
|
||||
include: {
|
||||
coachType: true,
|
||||
seats: { select: { id: true, status: true } },
|
||||
seats: {
|
||||
select: {
|
||||
id: true,
|
||||
status: true,
|
||||
bookingSeats: {
|
||||
where,
|
||||
select: { id: true },
|
||||
},
|
||||
blocks: {
|
||||
where,
|
||||
select: { id: true, reasonCategory: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
assignments: {
|
||||
where,
|
||||
include: {
|
||||
schedule: {
|
||||
select: { id: true, departureAt: true, status: true, _count: { select: { bookings: true } } },
|
||||
@@ -842,10 +865,12 @@ export class FleetService {
|
||||
|
||||
return coaches.map((coach) => {
|
||||
const totalSeats = coach.seats.length;
|
||||
const bookedSeats = coach.seats.filter((s) => s.status === 'BOOKED').length;
|
||||
const blockedSeats = coach.seats.filter((s) => s.status === 'BLOCKED').length;
|
||||
const maintenanceSeats = coach.seats.filter((s) => (s.status as string) === 'UNDER_MAINTENANCE').length;
|
||||
const availableSeats = coach.seats.filter((s) => s.status === 'AVAILABLE').length;
|
||||
const bookedSeats = coach.seats.filter((s) => (s.bookingSeats?.length ?? 0) > 0).length;
|
||||
const blockedSeats = coach.seats.filter((s) => (s.blocks?.length ?? 0) > 0).length;
|
||||
const maintenanceSeats = coach.seats.filter((s) => (s.blocks ?? []).some((b) => b.reasonCategory === 'MAINTENANCE')).length;
|
||||
const availableSeats = scheduleId
|
||||
? Math.max(totalSeats - bookedSeats - blockedSeats - maintenanceSeats, 0)
|
||||
: coach.seats.filter((s) => s.status === 'AVAILABLE').length;
|
||||
const totalAssignments = coach.assignments.length;
|
||||
const totalBookings = coach.assignments.reduce((sum, a) => sum + ((a.schedule as any)._count?.bookings ?? 0), 0);
|
||||
const utilizationRate = totalSeats > 0 ? +((bookedSeats / totalSeats) * 100).toFixed(2) : 0;
|
||||
|
||||
Reference in New Issue
Block a user