import { NextRequest, NextResponse } from 'next/server'; import { getServerSession } from 'next-auth'; import { authOptions } from '@/lib/auth'; import { db } from '@/lib/db'; interface RouteContext { params: Promise<{ id: string }>; } // GET /api/sales/[id] - Get a single sale with items, payments, and products export async function GET( request: NextRequest, context: RouteContext ) { try { const session = await getServerSession(authOptions); if (!session?.user) { return NextResponse.json( { error: 'Unauthorized' }, { status: 401 } ); } const { id } = await context.params; const sale = await db.sale.findFirst({ where: { id, createdBy: { organizationId: session.user.organizationId, }, }, include: { items: { include: { product: { select: { id: true, name: true, sku: true, price: true, image: true, category: { select: { id: true, name: true, }, }, }, }, }, }, payments: { select: { id: true, amount: true, paymentType: true, reference: true, notes: true, createdAt: true, }, }, client: { select: { id: true, firstName: true, lastName: true, email: true, phone: true, }, }, createdBy: { select: { id: true, firstName: true, lastName: true, email: true, }, }, cashRegister: { select: { id: true, openedAt: true, closedAt: true, site: { select: { id: true, name: true, }, }, user: { select: { id: true, firstName: true, lastName: true, }, }, }, }, }, }); if (!sale) { return NextResponse.json( { error: 'Sale not found' }, { status: 404 } ); } return NextResponse.json(sale); } catch (error) { console.error('Error fetching sale:', error); return NextResponse.json( { error: 'Failed to fetch sale' }, { status: 500 } ); } } // DELETE /api/sales/[id] - Void/cancel a sale and restore stock export async function DELETE( request: NextRequest, context: RouteContext ) { try { const session = await getServerSession(authOptions); if (!session?.user) { return NextResponse.json( { error: 'Unauthorized' }, { status: 401 } ); } // Check if user has admin role const allowedRoles = ['SUPER_ADMIN', 'ORG_ADMIN', 'SITE_ADMIN']; if (!allowedRoles.includes(session.user.role)) { return NextResponse.json( { error: 'Forbidden: Insufficient permissions to void sales' }, { status: 403 } ); } const { id } = await context.params; // Fetch the sale with items const sale = await db.sale.findFirst({ where: { id, createdBy: { organizationId: session.user.organizationId, }, }, include: { items: { include: { product: true, }, }, cashRegister: true, }, }); if (!sale) { return NextResponse.json( { error: 'Sale not found' }, { status: 404 } ); } // If sale is associated with a closed cash register, we cannot void it if (sale.cashRegister && sale.cashRegister.closedAt) { return NextResponse.json( { error: 'Cannot void a sale from a closed cash register' }, { status: 400 } ); } // If user is SITE_ADMIN, verify they have access to the cash register's site if (session.user.role === 'SITE_ADMIN' && sale.cashRegister) { if (session.user.siteId !== sale.cashRegister.siteId) { return NextResponse.json( { error: 'Forbidden: You do not have access to void this sale' }, { status: 403 } ); } } // Void the sale within a transaction await db.$transaction(async (tx) => { // Restore stock for each item for (const item of sale.items) { if (item.product.trackStock) { await tx.product.update({ where: { id: item.productId }, data: { stock: { increment: item.quantity, }, }, }); } } // Delete payments associated with this sale await tx.payment.deleteMany({ where: { saleId: id }, }); // Delete sale items await tx.saleItem.deleteMany({ where: { saleId: id }, }); // Delete the sale await tx.sale.delete({ where: { id }, }); }); return NextResponse.json({ message: 'Sale voided successfully', restoredItems: sale.items.map(item => ({ productId: item.productId, productName: item.product.name, quantity: item.quantity, stockRestored: item.product.trackStock, })), }); } catch (error) { console.error('Error voiding sale:', error); return NextResponse.json( { error: 'Failed to void sale' }, { status: 500 } ); } }