Initial commit of edr-passenger-api alpha version

This commit is contained in:
Stephanos A
2026-05-13 16:58:49 +03:00
parent 199a3eba11
commit 39ba561d8f
113 changed files with 3602 additions and 1035 deletions

View File

@@ -0,0 +1,18 @@
import { Body, Controller, Get, Post, UseGuards } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { FleetService } from './fleet.service';
import { CreateTrainServiceDto, CreateCoachDto, CreateSeatBatchDto } 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) {}
@Get('services') @ApiOperation({ summary: 'List train services' }) getServices() { return this.service.getServices(); }
@Post('services') @ApiOperation({ summary: 'Create train service' }) createService(@Body() dto: CreateTrainServiceDto) { return this.service.createService(dto); }
@Post('coaches') @ApiOperation({ summary: 'Add coach to trip' }) createCoach(@Body() dto: CreateCoachDto) { return this.service.createCoach(dto); }
@Post('seats/batch')@ApiOperation({ summary: 'Batch-create seats for coach' }) createSeatBatch(@Body() dto: CreateSeatBatchDto) { return this.service.createSeatBatch(dto); }
@Get('analytics') @ApiOperation({ summary: 'Fleet analytics' }) getAnalytics() { return this.service.getAnalytics(); }
}

View File

@@ -0,0 +1,20 @@
import { IsString, IsEnum, IsInt } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
import { ServiceClass } from '@prisma/client';
export class CreateTrainServiceDto {
@ApiProperty({ example: '301' }) @IsString() number: string;
@ApiProperty({ example: 'Express 301' }) @IsString() name: string;
}
export class CreateCoachDto {
@ApiProperty() @IsString() tripId: string;
@ApiProperty({ example: 'A' }) @IsString() label: string;
@ApiProperty({ enum: ServiceClass }) @IsEnum(ServiceClass) serviceClass: ServiceClass;
}
export class CreateSeatBatchDto {
@ApiProperty() @IsString() coachId: string;
@ApiProperty({ example: 10 }) @IsInt() rows: number;
@ApiProperty({ example: ['A', 'B', 'C', 'D'] }) cols: string[];
}

View File

@@ -0,0 +1,6 @@
import { Module } from '@nestjs/common';
import { FleetController } from './fleet.controller';
import { FleetService } from './fleet.service';
@Module({ controllers: [FleetController], providers: [FleetService], exports: [FleetService] })
export class FleetModule {}

View File

@@ -0,0 +1,26 @@
import { Injectable, NotFoundException } from '@nestjs/common';
import { PrismaService } from '../../common/prisma.service';
import { CreateTrainServiceDto, CreateCoachDto, CreateSeatBatchDto } from './fleet.dto';
@Injectable()
export class FleetService {
constructor(private prisma: PrismaService) {}
getServices() { return this.prisma.trainService.findMany({ include: { trips: { take: 5, orderBy: { departureAt: 'desc' } } } }); }
createService(dto: CreateTrainServiceDto) { return this.prisma.trainService.create({ data: dto }); }
createCoach(dto: CreateCoachDto) { return this.prisma.coach.create({ data: dto }); }
async createSeatBatch(dto: CreateSeatBatchDto) {
const coach = await this.prisma.coach.findUnique({ where: { id: dto.coachId } });
if (!coach) throw new NotFoundException('Coach not found');
const seats = [];
for (let row = 1; row <= dto.rows; row++) for (const col of dto.cols) seats.push({ coachId: dto.coachId, row, col, label: `${row}${col}` });
await this.prisma.seat.createMany({ data: seats, skipDuplicates: true });
return { created: seats.length };
}
async getAnalytics() {
const [totalServices, totalTrips, totalSeats, bookedSeats] = await Promise.all([
this.prisma.trainService.count(), this.prisma.trip.count(),
this.prisma.seat.count(), this.prisma.seat.count({ where: { status: 'BOOKED' } }),
]);
return { totalServices, totalTrips, totalSeats, bookedSeats, occupancyRate: totalSeats > 0 ? +((bookedSeats / totalSeats) * 100).toFixed(2) : 0 };
}
}