mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-27 07:22:53 +00:00
369 lines
13 KiB
TypeScript
369 lines
13 KiB
TypeScript
import { Body, Controller, Delete, Get, Param, Patch, Post, Query, UseGuards } from '@nestjs/common';
|
|
import { ApiTags, ApiOperation, ApiBearerAuth, ApiParam, ApiQuery, ApiBody, ApiResponse } from '@nestjs/swagger';
|
|
import { FleetService } from './fleet.service';
|
|
import { CreateTrainDto, CreateCoachDto, UpdateCoachDto, AssignCoachDto, ListCoachesDto, CreateCoachTypeDto, UpdateCoachTypeDto, CreateClassDto, UpdateClassDto, GenerateSeatMapDto } from './fleet.dto';
|
|
import { JwtGuard } from '../../common/jwt.guard';
|
|
|
|
@ApiTags('Fleet')
|
|
@Controller('fleet')
|
|
@UseGuards(JwtGuard)
|
|
@ApiBearerAuth('JWT-auth')
|
|
export class FleetController {
|
|
constructor(private service: FleetService) {}
|
|
|
|
// Coach Type Endpoints
|
|
@Get('coach-types')
|
|
@ApiOperation({ summary: 'List all coach types' })
|
|
@ApiResponse({ status: 200, description: 'Array of coach types' })
|
|
getCoachTypes() {
|
|
return this.service.getCoachTypes();
|
|
}
|
|
|
|
@Post('coach-types')
|
|
@ApiOperation({ summary: 'Create a coach type' })
|
|
@ApiBody({ type: CreateCoachTypeDto })
|
|
@ApiResponse({ status: 201, description: 'Coach type created' })
|
|
createCoachType(@Body() dto: CreateCoachTypeDto) {
|
|
return this.service.createCoachType(dto);
|
|
}
|
|
|
|
@Patch('coach-types/:id')
|
|
@ApiOperation({ summary: 'Update a coach type' })
|
|
@ApiParam({ name: 'id', description: 'Coach Type UUID' })
|
|
@ApiBody({ type: UpdateCoachTypeDto })
|
|
@ApiResponse({ status: 200, description: 'Coach type updated' })
|
|
@ApiResponse({ status: 404, description: 'Coach type not found' })
|
|
updateCoachType(@Param('id') id: string, @Body() dto: UpdateCoachTypeDto) {
|
|
return this.service.updateCoachType(id, dto);
|
|
}
|
|
|
|
@Delete('coach-types/:id')
|
|
@ApiOperation({ summary: 'Delete a coach type' })
|
|
@ApiParam({ name: 'id', description: 'Coach Type UUID' })
|
|
@ApiResponse({ status: 200, description: 'Coach type deleted' })
|
|
@ApiResponse({ status: 404, description: 'Coach type not found' })
|
|
deleteCoachType(@Param('id') id: string) {
|
|
return this.service.deleteCoachType(id);
|
|
}
|
|
|
|
// Class Endpoints
|
|
@Get('classes')
|
|
@ApiOperation({ summary: 'List all classes' })
|
|
@ApiQuery({ name: 'coachTypeId', required: false, description: 'Filter by coach type' })
|
|
@ApiResponse({ status: 200, description: 'Array of classes' })
|
|
getClasses(@Query('coachTypeId') coachTypeId?: string) {
|
|
return this.service.getClasses(coachTypeId);
|
|
}
|
|
|
|
@Post('classes')
|
|
@ApiOperation({ summary: 'Create a class' })
|
|
@ApiBody({ type: CreateClassDto })
|
|
@ApiResponse({ status: 201, description: 'Class created' })
|
|
createClass(@Body() dto: CreateClassDto) {
|
|
return this.service.createClass(dto);
|
|
}
|
|
|
|
@Patch('classes/:id')
|
|
@ApiOperation({ summary: 'Update a class' })
|
|
@ApiParam({ name: 'id', description: 'Class UUID' })
|
|
@ApiBody({ type: UpdateClassDto })
|
|
@ApiResponse({ status: 200, description: 'Class updated' })
|
|
@ApiResponse({ status: 404, description: 'Class not found' })
|
|
updateClass(@Param('id') id: string, @Body() dto: UpdateClassDto) {
|
|
return this.service.updateClass(id, dto);
|
|
}
|
|
|
|
@Delete('classes/:id')
|
|
@ApiOperation({ summary: 'Delete a class' })
|
|
@ApiParam({ name: 'id', description: 'Class UUID' })
|
|
@ApiResponse({ status: 200, description: 'Class deleted' })
|
|
@ApiResponse({ status: 404, description: 'Class not found' })
|
|
deleteClass(@Param('id') id: string) {
|
|
return this.service.deleteClass(id);
|
|
}
|
|
|
|
// Seat Class Endpoints (DEPRECATED - use Classes endpoints instead)
|
|
@Get('seat-classes')
|
|
@ApiOperation({ summary: 'List all classes (DEPRECATED - use /fleet/classes)' })
|
|
@ApiQuery({ name: 'coachTypeId', required: false, description: 'Filter by coach type' })
|
|
@ApiResponse({ status: 200, description: 'Array of classes' })
|
|
getSeatClasses(@Query('coachTypeId') coachTypeId?: string) {
|
|
return this.service.getClasses(coachTypeId);
|
|
}
|
|
|
|
@Post('seat-classes')
|
|
@ApiOperation({ summary: 'Create a class (DEPRECATED - use /fleet/classes)' })
|
|
@ApiBody({ type: CreateClassDto })
|
|
@ApiResponse({ status: 201, description: 'Class created' })
|
|
createSeatClass(@Body() dto: CreateClassDto) {
|
|
return this.service.createClass(dto);
|
|
}
|
|
|
|
@Patch('seat-classes/:id')
|
|
@ApiOperation({ summary: 'Update a class (DEPRECATED - use /fleet/classes)' })
|
|
@ApiParam({ name: 'id', description: 'Class UUID' })
|
|
@ApiBody({ type: UpdateClassDto })
|
|
@ApiResponse({ status: 200, description: 'Class updated' })
|
|
@ApiResponse({ status: 404, description: 'Class not found' })
|
|
updateSeatClass(@Param('id') id: string, @Body() dto: UpdateClassDto) {
|
|
return this.service.updateClass(id, dto);
|
|
}
|
|
|
|
@Delete('seat-classes/:id')
|
|
@ApiOperation({ summary: 'Delete a class (DEPRECATED - use /fleet/classes)' })
|
|
@ApiParam({ name: 'id', description: 'Class UUID' })
|
|
@ApiResponse({ status: 200, description: 'Class deleted' })
|
|
@ApiResponse({ status: 404, description: 'Class not found' })
|
|
deleteSeatClass(@Param('id') id: string) {
|
|
return this.service.deleteClass(id);
|
|
}
|
|
|
|
// Train Endpoints
|
|
@Get('trains')
|
|
@ApiOperation({ summary: 'List all trains with their recent schedules' })
|
|
@ApiResponse({ status: 200, description: 'Array of trains' })
|
|
getTrains() {
|
|
return this.service.getTrains();
|
|
}
|
|
|
|
@Post('trains')
|
|
@ApiOperation({ summary: 'Create a train service' })
|
|
@ApiBody({ type: CreateTrainDto })
|
|
@ApiResponse({ status: 201, description: 'Train created' })
|
|
createTrain(@Body() dto: CreateTrainDto) {
|
|
return this.service.createTrain(dto);
|
|
}
|
|
|
|
@Patch('trains/:id')
|
|
@ApiOperation({ summary: 'Update a train service' })
|
|
@ApiParam({ name: 'id', description: 'Train UUID' })
|
|
@ApiBody({ type: CreateTrainDto })
|
|
@ApiResponse({ status: 200, description: 'Train updated' })
|
|
@ApiResponse({ status: 404, description: 'Train not found' })
|
|
updateTrain(@Param('id') id: string, @Body() dto: CreateTrainDto) {
|
|
return this.service.updateTrain(id, dto);
|
|
}
|
|
|
|
@Delete('trains/:id')
|
|
@ApiOperation({ summary: 'Delete a train service' })
|
|
@ApiParam({ name: 'id', description: 'Train UUID' })
|
|
@ApiResponse({ status: 200, description: 'Train deleted' })
|
|
@ApiResponse({ status: 404, description: 'Train not found' })
|
|
deleteTrain(@Param('id') id: string) {
|
|
return this.service.deleteTrain(id);
|
|
}
|
|
|
|
@Patch('trains/:id/restore')
|
|
@ApiOperation({ summary: 'Restore (reactivate) a deactivated train' })
|
|
@ApiParam({ name: 'id', description: 'Train UUID' })
|
|
@ApiResponse({ status: 200, description: 'Train restored' })
|
|
@ApiResponse({ status: 404, description: 'Train not found' })
|
|
restoreTrain(@Param('id') id: string) {
|
|
return this.service.restoreTrain(id);
|
|
}
|
|
|
|
// Coach Endpoints
|
|
@Get('coaches')
|
|
@ApiOperation({ summary: 'List coaches with seat status summary' })
|
|
@ApiQuery({ name: 'status', required: false, description: 'Filter by status: ACTIVE, INACTIVE' })
|
|
@ApiQuery({ name: 'scheduleId', required: false, description: 'Filter coaches assigned to schedule' })
|
|
@ApiResponse({
|
|
status: 200,
|
|
description: 'Array of coaches',
|
|
schema: {
|
|
example: [
|
|
{
|
|
id: '550e8400-e29b-41d4-a716-446655440000',
|
|
number: 'A-001',
|
|
sequence: 1,
|
|
coachTypeId: 'coach-type-uuid',
|
|
coachType: {
|
|
id: 'coach-type-uuid',
|
|
code: 'sleeper',
|
|
name: 'Sleeper Coach'
|
|
},
|
|
arrangement: '2+2',
|
|
capacity: 60,
|
|
status: 'ACTIVE',
|
|
totalSeats: 60,
|
|
availableSeats: 45,
|
|
occupiedSeats: 15,
|
|
blockedSeats: 0,
|
|
createdAt: '2024-01-15T10:30:00.000Z',
|
|
updatedAt: '2024-01-15T10:30:00.000Z'
|
|
}
|
|
]
|
|
}
|
|
})
|
|
listCoaches(
|
|
@Query('status') status?: string,
|
|
@Query('scheduleId') scheduleId?: string,
|
|
) {
|
|
const dto: ListCoachesDto = {
|
|
status,
|
|
scheduleId,
|
|
};
|
|
return this.service.listCoaches(dto);
|
|
}
|
|
|
|
@Get('coaches/:id')
|
|
@ApiOperation({ summary: 'Get single coach with seat layout' })
|
|
@ApiParam({ name: 'id', description: 'Coach UUID' })
|
|
@ApiResponse({
|
|
status: 200,
|
|
description: 'Coach detail with seats by row',
|
|
schema: {
|
|
example: {
|
|
id: '550e8400-e29b-41d4-a716-446655440000',
|
|
number: 'A-001',
|
|
sequence: 1,
|
|
coachTypeId: 'coach-type-uuid',
|
|
coachType: {
|
|
id: 'coach-type-uuid',
|
|
code: 'sleeper',
|
|
name: 'Sleeper Coach'
|
|
},
|
|
arrangement: '2+2',
|
|
capacity: 60,
|
|
status: 'ACTIVE',
|
|
seats: [
|
|
{
|
|
id: 'seat-uuid-1',
|
|
seatNumber: '1A',
|
|
status: 'AVAILABLE',
|
|
class: {
|
|
id: 'class-uuid',
|
|
name: 'Economy',
|
|
baseFareMinor: 5000
|
|
}
|
|
}
|
|
],
|
|
createdAt: '2024-01-15T10:30:00.000Z',
|
|
updatedAt: '2024-01-15T10:30:00.000Z'
|
|
}
|
|
}
|
|
})
|
|
@ApiResponse({ status: 404, description: 'Coach not found' })
|
|
getCoach(@Param('id') id: string) {
|
|
return this.service.getCoach(id);
|
|
}
|
|
|
|
@Post('coaches')
|
|
@ApiOperation({ summary: 'Create a coach with auto-generated seat numbers' })
|
|
@ApiBody({ type: CreateCoachDto })
|
|
@ApiResponse({
|
|
status: 201,
|
|
description: 'Coach created',
|
|
schema: {
|
|
example: {
|
|
id: '550e8400-e29b-41d4-a716-446655440000',
|
|
number: 'A-001',
|
|
sequence: 1,
|
|
coachTypeId: 'coach-type-uuid',
|
|
arrangement: '2+2',
|
|
capacity: 60,
|
|
status: 'ACTIVE',
|
|
createdAt: '2024-01-15T10:30:00.000Z',
|
|
updatedAt: '2024-01-15T10:30:00.000Z'
|
|
}
|
|
}
|
|
})
|
|
@ApiResponse({ status: 400, description: 'Invalid arrangement format' })
|
|
createCoach(@Body() dto: CreateCoachDto) {
|
|
return this.service.createCoach(dto);
|
|
}
|
|
|
|
@Patch('coaches/:id')
|
|
@ApiOperation({ summary: 'Update coach properties' })
|
|
@ApiParam({ name: 'id', description: 'Coach UUID' })
|
|
@ApiBody({ type: UpdateCoachDto })
|
|
@ApiResponse({
|
|
status: 200,
|
|
description: 'Coach updated',
|
|
schema: {
|
|
example: {
|
|
id: '550e8400-e29b-41d4-a716-446655440000',
|
|
number: 'A-001',
|
|
sequence: 1,
|
|
coachTypeId: 'coach-type-uuid',
|
|
arrangement: '2+2',
|
|
capacity: 60,
|
|
status: 'ACTIVE',
|
|
createdAt: '2024-01-15T10:30:00.000Z',
|
|
updatedAt: '2024-01-15T10:30:00.000Z'
|
|
}
|
|
}
|
|
})
|
|
@ApiResponse({ status: 404, description: 'Coach not found' })
|
|
updateCoach(@Param('id') id: string, @Body() dto: UpdateCoachDto) {
|
|
return this.service.updateCoach(id, dto);
|
|
}
|
|
|
|
@Delete('coaches/:id')
|
|
@ApiOperation({ summary: 'Delete a coach' })
|
|
@ApiParam({ name: 'id', description: 'Coach UUID' })
|
|
@ApiResponse({ status: 200, description: 'Coach deleted successfully' })
|
|
@ApiResponse({ status: 404, description: 'Coach not found' })
|
|
deleteCoach(@Param('id') id: string) {
|
|
return this.service.deleteCoach(id);
|
|
}
|
|
|
|
@Post('assignments')
|
|
@ApiOperation({ summary: 'Assign a coach to a schedule' })
|
|
@ApiBody({ type: AssignCoachDto })
|
|
@ApiResponse({ status: 201, description: 'Coach assigned' })
|
|
@ApiResponse({ status: 404, description: 'Schedule or coach not found' })
|
|
assignCoach(@Body() dto: AssignCoachDto) {
|
|
return this.service.assignCoach(dto);
|
|
}
|
|
|
|
@Delete('assignments/:id')
|
|
@ApiOperation({ summary: 'Remove a coach assignment' })
|
|
@ApiParam({ name: 'id', description: 'Assignment UUID' })
|
|
@ApiResponse({ status: 200, description: 'Assignment removed' })
|
|
@ApiResponse({ status: 404, description: 'Assignment not found' })
|
|
removeAssignment(@Param('id') id: string) {
|
|
return this.service.removeAssignment(id);
|
|
}
|
|
|
|
@Post('seatmap/generate')
|
|
@ApiOperation({
|
|
summary: 'Preview bed seat map — ECONOMY_BED or VIP_BED',
|
|
description: `Generates a structured seat map for bed coaches without persisting anything.
|
|
|
|
**ECONOMY_BED**: 6 beds per room — Left(Lower/Middle/Upper) + Right(Lower/Middle/Upper)
|
|
|
|
**VIP_BED**: 4 beds per room — Left(Lower/Upper) + Right(Lower/Upper)
|
|
|
|
Use this to preview the full flat seat list before creating coaches.`,
|
|
})
|
|
@ApiBody({ type: GenerateSeatMapDto })
|
|
@ApiResponse({
|
|
status: 201,
|
|
description: 'Generated seat map preview',
|
|
schema: {
|
|
example: {
|
|
coachCount: 1, roomsPerCoach: 2, roomType: 'ECONOMY_BED', bedsPerRoom: 6, totalBeds: 12,
|
|
seats: [
|
|
{ seat_id: 'C1-C1-R1-S1', coach_id: 'C1', room_id: 'C1-R1', category: 'ECONOMY_BED', position: 'LEFT', bed_type: 'LOWER', sequence_number: 1, status: 'AVAILABLE' },
|
|
{ seat_id: 'C1-C1-R1-S2', coach_id: 'C1', room_id: 'C1-R1', category: 'ECONOMY_BED', position: 'LEFT', bed_type: 'MIDDLE', sequence_number: 2, status: 'AVAILABLE' },
|
|
{ seat_id: 'C1-C1-R1-S3', coach_id: 'C1', room_id: 'C1-R1', category: 'ECONOMY_BED', position: 'LEFT', bed_type: 'UPPER', sequence_number: 3, status: 'AVAILABLE' },
|
|
{ seat_id: 'C1-C1-R1-S4', coach_id: 'C1', room_id: 'C1-R1', category: 'ECONOMY_BED', position: 'RIGHT', bed_type: 'LOWER', sequence_number: 4, status: 'AVAILABLE' },
|
|
{ seat_id: 'C1-C1-R1-S5', coach_id: 'C1', room_id: 'C1-R1', category: 'ECONOMY_BED', position: 'RIGHT', bed_type: 'MIDDLE', sequence_number: 5, status: 'AVAILABLE' },
|
|
{ seat_id: 'C1-C1-R1-S6', coach_id: 'C1', room_id: 'C1-R1', category: 'ECONOMY_BED', position: 'RIGHT', bed_type: 'UPPER', sequence_number: 6, status: 'AVAILABLE' },
|
|
],
|
|
},
|
|
},
|
|
})
|
|
generateSeatMap(@Body() dto: GenerateSeatMapDto) {
|
|
return this.service.generateSeatMapPreview(dto);
|
|
}
|
|
|
|
@Get('analytics')
|
|
@ApiOperation({ summary: 'Fleet analytics and occupancy metrics' })
|
|
@ApiResponse({ status: 200, description: 'Occupancy statistics' })
|
|
getAnalytics() {
|
|
return this.service.getAnalytics();
|
|
}
|
|
}
|