import { NextRequest, NextResponse } from 'next/server'; import { invoiceSchema, updateInvoiceSchema } from 'src/schemas'; import prisma from 'src/lib/prisma'; import { authenticateRequest } from 'src/lib/auth-middleware'; import { Prisma } from '@prisma/client'; export async function GET(request: NextRequest, { params }: { params: { id: string } }) { try { // Validate ID format if (!params.id || !/^[0-9a-fA-F-]+$/.test(params.id)) { return NextResponse.json({ error: 'Invalid invoice ID format' }, { status: 400 }); } // Authenticate request const authResult = await authenticateRequest(request); if (authResult instanceof NextResponse) { return authResult; } const { userId } = authResult; // Fetch invoice with user check const invoice = await prisma.invoice.findFirst({ where: { id: params.id, // invoiceFromId: userId, }, include: { invoiceFrom: true, invoiceTo: true, items: true, }, }); if (!invoice) { return NextResponse.json({ error: 'Invoice not found or access denied' }, { status: 404 }); } return NextResponse.json(invoice); } catch (error) { console.error('Error fetching invoice:', error); if (error instanceof Prisma.PrismaClientKnownRequestError) { return NextResponse.json({ error: 'Database error occurred' }, { status: 500 }); } return NextResponse.json({ error: 'Internal server error' }, { status: 500 }); } } export async function PATCH(request: NextRequest, { params }: { params: { id: string } }) { try { // Validate ID format if (!params.id || !/^[0-9a-fA-F-]+$/.test(params.id)) { return NextResponse.json({ error: 'Invalid invoice ID format' }, { status: 400 }); } // Authenticate request const authResult = await authenticateRequest(request); if (authResult instanceof NextResponse) { return authResult; } const { userId } = authResult; // Parse and validate request body const body = await request.json(); const validation = updateInvoiceSchema.partial().safeParse(body); if (!validation.success) { return NextResponse.json( { error: 'Invalid invoice data', details: validation.error.format() }, { status: 400 } ); } // Verify invoice exists and belongs to user const existingInvoice = await prisma.invoice.findFirst({ where: { id: params.id, // invoiceFromId: userId, }, }); if (!existingInvoice) { return NextResponse.json({ error: 'Invoice not found or access denied' }, { status: 404 }); } // Update invoice and related data const updatedInvoice = await prisma.$transaction(async (tx) => { // Conditionally delete and recreate items only if they are provided if (validation.data.items) { await tx.lineItem.deleteMany({ where: { invoiceId: params.id }, }); } // Update the invoice and create new items if provided return tx.invoice.update({ where: { id: params.id }, data: { invoiceNumber: validation.data.invoiceNumber, createDate: validation.data.createDate, dueDate: validation.data.dueDate, status: validation.data.status, currency: validation.data.currency, quantityType: validation.data.quantityType, subTotal: validation.data.subTotal, month: validation.data.month, totalAmount: validation.data.totalAmount, discount: validation.data.discount, taxes: validation.data.taxes, pdfRef: validation.data.pdfRef, invoiceTo: { update: validation.data.invoiceTo, }, items: validation.data.items ? { create: validation.data.items.map((item) => ({ ...item, service: { connect: { id: item.service.id }, }, })), } : undefined, }, include: { invoiceFrom: true, invoiceTo: true, items: true, }, }); }); return NextResponse.json(updatedInvoice); } catch (error) { console.error('Error updating invoice:', error); if (error instanceof Prisma.PrismaClientKnownRequestError) { return NextResponse.json({ error: 'Database error occurred' }, { status: 500 }); } return NextResponse.json({ error: 'Internal server error' }, { status: 500 }); } } export async function DELETE(request: NextRequest, { params }: { params: { id: string } }) { try { // Validate ID format if (!params.id || !/^[0-9a-fA-F-]+$/.test(params.id)) { return NextResponse.json({ error: 'Invalid invoice ID format' }, { status: 400 }); } // Authenticate request const authResult = await authenticateRequest(request); if (authResult instanceof NextResponse) { return authResult; } const { userId } = authResult; console.log('userId', userId); // Verify invoice exists and belongs to user const existingInvoice = await prisma.invoice.findFirst({ where: { id: params.id, }, }); if (!existingInvoice) { return NextResponse.json({ error: 'Invoice not found or access denied' }, { status: 404 }); } // Delete invoice and related items in a transaction await prisma.$transaction(async (tx) => { // Delete related items first await tx.lineItem.deleteMany({ where: { invoiceId: params.id }, }); // Delete the invoice await tx.invoice.delete({ where: { id: params.id }, }); }); return NextResponse.json({ message: 'Invoice deleted successfully' }, { status: 200 }); } catch (error) { console.error('Error deleting invoice:', error); if (error instanceof Prisma.PrismaClientKnownRequestError) { if (error.code === 'P2025') { return NextResponse.json({ error: 'Invoice not found' }, { status: 404 }); } return NextResponse.json({ error: 'Database error occurred' }, { status: 500 }); } return NextResponse.json({ error: 'Internal server error' }, { status: 500 }); } }