import { NextResponse } from "next/server"; import { prisma } from "@/core/storage/prisma"; import { requireCfAccess } from "@/core/auth/cf-access"; import { enrichCfLocations } from "@/modules/parcel-sync/services/cf-enrich-location"; export const runtime = "nodejs"; export const dynamic = "force-dynamic"; /** * GET /api/ancpi/orders — list all CF extract orders. * * Query params: * ?nrCadastral=123 — single cadastral number * ?nrCadastral=123,456 — comma-separated for batch status check * ?status=completed — filter by status * ?limit=50&offset=0 — pagination * * When nrCadastral contains commas, returns an extra `statusMap` field: * { orders, total, statusMap: { "123": "valid", "456": "expired", "789": "none" } } * - "valid" = completed + expiresAt > now * - "expired" = completed + expiresAt <= now * - "none" = no completed record */ export async function GET(req: Request) { try { const access = await requireCfAccess(); if (!access.ok) { return NextResponse.json({ error: access.error }, { status: access.status }); } const url = new URL(req.url); const nrCadastralParam = url.searchParams.get("nrCadastral") || undefined; const status = url.searchParams.get("status") || undefined; const limit = Math.min(parseInt(url.searchParams.get("limit") ?? "50"), 200); const offset = parseInt(url.searchParams.get("offset") ?? "0"); // Check if multi-cadastral query const cadastralNumbers = nrCadastralParam ? nrCadastralParam.split(",").map((s) => s.trim()).filter(Boolean) : []; const isMulti = cadastralNumbers.length > 1; const where: Record = {}; if (cadastralNumbers.length === 1) { where.nrCadastral = cadastralNumbers[0]; } else if (isMulti) { where.nrCadastral = { in: cadastralNumbers }; } if (status) where.status = status; const [orders, total] = await Promise.all([ prisma.cfExtract.findMany({ where, orderBy: { createdAt: "desc" }, take: limit, skip: offset, }), prisma.cfExtract.count({ where }), ]); // Fill missing uatName/judetName from SIRUTA (old intern rows stored an // empty judetName) so the list shows localitate + judet for them too. await enrichCfLocations(orders); // Build statusMap for multi-cadastral queries (or single if requested) if (cadastralNumbers.length > 0) { const now = new Date(); // For status map, we need completed records for each cadastral number const completedRecords = await prisma.cfExtract.findMany({ where: { nrCadastral: { in: cadastralNumbers }, status: "completed", }, orderBy: { createdAt: "desc" }, select: { id: true, nrCadastral: true, expiresAt: true, completedAt: true, minioPath: true, }, }); const statusMap: Record = {}; const latestById: Record = {}; // Find latest completed record per cadastral number for (const rec of completedRecords) { const existing = latestById[rec.nrCadastral]; if (!existing) { latestById[rec.nrCadastral] = rec; } } for (const nr of cadastralNumbers) { const rec = latestById[nr]; if (!rec) { statusMap[nr] = "none"; } else if (rec.expiresAt && rec.expiresAt <= now) { statusMap[nr] = "expired"; } else { statusMap[nr] = "valid"; } } // QW6: surface terminal failure/review so the UI can flag them (a // cadastral whose latest record failed used to show as "none"). Only // applies where there's no valid extract — a fresh valid one wins. const attentionRecords = await prisma.cfExtract.findMany({ where: { nrCadastral: { in: cadastralNumbers }, status: { in: ["failed", "review"] }, }, orderBy: { createdAt: "desc" }, select: { nrCadastral: true, status: true }, }); for (const rec of attentionRecords) { if (statusMap[rec.nrCadastral] === "none") { statusMap[rec.nrCadastral] = rec.status; // "failed" | "review" } } // Active (in-progress) orders take priority over none/failed/review/ // expired — an in-flight re-order should read as "processing". const activeRecords = await prisma.cfExtract.findMany({ where: { nrCadastral: { in: cadastralNumbers }, status: { in: ["pending", "queued", "cart", "searching", "ordering", "polling", "downloading"], }, }, select: { nrCadastral: true }, }); for (const rec of activeRecords) { if (statusMap[rec.nrCadastral] !== "valid") { statusMap[rec.nrCadastral] = "processing"; } } return NextResponse.json({ orders, total, statusMap, latestById }); } return NextResponse.json({ orders, total }); } catch (error) { const message = error instanceof Error ? error.message : "Eroare server"; return NextResponse.json({ error: message }, { status: 500 }); } }