import { NextResponse } from 'next/server'; import { createClient } from '@/lib/supabase/server'; import { getProducts, getCategories } from '@/lib/actions/products'; import { buildCustomerSnapshot, buildOrderSnapshot } from '@/lib/license-transform'; import { sendMail } from '@/utils/mail'; import { createHash } from 'crypto'; import { renderToBuffer } from '@react-pdf/renderer'; import React from 'react'; import { InvoicePDF } from '@/components/invoice-pdf'; function generateOrderNumber(prefix: 'BE' | 'AE' = 'AE'): string { const year = new Date().getFullYear(); const rand = Math.floor(10000 + Math.random() * 90000); return `${prefix}-${year}-${rand}`; } function hashOrderSnapshot(snapshot: object): string { return createHash('sha256').update(JSON.stringify(snapshot)).digest('hex'); } export async function POST(request: Request) { try { const supabase = await createClient(); const { data: { user } } = await supabase.auth.getUser(); if (!user) { return NextResponse.json({ error: 'Not authenticated' }, { status: 401 }); } const { data: dbUser } = await supabase .from('users') .select('role, company_id') .eq('id', user.id) .single(); const isAdminUser = dbUser?.role === 'admin'; if (!isAdminUser && !dbUser?.company_id) { return NextResponse.json({ error: 'Firma erforderlich' }, { status: 403 }); } const body = await request.json(); const { items, customerProfile, endCustomerId, endCustomer } = body; if (!items || !Array.isArray(items) || items.length === 0) { return NextResponse.json({ error: 'Warenkorb leer' }, { status: 400 }); } const products = await getProducts(); const categories = await getCategories(); // Split items into purchase and subscription const purchaseItems = items.filter( (item: any) => item.billingInterval === 'one_time' || item.billingType === 'purchase' ); const subscriptionItems = items.filter( (item: any) => item.billingInterval === 'monthly' || item.billingType === 'subscription' ); const createdOrders: any[] = []; const processOrderGroup = async (groupItems: any[], type: 'purchase' | 'subscription', paymentMethod: string) => { if (groupItems.length === 0) return; // Build consolidated snapshots // For the multi-item support, we combine the order snapshots of each item in the group const customerSnapshot = buildCustomerSnapshot(customerProfile, endCustomer); const orderItemsList: any[] = []; let total = 0; for (const item of groupItems) { const itemSnapshot = buildOrderSnapshot( item.selections, products, categories, type === 'purchase' ? 'one_time' : 'monthly', item.moduleQuantities ); orderItemsList.push(...itemSnapshot.items); total += itemSnapshot.total; } const orderSnapshot = { schema_version: 1, billing_cycle: type === 'purchase' ? 'one_time' : 'monthly', items: orderItemsList, total: total, tax_rate: 19, // default tax_amount: Math.round(total * 0.19 * 100) / 100, subtotal: Math.round((total / 1.19) * 100) / 100 }; const orderHash = hashOrderSnapshot(orderSnapshot); const orderNumber = generateOrderNumber(type === 'purchase' ? 'AE' : 'BE'); const { data: order, error: orderError } = await supabase .from('orders') .insert([{ user_id: user.id, company_id: dbUser?.company_id || null, order_number: orderNumber, order_hash: orderHash, end_customer_id: endCustomerId || null, total_price: total, customer_data: customerSnapshot, order_data: orderSnapshot, type: type, payment_method: paymentMethod, status: 'pending' }]) .select() .single(); if (orderError) throw orderError; // Trigger PDF generation & storage upload try { const buffer = await renderToBuffer( React.createElement(InvoicePDF, { order, customer: customerSnapshot, orderSnapshot, }) ); const fileName = `ab_${order.id}.pdf`; const { error: uploadError } = await supabase .storage .from('invoices') .upload(fileName, buffer, { contentType: 'application/pdf', upsert: true }); if (!uploadError) { await supabase.from('orders').update({ pdf_url: fileName }).eq('id', order.id); order.pdf_url = fileName; } } catch (pdfErr) { console.error('PDF error for order ' + order.id, pdfErr); } // Trigger E-Mail notifications if (user.email) { try { await sendMail({ to: user.email, subject: `Bestellbestätigung ${order.order_number}`, text: `Vielen Dank für Ihre Bestellung ${order.order_number}. Typ: ${type}.`, html: `
Vielen Dank für Ihre Bestellung ${order.order_number}.
Typ: ${type}
` }); } catch (mailErr) { console.error('Mail error for order ' + order.id, mailErr); } } createdOrders.push(order); }; await processOrderGroup(purchaseItems, 'purchase', 'invoice'); await processOrderGroup(subscriptionItems, 'subscription', 'sepa'); return NextResponse.json({ success: true, orders: createdOrders }); } catch (error: any) { console.error('Checkout error:', error); return NextResponse.json({ error: error.message || 'Internal server error' }, { status: 500 }); } }