/** * POST /api/geoportal/enrich * * Quick single-parcel enrichment via eTerra immovable API. * Persists result in GisFeature.enrichment column. * * Body: { featureId: string } (GisFeature UUID) */ import { NextResponse } from "next/server"; import { prisma } from "@/core/storage/prisma"; import { EterraClient } from "@/modules/parcel-sync/services/eterra-client"; import { getSessionCredentials } from "@/modules/parcel-sync/services/session-store"; export const runtime = "nodejs"; export const dynamic = "force-dynamic"; async function getClient(): Promise { const session = getSessionCredentials(); const username = session?.username || process.env.ETERRA_USERNAME || ""; const password = session?.password || process.env.ETERRA_PASSWORD || ""; if (!username || !password) { throw new Error("Credentiale eTerra indisponibile. Deschide eTerra Parcele si logheaza-te."); } return EterraClient.create(username, password); } export async function POST(req: Request) { try { const body = (await req.json()) as { featureId?: string; siruta?: string; objectId?: number }; // Find the feature let feature; if (body.featureId) { feature = await prisma.gisFeature.findUnique({ where: { id: body.featureId }, select: { id: true, objectId: true, siruta: true, cadastralRef: true, attributes: true, areaValue: true, enrichment: true, enrichedAt: true }, }); } else if (body.siruta && body.objectId) { feature = await prisma.gisFeature.findFirst({ where: { siruta: body.siruta, objectId: body.objectId }, select: { id: true, objectId: true, siruta: true, cadastralRef: true, attributes: true, areaValue: true, enrichment: true, enrichedAt: true }, }); } if (!feature) { return NextResponse.json({ error: "Parcela negasita in baza de date" }, { status: 404 }); } // Already enriched recently (< 7 days)? if (feature.enrichedAt) { const age = Date.now() - new Date(feature.enrichedAt).getTime(); if (age < 7 * 24 * 3600 * 1000 && feature.enrichment) { return NextResponse.json({ status: "ok", message: "Datele sunt deja actualizate", enrichment: feature.enrichment, }); } } const client = await getClient(); // Get workspace PK from GisUat const uat = await prisma.gisUat.findUnique({ where: { siruta: feature.siruta }, select: { workspacePk: true }, }); if (!uat?.workspacePk) { return NextResponse.json({ error: "UAT fara workspace. Sincronizeaza UAT-ul din eTerra Parcele." }, { status: 400 }); } // Fetch immovable data from eTerra for this specific parcel const attrs = (feature.attributes ?? {}) as Record; const cadRef = feature.cadastralRef ?? String(attrs.NATIONAL_CADASTRAL_REFERENCE ?? ""); // Search by cadastral reference const searchResult = await client.fetchImmovableListByAdminUnit( uat.workspacePk, Number(attrs.ADMIN_UNIT_ID ?? 0), 0, 100, ); // Find matching parcel in results const items = (searchResult as { content?: Array> })?.content ?? []; const match = items.find((item: Record) => { const itemCad = String(item.nationalCadastralReference ?? item.cadastralNo ?? ""); return itemCad === cadRef || String(item.objectId) === String(feature.objectId); }); // Build enrichment from available data const enrichment: Record = { NR_CAD: cadRef, NR_CF: match ? String(match.cfNumber ?? match.cfNo ?? "") : "", NR_CF_VECHI: "", NR_TOPO: "", ADRESA: "", PROPRIETARI: match ? formatOwners(match) : "", PROPRIETARI_VECHI: "", SUPRAFATA_2D: feature.areaValue ?? "", SUPRAFATA_R: feature.areaValue ? Math.round(feature.areaValue) : "", SOLICITANT: "", INTRAVILAN: match ? (match.isIntravillan ? "DA" : "Nu") : "", CATEGORIE_FOLOSINTA: match ? String(match.landUseCategory ?? "") : "", HAS_BUILDING: 0, BUILD_LEGAL: 0, }; // Persist await prisma.gisFeature.update({ where: { id: feature.id }, data: { enrichment: enrichment as object, enrichedAt: new Date(), }, }); return NextResponse.json({ status: "ok", message: "Parcela imbogatita cu succes", enrichment, }); } catch (error) { const msg = error instanceof Error ? error.message : "Eroare"; if (msg.includes("timeout") || msg.includes("ETIMEDOUT")) { return NextResponse.json({ error: "eTerra nu raspunde. Incearca mai tarziu." }, { status: 504 }); } if (msg.includes("maintenance") || msg.includes("Mentenan")) { return NextResponse.json({ error: "eTerra in mentenanta." }, { status: 503 }); } return NextResponse.json({ error: msg }, { status: 500 }); } } function formatOwners(item: Record): string { const owners = item.owners ?? item.proprietari; if (Array.isArray(owners)) { return owners.map((o: Record) => String(o.name ?? o.fullName ?? "")).filter(Boolean).join("; "); } if (typeof owners === "string") return owners; return ""; }