Enhance passenger API and web application functionality

This commit is contained in:
Stephanos A
2026-06-03 11:15:14 +03:00
parent 8d6d853305
commit 6f4ce7d49a
12 changed files with 161 additions and 98 deletions

View File

@@ -22,7 +22,7 @@ async function bootstrap() {
new ResponseTransformInterceptor(),
app.get(SessionActivityInterceptor),
);
app.useGlobalPipes(new ValidationPipe({ whitelist: true, transform: true }));
app.useGlobalPipes(new ValidationPipe({ whitelist: true, transform: true, forbidUnknownValues: false }));
const config = new DocumentBuilder()
.setTitle("EDR Passenger API")

View File

@@ -219,21 +219,41 @@ The API automatically detects:
@Post('save-details')
@ApiOperation({
summary: '[LEGACY] Save all passenger details before seat selection',
description: `**Note:** This endpoint is legacy. Consider using \`POST /passengers/register\` instead.
summary: 'Bulk save passenger details from booking flow',
description: `**Endpoint for saving multiple passengers in a single booking**
Saves all passenger details to database before proceeding to seat selection.
---
- Required step in booking flow
- Saves details for all passengers in booking
- Supports both logged-in users and guests
- Prevents data loss if user navigates away
### Purpose
Save all passenger details for a multi-passenger booking before proceeding to seat selection. Optimized for batch operations where all passengers are collected upfront.
**Migration:** Use \`POST /passengers/register\` for new implementations.`,
---
### Use Cases
1. **Multi-passenger bookings** - Save all passengers in a single request
2. **Batch registration** - Admin/Agent registering multiple passengers at once
3. **Data preservation** - Save passenger data before proceeding to seat selection
4. **Guest bookings** - Multiple guests booking together
---
### Differences from /register
| Feature | /register | /save-details |
|---------|-----------|---------------|
| Purpose | Single passenger registration with optional verification | Bulk save multiple passengers |
| Passengers | One at a time | Multiple in array |
| Verification | Auto-attempts for Ethiopian nationals (if enabled) | No automatic verification |
| Use case | Individual registration flow | Booking flow with all passengers |
| Authentication | Optional JWT | Optional JWT |
---
### Response
Returns saved passenger details with generated IDs and confirmation.`,
})
@ApiResponse({
status: 201,
description: 'Passenger details saved successfully',
description: 'All passenger details saved successfully',
schema: {
example: {
count: 2,
@@ -241,15 +261,17 @@ Saves all passenger details to database before proceeding to seat selection.
passengers: [
{
id: 'uuid-1',
passengerName: 'John Doe',
dateOfBirth: '1990-01-01T00:00:00.000Z',
nationality: 'Ethiopian'
passengerName: 'Abebe Kebede',
dateOfBirth: '1985-03-15T00:00:00.000Z',
nationality: 'Ethiopian',
nationalId: 'ET123456789'
},
{
id: 'uuid-2',
passengerName: 'Jane Doe',
dateOfBirth: '1992-05-15T00:00:00.000Z',
nationality: 'Ethiopian'
passengerName: 'Sara Ketsela',
dateOfBirth: '1990-08-22T00:00:00.000Z',
nationality: 'Ethiopian',
nationalId: 'ET987654321'
}
],
message: 'Passenger details saved successfully'
@@ -257,9 +279,8 @@ Saves all passenger details to database before proceeding to seat selection.
}
})
@ApiResponse({ status: 400, description: 'Validation error - passengers array required' })
savePassengers(@Body() body: any) {
const passengers = body.passengers || (Array.isArray(body) ? body : [body]);
return this.service.savePassengers(passengers, body.userId, body.deviceId);
savePassengers(@Body() dto: SavePassengersDto) {
return this.service.savePassengers(dto.passengers, dto.userId, dto.deviceId);
}
@Post('traveler-profiles')

View File

@@ -1,4 +1,5 @@
import { IsString, IsOptional, IsDateString, IsEnum, IsBoolean } from 'class-validator';
import { IsString, IsOptional, IsDateString, IsEnum, IsBoolean, IsArray, ValidateNested } from 'class-validator';
import { Type } from 'class-transformer';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
export class CreateTravelerProfileDto {
@@ -76,51 +77,60 @@ export class RegisterInternationalPassengerDto {
}
export class SavePassengerDetailsDto {
@ApiProperty({ example: 'Abebe Kebede' })
@ApiProperty({ example: 'Abebe Kebede', description: 'Full name of passenger' })
@IsString()
name: string;
@ApiProperty({ example: '1985-03-15' })
@ApiProperty({ example: '1985-03-15', description: 'Date of birth in ISO format YYYY-MM-DD' })
@IsDateString()
dateOfBirth: string;
@ApiProperty({ example: 'ETHIOPIAN' })
@IsString()
nationality: string;
@ApiPropertyOptional({ example: 'ET123456789' })
@ApiPropertyOptional({ example: 'ET123456789', description: 'Ethiopian national ID (for Ethiopian passengers)' })
@IsOptional()
@IsString()
nationalId?: string;
@ApiPropertyOptional({ example: 'P1234567' })
@ApiPropertyOptional({ example: 'P1234567', description: 'Passport number (for international passengers)' })
@IsOptional()
@IsString()
passportNumber?: string;
@ApiPropertyOptional({ example: 'Kenya' })
@ApiPropertyOptional({ example: 'Kenya', description: 'Passport issuing country' })
@IsOptional()
@IsString()
passportCountry?: string;
@ApiPropertyOptional({ example: '+251911234567' })
@ApiPropertyOptional({ example: 'Ethiopian', description: 'Nationality' })
@IsOptional()
@IsString()
nationality?: string;
@ApiPropertyOptional({ example: '+251911234567', description: 'Phone number' })
@IsOptional()
@IsString()
phone?: string;
@ApiPropertyOptional({ example: 'email@example.com' })
@ApiPropertyOptional({ example: 'abebe@example.com', description: 'Email address' })
@IsOptional()
@IsString()
email?: string;
@ApiPropertyOptional()
@ApiPropertyOptional({ example: 'Male', description: 'Gender' })
@IsOptional()
@IsString()
faydaSub?: string;
gender?: string;
@ApiPropertyOptional({ example: true, description: 'Whether this is the primary passenger' })
@IsOptional()
@IsBoolean()
isPrimaryPassenger?: boolean;
}
export class SavePassengersDto {
@ApiProperty({ type: [SavePassengerDetailsDto] })
@IsArray()
@ValidateNested({ each: true })
@Type(() => SavePassengerDetailsDto)
passengers: SavePassengerDetailsDto[];
@ApiPropertyOptional({ description: 'User ID if logged in' })

View File

@@ -145,7 +145,7 @@ export class PassengersService {
data: {
userId,
deviceId,
passengerName: p.name,
passengerName: p.name || p.passengerName,
dateOfBirth: new Date(p.dateOfBirth),
idDocumentType: p.nationalId ? 'NATIONAL_ID' : 'PASSPORT',
passportNumber: p.passportNumber,