import { createClient } from '@/lib/supabase/server' import { NextResponse } from 'next/server' import { eventBus } from '@/lib/events' import { createSupplierInvoiceRegistrationEntry } from '@/lib/bookkeeping/supplier-invoice-entries' import { ensureInitialized } from '@/lib/init' import { validateBody } from '@/lib/api/validate' import { CreateSupplierInvoiceSchema } from '@/lib/api/schemas' import type { SupplierInvoice, SupplierInvoiceItem } from '@/types' ensureInitialized() export async function GET(request: Request) { const supabase = await createClient() const { data: { user } } = await supabase.auth.getUser() if (!user) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) } const { searchParams } = new URL(request.url) const status = searchParams.get('status') let query = supabase .from('supplier_invoices') .select('*, supplier:suppliers(id, name)') .eq('user_id', user.id) if (status && status !== 'all') { if (status === 'to_pay') { query = query.in('status', ['approved', 'overdue']) } else { query = query.eq('status', status) } } const { data, error } = await query.order('due_date', { ascending: true }) if (error) { return NextResponse.json({ error: error.message }, { status: 500 }) } return NextResponse.json({ data }) } export async function POST(request: Request) { const supabase = await createClient() const { data: { user } } = await supabase.auth.getUser() if (!user) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) } const validation = await validateBody(request, CreateSupplierInvoiceSchema) if (!validation.success) return validation.response const body = validation.data // Validate supplier exists and belongs to user const { data: supplier, error: supplierError } = await supabase .from('suppliers') .select('*') .eq('id', body.supplier_id) .eq('user_id', user.id) .single() if (supplierError || !supplier) { return NextResponse.json({ error: 'Supplier not found' }, { status: 404 }) } // Get next arrival number const { data: arrivalNum, error: arrivalError } = await supabase .rpc('get_next_arrival_number', { p_user_id: user.id }) if (arrivalError) { return NextResponse.json({ error: 'Failed to get arrival number' }, { status: 500 }) } // Calculate totals from items (supports both amount-based and legacy quantity*price) const items = body.items.map((item, index) => { const vatRate = item.vat_rate ?? 0.25 const lineTotal = item.amount != null ? Math.round(item.amount * 100) / 100 : Math.round((item.quantity ?? 1) * (item.unit_price ?? 0) * 100) / 100 const vatAmount = Math.round(lineTotal * vatRate * 100) / 100 return { sort_order: index, description: item.description, quantity: item.amount != null ? 1 : (item.quantity ?? 1), unit: item.amount != null ? 'st' : (item.unit || 'st'), unit_price: item.amount != null ? lineTotal : (item.unit_price ?? 0), line_total: lineTotal, account_number: item.account_number, vat_code: item.vat_code || null, vat_rate: vatRate, vat_amount: vatAmount, } }) const subtotal = items.reduce((sum, i) => sum + i.line_total, 0) const vatAmount = items.reduce((sum, i) => sum + i.vat_amount, 0) const total = Math.round((subtotal + vatAmount) * 100) / 100 const exchangeRate = body.exchange_rate || null const subtotalSek = exchangeRate ? Math.round(subtotal * exchangeRate * 100) / 100 : null const vatAmountSek = exchangeRate ? Math.round(vatAmount * exchangeRate * 100) / 100 : null const totalSek = exchangeRate ? Math.round(total * exchangeRate * 100) / 100 : null // Insert supplier invoice const { data: invoice, error: invoiceError } = await supabase .from('supplier_invoices') .insert({ user_id: user.id, supplier_id: body.supplier_id, arrival_number: arrivalNum, supplier_invoice_number: body.supplier_invoice_number, invoice_date: body.invoice_date, due_date: body.due_date, delivery_date: body.delivery_date || null, status: 'registered', currency: body.currency || 'SEK', exchange_rate: exchangeRate, vat_treatment: body.vat_treatment || 'standard_25', reverse_charge: body.reverse_charge || false, payment_reference: body.payment_reference || null, subtotal: Math.round(subtotal * 100) / 100, subtotal_sek: subtotalSek, vat_amount: Math.round(vatAmount * 100) / 100, vat_amount_sek: vatAmountSek, total: Math.round(total * 100) / 100, total_sek: totalSek, remaining_amount: Math.round(total * 100) / 100, notes: body.notes || null, }) .select() .single() if (invoiceError || !invoice) { return NextResponse.json({ error: invoiceError?.message || 'Failed to create invoice' }, { status: 500 }) } // Insert line items const itemInserts = items.map((item) => ({ supplier_invoice_id: invoice.id, ...item, })) const { error: itemsError } = await supabase .from('supplier_invoice_items') .insert(itemInserts) if (itemsError) { // Clean up invoice on items failure await supabase.from('supplier_invoices').delete().eq('id', invoice.id) return NextResponse.json({ error: itemsError.message }, { status: 500 }) } // Accrual method: create registration journal entry const { data: settings } = await supabase .from('company_settings') .select('accounting_method') .eq('user_id', user.id) .single() const accountingMethod = settings?.accounting_method || 'accrual' let registrationJournalEntryId: string | null = null if (accountingMethod === 'accrual') { try { const journalEntry = await createSupplierInvoiceRegistrationEntry( supabase, user.id, invoice as SupplierInvoice, items as SupplierInvoiceItem[], supplier.supplier_type ) if (journalEntry) { registrationJournalEntryId = journalEntry.id await supabase .from('supplier_invoices') .update({ registration_journal_entry_id: journalEntry.id }) .eq('id', invoice.id) } } catch (err) { console.error('Failed to create registration journal entry:', err) } } try { await eventBus.emit({ type: 'supplier_invoice.registered', payload: { supplierInvoice: invoice as SupplierInvoice, userId: user.id }, }) } catch { // Non-blocking — event emission failure should not affect the response } return NextResponse.json({ data: { ...invoice, items: itemInserts, registration_journal_entry_id: registrationJournalEntryId, }, }) }