feat: ( reschedule ) implement booking reschedule

This commit is contained in:
Abubeker
2026-08-21 08:18:03 +00:00
parent e174efb8e0
commit 80a7a2f702
27 changed files with 1450 additions and 51 deletions

View File

@@ -26,7 +26,6 @@ import { BookingsService } from "./bookings.service";
import { GuestBookingService } from "./guest-booking.service";
import {
CreateBookingDto,
ModifyBookingDto,
CancelBookingDto,
} from "./bookings.dto";
import {
@@ -663,22 +662,6 @@ Results are ordered most-recent first. Use the returned \`bookingRef\` to open b
return this.service.getByRef(ref);
}
@Patch(":bookingRef/modify")
@UseGuards(JwtGuard)
@ApiBearerAuth("JWT-auth")
@ApiOperation({
summary: "Modify booking seats or trip",
description: "Allows modification of confirmed bookings before departure",
})
@ApiResponse({ status: 200, description: "Booking modified successfully" })
@ApiResponse({
status: 400,
description: "Cannot modify cancelled or past bookings",
})
modify(@Req() req: any, @Body() dto: ModifyBookingDto) {
return this.service.modify(dto, req.user?.id);
}
@Delete(":id")
@PassengerAdmin()
@ApiBearerAuth("IAM-auth")

View File

@@ -214,13 +214,6 @@ export class CreateBookingDto {
@IsOptional() @IsString() returnLeg2SeatClassId?: string;
}
export class ModifyBookingDto {
@ApiProperty() @IsString() bookingRef: string;
@ApiProperty({ example: 'schedule-uuid' }) @IsString() newScheduleId: string;
@ApiProperty({ type: [String] }) @IsArray() newSeatIds: string[];
@ApiPropertyOptional() @IsOptional() @IsString() reason?: string;
}
export class CancelBookingDto {
@ApiProperty() @IsString() bookingRef: string;
@ApiPropertyOptional() @IsOptional() @IsString() reason?: string;

View File

@@ -5,7 +5,7 @@ import { PrismaService } from '../../common/prisma.service';
import { SeatsService } from '../seats/seats.service';
import { TicketsService } from '../tickets/tickets.service';
import { EventEmitter2 } from '@nestjs/event-emitter';
import { CreateBookingDto, ModifyBookingDto } from './bookings.dto';
import { CreateBookingDto } from './bookings.dto';
import { assertIdentitiesNotAlreadyBooked, resolveIdentityRef } from './booking-identity.util';
import { Cron, CronExpression } from '@nestjs/schedule';
import { VerifaydaService } from '../verifayda/verifayda.service';
@@ -1905,7 +1905,7 @@ export class BookingsService {
};
}
private async getBaseFare(
async getBaseFare(
scheduleId: string,
seatClassId: string,
segmentRoute?: string,
@@ -2231,22 +2231,6 @@ export class BookingsService {
};
}
async modify(dto: ModifyBookingDto, iamUserId?: string) {
const booking = await this.prisma.booking.findUnique({ where: { bookingRef: dto.bookingRef }, include: { seats: true, schedule: true } });
if (!booking) throw new NotFoundException('Booking not found');
if (booking.status !== 'CONFIRMED') throw new BadRequestException('Only confirmed bookings can be modified');
if (booking.schedule.departureAt < new Date()) throw new BadRequestException('Cannot modify past bookings');
const oldSeats = booking.seats.map(s => s.seatId);
await this.prisma.bookingModification.create({
data: { bookingId: booking.id, modifiedBy: booking.passengerId, modificationType: 'SEAT_CHANGE', oldData: { scheduleId: booking.scheduleId, seatIds: oldSeats }, newData: { scheduleId: dto.newScheduleId, seatIds: dto.newSeatIds }, fareAdjustment: 0, reason: dto.reason },
});
await this.seatsService.releaseSeats(booking.id);
await this.seatsService.confirmSeats(dto.newSeatIds);
await this.auditService.log({ userId: iamUserId ?? booking.passengerId, action: 'UPDATE', entityType: 'Booking', entityId: booking.id, oldData: { seatIds: oldSeats }, newData: { seatIds: dto.newSeatIds, reason: dto.reason } });
return { modified: true, bookingRef: dto.bookingRef };
}
async cancel(bookingRef: string, reason?: string, iamUserId?: string) {
const booking = await this.prisma.booking.findUnique({ where: { bookingRef }, include: { seats: true, paymentIntent: true } });
if (!booking) throw new NotFoundException('Booking not found');