mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 22:18:12 +00:00
Merge remote-tracking branch 'origin/dev' into tests
This commit is contained in:
@@ -3,6 +3,7 @@ import {
|
||||
Logger,
|
||||
NotFoundException,
|
||||
BadRequestException,
|
||||
ConflictException,
|
||||
} from "@nestjs/common";
|
||||
import { PrismaService } from "../../common/prisma.service";
|
||||
import { SeatsService } from "../seats/seats.service";
|
||||
@@ -826,6 +827,27 @@ export class PaymentsService {
|
||||
});
|
||||
if (!intent) throw new NotFoundException("PaymentIntent not found");
|
||||
if (intent.status === PaymentIntentStatus.SUCCEEDED) {
|
||||
// Idempotency guard — but still repair missing tickets. They can be absent
|
||||
// when the first finalization threw from generate() after the transaction
|
||||
// committed: the caller got a 500, retried, and now hits this early-return.
|
||||
const ticketCount = await this.prisma.ticket.count({ where: { bookingId: intent.bookingId } });
|
||||
if (ticketCount === 0) {
|
||||
try {
|
||||
await this.ticketsService.generate(intent.bookingId);
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
this.logger.warn(
|
||||
`Ticket generation failed on idempotency retry for booking ${intent.bookingId}: ${msg}. Attempting smart seat reassignment.`,
|
||||
);
|
||||
try {
|
||||
await this.ticketsService.smartAssignAndGenerate(intent.bookingId);
|
||||
} catch (retryErr) {
|
||||
this.logger.error(
|
||||
`Error generating ticket on idempotency retry for booking ${intent.bookingId}: ${retryErr instanceof Error ? retryErr.message : String(retryErr)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return { alreadyFinalized: true };
|
||||
}
|
||||
if (intent.status === PaymentIntentStatus.CANCELLED) {
|
||||
@@ -876,10 +898,25 @@ export class PaymentsService {
|
||||
try {
|
||||
await this.ticketsService.generate(booking.id);
|
||||
} catch (err) {
|
||||
this.logger.error(
|
||||
`Error generating ticket: ${err instanceof Error ? err.message : String(err)}`,
|
||||
);
|
||||
throw err;
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
// Only reassign seats when a *different* booking genuinely holds the seat
|
||||
// (ConflictException). Any other error (transient DB issue, etc.) is logged
|
||||
// and swallowed — the passenger keeps their original seat and the ticket can
|
||||
// be retried via "Generate Missing" in the backoffice.
|
||||
if (err instanceof ConflictException) {
|
||||
this.logger.warn(
|
||||
`Seat conflict for booking ${booking.id}: ${msg}. Attempting smart seat reassignment.`,
|
||||
);
|
||||
try {
|
||||
await this.ticketsService.smartAssignAndGenerate(booking.id);
|
||||
} catch (retryErr) {
|
||||
this.logger.error(
|
||||
`Smart assign also failed for booking ${booking.id}: ${retryErr instanceof Error ? retryErr.message : String(retryErr)}`,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
this.logger.error(`Error generating ticket for booking ${booking.id}: ${msg}`);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -1005,6 +1042,11 @@ export class PaymentsService {
|
||||
intentId: intent.id,
|
||||
providerTxnId: event.providerTxnId,
|
||||
paidAt: event.paidAt ? new Date(event.paidAt) : undefined,
|
||||
}).catch((err) => {
|
||||
this.logger.error(
|
||||
`finalizePaymentSuccess failed for booking ${event.referenceId}: ${err instanceof Error ? err.message : String(err)}`,
|
||||
);
|
||||
return { alreadyFinalized: false };
|
||||
});
|
||||
return { processed: true, alreadyFinalized };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user