Refactor business logic for train,schedule,coach,seat and search modules

This commit is contained in:
Roba Boru
2026-05-22 14:47:38 +03:00
parent 9151110fd8
commit 096c717bfa
48 changed files with 2254 additions and 2865 deletions

View File

@@ -1,21 +1,100 @@
import { Body, Controller, Get, Param, Patch, Post, Query, UseGuards } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { Body, Controller, Get, Param, Patch, Post, Query, ParseIntPipe, UseGuards } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth, ApiParam, ApiQuery, ApiResponse } from '@nestjs/swagger';
import { SchedulesService } from './schedules.service';
import { CreateTripDto, CreateFareRuleDto, UpdateTripStatusDto } from './schedules.dto';
import { CreateScheduleDto, CreateFareRuleDto, UpdateScheduleStatusDto, UpdateStopTimeDto, ListSchedulesDto } from './schedules.dto';
import { JwtGuard } from '../../common/jwt.guard';
import { TripStatus } from '@prisma/client';
@ApiTags('Schedule')
@Controller('schedule')
@Controller('schedules')
export class SchedulesController {
constructor(private service: SchedulesService) {}
@Post('trips') @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth') @ApiOperation({ summary: 'Create trip' })
createTrip(@Body() dto: CreateTripDto) { return this.service.createTrip(dto); }
@Get('trips/:id') @ApiOperation({ summary: 'Get trip details' })
getTrip(@Param('id') id: string) { return this.service.getTrip(id); }
@Patch('trips/:id/status') @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth') @ApiOperation({ summary: 'Update trip status' })
updateStatus(@Param('id') id: string, @Body() dto: UpdateTripStatusDto) { return this.service.updateTripStatus(id, dto); }
@Post('fares') @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth') @ApiOperation({ summary: 'Create fare rule' })
@Post()
@UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth')
@ApiOperation({
summary: 'Create a train schedule from a route template',
description: `Creates a schedule by referencing a Route (routeId).
Stops are automatically copied from the route's RouteStop definitions.
You supply the actual planned arrival/departure times per stop sequence.
Origin and destination are derived from the first and last route stop — no need to specify them manually.`,
})
@ApiResponse({ status: 201, description: 'Schedule created with stops copied from route template' })
@ApiResponse({ status: 400, description: 'Invalid times, inactive route, or missing planned times for some stops' })
@ApiResponse({ status: 404, description: 'Train or route not found' })
createSchedule(@Body() dto: CreateScheduleDto) { return this.service.createSchedule(dto); }
@Get()
@ApiOperation({ summary: 'List schedules with optional filters' })
@ApiQuery({ name: 'date', required: false, example: '2026-06-15', description: 'Departure date (YYYY-MM-DD). Returns all schedules departing on this calendar day.' })
@ApiQuery({ name: 'routeId', required: false, description: 'Filter by route UUID' })
@ApiQuery({ name: 'trainId', required: false, description: 'Filter by train UUID' })
@ApiQuery({ name: 'status', required: false, enum: TripStatus, description: 'Filter by schedule status' })
@ApiResponse({ status: 200, description: 'Array of schedules ordered by departureAt, each with train, origin/destination, stops, and booking/assignment counts' })
listSchedules(
@Query('date') date?: string,
@Query('routeId') routeId?: string,
@Query('trainId') trainId?: string,
@Query('status') status?: TripStatus,
) {
return this.service.listSchedules({ date, routeId, trainId, status });
}
// Static routes before parameterised ones
@Post('fares')
@UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth')
@ApiOperation({ summary: 'Create a fare rule scoped to a schedule or route code' })
@ApiResponse({ status: 201, description: 'Fare rule created' })
createFareRule(@Body() dto: CreateFareRuleDto) { return this.service.createFareRule(dto); }
@Get('fares/:tripId') @ApiOperation({ summary: 'Get fare for trip and class' })
getFare(@Param('tripId') tripId: string, @Query('class') cls: string) { return this.service.getFare(tripId, cls ?? 'ECONOMY'); }
@Get(':id')
@ApiOperation({ summary: 'Get schedule with train, coaches, seats, and stop timeline' })
@ApiParam({ name: 'id', description: 'TrainSchedule UUID' })
@ApiResponse({ status: 200, description: 'Full schedule detail including route stops with station info' })
@ApiResponse({ status: 404, description: 'Schedule not found' })
getSchedule(@Param('id') id: string) { return this.service.getSchedule(id); }
@Patch(':id/status')
@UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth')
@ApiOperation({ summary: 'Update schedule status (SCHEDULED → BOARDING → EN_ROUTE → ARRIVED)' })
@ApiParam({ name: 'id', description: 'TrainSchedule UUID' })
@ApiResponse({ status: 200, description: 'Status updated' })
@ApiResponse({ status: 404, description: 'Schedule not found' })
updateStatus(@Param('id') id: string, @Body() dto: UpdateScheduleStatusDto) {
return this.service.updateScheduleStatus(id, dto);
}
// ── Stop Times ─────────────────────────────────────────────────────────────
@Get(':id/stops')
@ApiOperation({ summary: 'List all stops for a schedule ordered by sequence' })
@ApiParam({ name: 'id', description: 'TrainSchedule UUID' })
@ApiResponse({ status: 200, description: 'Ordered stop list with station details and planned/actual times' })
@ApiResponse({ status: 404, description: 'Schedule not found' })
getStops(@Param('id') id: string) { return this.service.getStops(id); }
@Patch(':id/stops/:sequence')
@UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth')
@ApiOperation({ summary: 'Update planned times or live status of a specific stop' })
@ApiParam({ name: 'id', description: 'TrainSchedule UUID' })
@ApiParam({ name: 'sequence', description: 'Stop sequence number' })
@ApiResponse({ status: 200, description: 'Stop updated' })
@ApiResponse({ status: 404, description: 'Stop not found on schedule' })
updateStop(
@Param('id') id: string,
@Param('sequence', ParseIntPipe) sequence: number,
@Body() dto: UpdateStopTimeDto,
) { return this.service.updateStop(id, sequence, dto); }
// ── Fares ──────────────────────────────────────────────────────────────────
@Get(':scheduleId/fares')
@ApiOperation({ summary: 'Get applicable fare for a schedule and seat class' })
@ApiParam({ name: 'scheduleId', description: 'TrainSchedule UUID' })
@ApiQuery({ name: 'class', required: false, description: 'Seat class name: "Economy Regular" | "Economy Bed" | "VIP Bed". Defaults to Economy Regular.' })
@ApiResponse({ status: 200, description: 'Fare rule or default fare' })
@ApiResponse({ status: 404, description: 'Schedule not found' })
getFare(@Param('scheduleId') scheduleId: string, @Query('class') cls: string) {
return this.service.getFare(scheduleId, cls ?? 'Economy Regular');
}
}