feat(parcel-sync): import eTerra immovables without geometry

- Add geometrySource field to GisFeature (NO_GEOMETRY marker)
- New no-geom-sync service: scan + import parcels missing from GIS layer
- Uses negative immovablePk as objectId to avoid @@unique collision
- New /api/eterra/no-geom-scan endpoint for counting
- Export-bundle: includeNoGeometry flag, imports before enrich
- CSV export: new HAS_GEOMETRY column (0/1)
- GPKG: still geometry-only (unchanged)
- UI: checkbox + scan button on Export tab
- Baza de Date tab: shows no-geometry counts per UAT
- db-summary API: includes noGeomCount per layer
This commit is contained in:
AI Assistant
2026-03-07 12:58:10 +02:00
parent d50b9ea0e2
commit 30915e8628
6 changed files with 604 additions and 22 deletions
+55
View File
@@ -0,0 +1,55 @@
/**
* POST /api/eterra/no-geom-scan
*
* Scans eTerra immovable list for a UAT and counts how many parcels
* exist in the eTerra database but have no geometry in the GIS layer
* (i.e., they are NOT in the local TERENURI_ACTIVE DB).
*
* Body: { siruta: string }
* Returns: { totalImmovables, totalInDb, noGeomCount, samples }
*
* Requires active eTerra session.
*/
import { NextResponse } from "next/server";
import { EterraClient } from "@/modules/parcel-sync/services/eterra-client";
import { getSessionCredentials } from "@/modules/parcel-sync/services/session-store";
import { scanNoGeometryParcels } from "@/modules/parcel-sync/services/no-geom-sync";
export const runtime = "nodejs";
export const dynamic = "force-dynamic";
export async function POST(req: Request) {
try {
const body = (await req.json()) as { siruta?: string };
const siruta = String(body.siruta ?? "").trim();
if (!/^\d+$/.test(siruta)) {
return NextResponse.json(
{ error: "SIRUTA must be numeric" },
{ status: 400 },
);
}
const session = getSessionCredentials();
const username = String(
session?.username || process.env.ETERRA_USERNAME || "",
).trim();
const password = String(
session?.password || process.env.ETERRA_PASSWORD || "",
).trim();
if (!username || !password) {
return NextResponse.json(
{ error: "Nu ești conectat la eTerra" },
{ status: 401 },
);
}
const client = await EterraClient.create(username, password);
const result = await scanNoGeometryParcels(client, siruta);
return NextResponse.json(result);
} catch (error) {
const message = error instanceof Error ? error.message : "Eroare server";
return NextResponse.json({ error: message }, { status: 500 });
}
}