import { NextRequest, NextResponse } from "next/server"; import { getStripe, getStripeAccountId } from "@/src/lib/stripe"; import { prisma } from "@/src/lib/prisma"; import { getApartmentBySlug, bookingConfig } from "@/src/config/apartments"; import { getAvailability, getEffectiveMinStay } from "@/src/lib/beds24"; import { calculatePrice } from "@/src/lib/pricing"; import { nightsBetween } from "@/src/lib/date"; export const dynamic = "force-dynamic"; export async function POST(request: NextRequest) { try { const body = await request.json(); const { apartmentSlug, start, end, guestEmail, guestName, successUrl, cancelUrl, } = body; if (!apartmentSlug || !start || !end || !guestEmail || !guestName) { return NextResponse.json( { error: "Missing required booking parameters" }, { status: 400 } ); } const apartment = getApartmentBySlug(apartmentSlug); if (!apartment) { return NextResponse.json( { error: "Apartment not found" }, { status: 404 } ); } const startDate = new Date(start); const endDate = new Date(end); const nights = nightsBetween(start, end); const minStayNights = await getEffectiveMinStay( apartment.houseId, apartment.beds24PropertyId, apartment.beds24RoomId, start, bookingConfig.minStayNights ); if (nights < minStayNights) { return NextResponse.json( { error: `Minimum stay is ${minStayNights} nights` }, { status: 400 } ); } const availability = await getAvailability({ houseId: apartment.houseId, propertyId: apartment.beds24PropertyId, roomId: apartment.beds24RoomId, start, end, }); if (!availability.available) { return NextResponse.json( { error: "Apartment not available for selected dates" }, { status: 409 } ); } const price = calculatePrice(availability.price, nights, availability.currency); const depositAmount = Math.round(price.depositAmount * 100); // cents const stripe = getStripe(apartment.houseId); const accountId = getStripeAccountId(apartment.houseId); // Create or update Stripe customer let customer; const existingCustomers = await stripe.customers.list({ email: guestEmail, limit: 1, }); if (existingCustomers.data.length > 0) { customer = existingCustomers.data[0]; } else { customer = await stripe.customers.create({ email: guestEmail, name: guestName, }); } const bookingReference = `BB-${Date.now()}-${Math.random().toString(36).substring(2, 7).toUpperCase()}`; // Create pending booking in database await prisma.booking.create({ data: { bookingReference, apartmentSlug, houseId: apartment.houseId, beds24PropertyId: apartment.beds24PropertyId, beds24RoomId: apartment.beds24RoomId, guestEmail, guestName, checkIn: startDate, checkOut: endDate, nights, totalAmount: price.totalAfterDiscount, depositAmount: price.depositAmount, currency: price.currency, status: "pending", stripeAccountId: accountId, stripeCustomerId: customer.id, }, }); const session = await stripe.checkout.sessions.create({ customer: customer.id, payment_method_types: ["card"], line_items: [ { price_data: { currency: price.currency.toLowerCase(), product_data: { name: `Anzahlung Apartment ${apartment.name}`, description: `Aufenthalt: ${start} bis ${end} (${nights} Nächte)`, }, unit_amount: depositAmount, }, quantity: 1, }, ], mode: "payment", success_url: successUrl || `${process.env.NEXT_PUBLIC_BASE_URL}/de/booking-success?reference=${bookingReference}`, cancel_url: cancelUrl || `${process.env.NEXT_PUBLIC_BASE_URL}/de/apartments/${apartmentSlug}`, metadata: { bookingReference, apartmentSlug, houseId: apartment.houseId, }, }); await prisma.booking.update({ where: { bookingReference }, data: { stripeCheckoutSessionId: session.id }, }); return NextResponse.json({ sessionId: session.id, bookingReference, url: session.url, }); } catch (error) { console.error("Checkout session error:", error); return NextResponse.json( { error: "Failed to create checkout session" }, { status: 500 } ); } }