Added stops departure and arrival datetime

This commit is contained in:
Roba Boru
2026-07-18 21:51:54 +03:00
parent d7a66cfac5
commit c1858e76d4
16 changed files with 1026 additions and 94 deletions

View File

@@ -128,4 +128,13 @@ export class BookPackageDto {
/** Number of child passengers (<5 years). Derived from passengers array if omitted. */
@ApiPropertyOptional({ example: 1 }) @IsOptional() @IsInt() @Min(0) childCount?: number;
/**
* SeatHold UUID returned by POST /seats/hold when the user selected seats on the
* seatmap before proceeding to book. When provided, the hold's expiry is extended
* to the payment deadline so the specific seat stays reserved on the seatmap for
* the full payment window, matching the behaviour of normal bookings.
*/
@ApiPropertyOptional({ description: 'SeatHold ID from seatmap selection' })
@IsOptional() @IsUUID() holdId?: string;
}

View File

@@ -6,6 +6,7 @@ import { Currency } from '@prisma/client';
import { BookingsService } from '../bookings/bookings.service';
import { GuestBookingService } from '../bookings/guest-booking.service';
import { AuditService } from '../../common/audit.service';
import { computePaymentDeadline, CUTOFF_MINUTES } from '../../common/utils/payment-deadline.utils';
/** Package-specific fare rules */
const PKG_MAX_ADULTS = 5;
@@ -382,7 +383,10 @@ export class PackagesService {
async book(dto: BookPackageDto, passengerId?: string) {
const pkg = await this.prisma.travelPackage.findUnique({
where: { id: dto.packageId },
include: { priceTiers: true },
include: {
priceTiers: true,
outboundSchedule: { select: { departureAt: true, route: { select: { checkinMinutesBefore: true } } } },
},
});
if (!pkg) throw new NotFoundException('Package not found');
if (pkg.status !== 'ACTIVE') throw new BadRequestException('Package is not available for booking');
@@ -477,6 +481,27 @@ export class PackagesService {
]);
});
// Extend the seatmap SeatHold (if one was passed) to the payment deadline so the
// specific seat remains visually reserved on the seatmap during the full payment
// window — matching the behaviour of normal bookings (which call confirmSeats).
if (dto.holdId) {
const dep = (pkg as any).outboundSchedule?.departureAt as Date | undefined;
if (dep) {
const checkinMinutes = (pkg as any).outboundSchedule?.route?.checkinMinutesBefore ?? CUTOFF_MINUTES;
const paymentDeadline = computePaymentDeadline(booking.createdAt as Date, dep, checkinMinutes);
const hold = await this.prisma.seatHold.findUnique({
where: { id: dto.holdId },
select: { expiresAt: true },
});
if (hold && paymentDeadline > hold.expiresAt) {
await this.prisma.seatHold.update({
where: { id: dto.holdId },
data: { expiresAt: paymentDeadline },
});
}
}
}
return {
...booking,
fareBreakdown: {