init
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { prisma } from '@/lib/db';
|
||||
import { getSessionUser } from '@/lib/auth';
|
||||
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const body = await request.json();
|
||||
const {
|
||||
scheduleId,
|
||||
passengerName,
|
||||
passengerEmail,
|
||||
passengerPhone,
|
||||
seats, // Array of strings, e.g. ["1", "2"] or ["1A", "1B"]
|
||||
} = body;
|
||||
|
||||
if (!scheduleId || !passengerName || !passengerEmail || !passengerPhone || !seats || !Array.isArray(seats) || seats.length === 0) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Missing required booking details or seat selections' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
// Fetch schedule to get the price
|
||||
const schedule = await prisma.schedule.findUnique({
|
||||
where: { id: Number(scheduleId) },
|
||||
});
|
||||
|
||||
if (!schedule) {
|
||||
return NextResponse.json({ error: 'Schedule not found' }, { status: 404 });
|
||||
}
|
||||
|
||||
// Check optional user session link
|
||||
const userSession = await getSessionUser();
|
||||
const userId = userSession ? userSession.userId : null;
|
||||
|
||||
// Calculate total price
|
||||
const unitPrice = Number(schedule.price);
|
||||
const totalPrice = unitPrice * seats.length;
|
||||
|
||||
// Generate unique booking code
|
||||
const bookingCode = 'TRV-' + Math.random().toString(36).substring(2, 8).toUpperCase();
|
||||
|
||||
// Perform database transaction to ensure atomic operations (no double seat bookings)
|
||||
const booking = await prisma.$transaction(async (tx) => {
|
||||
// 1. Check if any selected seat is already occupied for this schedule
|
||||
const occupied = await tx.bookingSeat.findMany({
|
||||
where: {
|
||||
scheduleId: Number(scheduleId),
|
||||
seatNumber: { in: seats },
|
||||
booking: {
|
||||
status: { in: ['PENDING', 'PAID'] },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (occupied.length > 0) {
|
||||
throw new Error('One or more selected seats have already been booked. Please choose other seats.');
|
||||
}
|
||||
|
||||
// 2. Create the booking record
|
||||
const newBooking = await tx.booking.create({
|
||||
data: {
|
||||
bookingCode,
|
||||
scheduleId: Number(scheduleId),
|
||||
userId,
|
||||
passengerName,
|
||||
passengerEmail,
|
||||
passengerPhone,
|
||||
totalPrice,
|
||||
status: 'PENDING',
|
||||
},
|
||||
});
|
||||
|
||||
// 3. Create the booking seat records
|
||||
const seatRecords = seats.map((seat: string) => ({
|
||||
bookingId: newBooking.id,
|
||||
scheduleId: Number(scheduleId),
|
||||
seatNumber: seat,
|
||||
}));
|
||||
|
||||
await tx.bookingSeat.createMany({
|
||||
data: seatRecords,
|
||||
});
|
||||
|
||||
return newBooking;
|
||||
});
|
||||
|
||||
return NextResponse.json({ success: true, bookingCode: booking.bookingCode, bookingId: booking.id });
|
||||
} catch (error: any) {
|
||||
console.error('Create booking transaction error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: error.message || 'Failed to process booking. Please try again.' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user