import { prisma } from "@/lib/prisma"; import { errorResponse, getJsonBody, jsonResponse } from "@/lib/api-helpers"; async function recalcOrderTotal(orderId: number) { const tasks = await prisma.task.findMany({ where: { orderId }, include: { parts: true }, }); const total = tasks.reduce((sum, task) => { const partsCost = task.parts.reduce( (p, tp) => p + (tp.price || 0) * tp.qty, 0, ); const laborCost = task.laborHours * task.hourlyRate; const price = task.price > 0 ? task.price : partsCost + laborCost; return sum + price; }, 0); await prisma.order.update({ where: { id: orderId }, data: { total } }); } export async function POST(req: Request) { const body = await getJsonBody(req); if (!body) return errorResponse("Invalid JSON"); const { orderId, title, notes, laborHours, hourlyRate, price, partIds = [], templateParts = [], } = body; if (!orderId || !title) return errorResponse("orderId and title are required"); const order = await prisma.order.findUnique({ where: { id: Number(orderId) }, include: { car: true }, }); if (!order) return errorResponse("Order not found", 404); const last = await prisma.task.findFirst({ where: { orderId: Number(orderId) }, orderBy: { orderIndex: "desc" }, }); // If the title matches a quick task template, pull its defaults. const quickTask = await prisma.quickTask.findFirst({ where: { title }, include: { parts: true }, }); if (quickTask) { await prisma.quickTask.update({ where: { id: quickTask.id }, data: { useCount: { increment: 1 } }, }); } const hasExplicitLabor = laborHours !== undefined && String(laborHours).trim() !== ""; const hasExplicitRate = hourlyRate !== undefined && String(hourlyRate).trim() !== ""; const hasExplicitPrice = price !== undefined && String(price).trim() !== ""; const taskLaborHours = quickTask && !hasExplicitLabor ? quickTask.laborHours : Number(laborHours) || 0; const taskHourlyRate = quickTask && !hasExplicitRate ? quickTask.hourlyRate : Number(hourlyRate) || 50; const taskPrice = quickTask && !hasExplicitPrice ? quickTask.price : hasExplicitPrice ? Number(price) || 0 : null; const effectiveTemplateParts = templateParts && templateParts.length > 0 ? templateParts : quickTask?.parts || []; const task = await prisma.task.create({ data: { orderId: Number(orderId), title, notes: notes || "", laborHours: Number(taskLaborHours) || 0, hourlyRate: Number(taskHourlyRate) || 50, price: taskPrice ?? undefined, orderIndex: (last?.orderIndex ?? -1) + 1, }, include: { parts: { include: { part: true } } }, }); // Attach selected existing parts — only link to the same car or global parts. for (const item of partIds) { const { partId, qty = 1, price: partPrice } = item; const part = await prisma.part.findFirst({ where: { id: Number(partId), OR: [{ carId: order.carId }, { isGlobal: true }], }, }); if (part) { await prisma.taskPart.create({ data: { taskId: task.id, partId: part.id, qty: Number(qty) || 1, price: partPrice != null ? Number(partPrice) : part.purchasePrice, }, }); } } // Convert template parts into private car parts (or link globals) and attach them. for (const tp of effectiveTemplateParts) { const isGlobal = tp.isGlobal || false; let partId: number | undefined; if (isGlobal) { // Try to find an existing global part with the same name. const existing = await prisma.part.findFirst({ where: { name: tp.name, isGlobal: true }, }); if (existing) { partId = existing.id; } else { const created = await prisma.part.create({ data: { name: tp.name, purchasePrice: Number(tp.price) || 0, notes: "", isGlobal: true, }, }); partId = created.id; } } else { const existing = await prisma.part.findFirst({ where: { name: tp.name, carId: order.carId, isGlobal: false }, }); if (existing) { partId = existing.id; } else { const created = await prisma.part.create({ data: { name: tp.name, purchasePrice: Number(tp.price) || 0, notes: "", carId: order.carId, isGlobal: false, }, }); partId = created.id; } } if (partId) { await prisma.taskPart.create({ data: { taskId: task.id, partId, qty: Number(tp.qty) || 1, price: Number(tp.price) || 0, }, }); } } await recalcOrderTotal(Number(orderId)); if (quickTask) { await prisma.quickTask.update({ where: { id: quickTask.id }, data: { useCount: { increment: 1 } }, }); } else { await prisma.quickTask.upsert({ where: { title }, update: { useCount: { increment: 1 } }, create: { title, useCount: 1 }, }); } const full = await prisma.task.findUnique({ where: { id: task.id }, include: { parts: { include: { part: true } } }, }); return jsonResponse(full, 201); }