mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 07:38:10 +00:00
Extend seat hold time if booking created
This commit is contained in:
@@ -5,6 +5,7 @@ import { Cron, CronExpression } from '@nestjs/schedule';
|
||||
import { SegmentsService } from '../segments/segments.service';
|
||||
import { SystemConfigService, CONFIG_KEYS } from '../system-config/system-config.service';
|
||||
import { AuditService } from '../../common/audit.service';
|
||||
import { computePaymentDeadline } from '../../common/utils/payment-deadline.utils';
|
||||
|
||||
@Injectable()
|
||||
export class SeatsService {
|
||||
@@ -625,7 +626,50 @@ export class SeatsService {
|
||||
return { released: true, holdId };
|
||||
}
|
||||
|
||||
async confirmSeats(_seatIds: string[]) {}
|
||||
// Called right after a booking (PNR) is created, and again on successful payment.
|
||||
// Extends the SeatHold(s) covering these seats to the booking's actual payment
|
||||
// deadline — the same MIN(createdAt + 2h, departureAt - 30min) window TasksService
|
||||
// uses to auto-cancel unpaid bookings — instead of leaving them on the original
|
||||
// short seat-selection hold (5 min by default). Without this, the hold could expire
|
||||
// while the customer was still on the payment page, and a second customer could
|
||||
// hold/book the exact same seat out from under them.
|
||||
async confirmSeats(seatIds: string[], now: Date = new Date()): Promise<void> {
|
||||
if (seatIds.length === 0) return;
|
||||
|
||||
const holds = await this.prisma.seatHold.findMany({
|
||||
where: { seatIds: { hasSome: seatIds } },
|
||||
select: { id: true, scheduleId: true, expiresAt: true },
|
||||
});
|
||||
if (holds.length === 0) return;
|
||||
|
||||
const scheduleIds = Array.from(new Set(holds.map(h => h.scheduleId)));
|
||||
const schedules = await this.prisma.trainSchedule.findMany({
|
||||
where: { id: { in: scheduleIds } },
|
||||
select: { id: true, departureAt: true },
|
||||
});
|
||||
const departureById = new Map(schedules.map(s => [s.id, s.departureAt]));
|
||||
|
||||
let extended = 0;
|
||||
await Promise.all(
|
||||
holds.map(async (hold) => {
|
||||
const departureAt = departureById.get(hold.scheduleId);
|
||||
if (!departureAt) return;
|
||||
const deadline = computePaymentDeadline(now, departureAt);
|
||||
// Only ever extend forward — never shorten a hold that's already valid longer
|
||||
// than the payment deadline would give it (e.g. a second confirmSeats call on
|
||||
// the same booking, or a hold that was already extended).
|
||||
if (deadline <= hold.expiresAt) return;
|
||||
await this.prisma.seatHold.update({ where: { id: hold.id }, data: { expiresAt: deadline } });
|
||||
extended++;
|
||||
}),
|
||||
);
|
||||
|
||||
if (extended > 0) {
|
||||
this.logger.log(
|
||||
`Extended ${extended} seat hold(s) covering ${seatIds.length} seat(s) to their booking's payment deadline`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the Journey (and its JourneySegments) scoped to this booking.
|
||||
async releaseSeats(bookingId: string) {
|
||||
|
||||
Reference in New Issue
Block a user