fix: workspace resolution via ArcGIS listLayer + seed UATs from uat.json
- resolveWorkspace: use listLayer() instead of listLayerByWhere() with hardcoded field names. Auto-discovers admin field (ADMIN_UNIT_ID/SIRUTA) from ArcGIS layer metadata via buildWhere(). - resolveWorkspace: persist WORKSPACE_ID to DB on first resolution for fast subsequent lookups. - UATs POST: seed from uat.json (correct SIRUTA codes) instead of eTerra nomenclature API (nomenPk != SIRUTA, county nomenPk != WORKSPACE_ID). - Remove eTerra nomenclature dependency from UATs endpoint. - Fix activeJobs Set iteration error on container restart. - Remove unused enrichedUatsFetched ref.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
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";
|
||||
import { readFile } from "fs/promises";
|
||||
import { join } from "path";
|
||||
|
||||
export const runtime = "nodejs";
|
||||
export const dynamic = "force-dynamic";
|
||||
@@ -74,119 +74,74 @@ export async function GET() {
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* POST /api/eterra/uats */
|
||||
/* */
|
||||
/* Sync check: compare eTerra county count vs DB. */
|
||||
/* If DB is empty or county count differs → full fetch + upsert. */
|
||||
/* Otherwise returns { synced: false, reason: "up-to-date" }. */
|
||||
/* Seed DB from static uat.json. */
|
||||
/* eTerra nomenPk ≠ SIRUTA, so we cannot use the nomenclature API */
|
||||
/* for populating UAT data. uat.json has correct SIRUTA codes. */
|
||||
/* Workspace (county) PKs are resolved lazily via ArcGIS layer query */
|
||||
/* in the search route and persisted to DB on first resolution. */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
export async function POST() {
|
||||
try {
|
||||
// Need eTerra credentials for sync
|
||||
const session = getSessionCredentials();
|
||||
const username = String(
|
||||
session?.username || process.env.ETERRA_USERNAME || "",
|
||||
).trim();
|
||||
const password = String(
|
||||
session?.password || process.env.ETERRA_PASSWORD || "",
|
||||
).trim();
|
||||
// Check if DB already has data
|
||||
const dbCount = await prisma.gisUat.count();
|
||||
if (dbCount > 0) {
|
||||
return NextResponse.json({
|
||||
synced: false,
|
||||
reason: "already-seeded",
|
||||
total: dbCount,
|
||||
});
|
||||
}
|
||||
|
||||
if (!username || !password) {
|
||||
// Read uat.json from public/ directory
|
||||
let rawUats: Array<{ siruta: string; name: string }>;
|
||||
try {
|
||||
const filePath = join(process.cwd(), "public", "uat.json");
|
||||
const content = await readFile(filePath, "utf-8");
|
||||
rawUats = JSON.parse(content);
|
||||
} catch {
|
||||
return NextResponse.json(
|
||||
{ error: "Conectează-te la eTerra mai întâi.", synced: false },
|
||||
{ status: 401 },
|
||||
{ error: "Nu s-a putut citi uat.json", synced: false },
|
||||
{ status: 500 },
|
||||
);
|
||||
}
|
||||
|
||||
const client = await EterraClient.create(username, password);
|
||||
|
||||
// Quick check: fetch county list from eTerra (lightweight)
|
||||
const counties = await client.fetchCounties();
|
||||
const eterraCountyCount = counties.length;
|
||||
|
||||
// Compare with DB
|
||||
const dbCounties = await prisma.gisUat.groupBy({
|
||||
by: ["county"],
|
||||
_count: true,
|
||||
});
|
||||
const dbCountyCount = dbCounties.length;
|
||||
const dbTotalUats = await prisma.gisUat.count();
|
||||
|
||||
// If county counts match and we have data → already synced
|
||||
if (
|
||||
dbCountyCount === eterraCountyCount &&
|
||||
dbCountyCount > 0 &&
|
||||
dbTotalUats > 0
|
||||
) {
|
||||
if (!Array.isArray(rawUats) || rawUats.length === 0) {
|
||||
return NextResponse.json({
|
||||
synced: false,
|
||||
reason: "up-to-date",
|
||||
total: dbTotalUats,
|
||||
counties: dbCountyCount,
|
||||
reason: "empty-uat-json",
|
||||
total: 0,
|
||||
});
|
||||
}
|
||||
|
||||
// Full sync: fetch all UATs for all counties
|
||||
const enriched: EnrichedUat[] = [];
|
||||
|
||||
for (const county of counties) {
|
||||
const countyPk = county?.nomenPk ?? county?.pk ?? county?.id;
|
||||
const countyName = String(county?.name ?? "").trim();
|
||||
if (!countyPk || !countyName) continue;
|
||||
|
||||
try {
|
||||
const uats = await client.fetchAdminUnitsByCounty(countyPk);
|
||||
for (const uat of uats) {
|
||||
const uatPk = String(uat?.nomenPk ?? uat?.pk ?? "");
|
||||
const uatName = String(uat?.name ?? "").trim();
|
||||
if (!uatPk || !uatName) continue;
|
||||
|
||||
enriched.push({
|
||||
siruta: uatPk,
|
||||
name: uatName,
|
||||
county: countyName,
|
||||
workspacePk: Number(countyPk),
|
||||
});
|
||||
}
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
// Batch insert in chunks of 500 (Prisma transaction limit)
|
||||
const CHUNK_SIZE = 500;
|
||||
let inserted = 0;
|
||||
for (let i = 0; i < rawUats.length; i += CHUNK_SIZE) {
|
||||
const chunk = rawUats.slice(i, i + CHUNK_SIZE);
|
||||
await prisma.$transaction(
|
||||
chunk
|
||||
.filter((u) => u.siruta && u.name)
|
||||
.map((u) =>
|
||||
prisma.gisUat.upsert({
|
||||
where: { siruta: String(u.siruta) },
|
||||
update: { name: String(u.name).trim() },
|
||||
create: {
|
||||
siruta: String(u.siruta),
|
||||
name: String(u.name).trim(),
|
||||
},
|
||||
}),
|
||||
),
|
||||
);
|
||||
inserted += chunk.length;
|
||||
}
|
||||
|
||||
if (enriched.length === 0) {
|
||||
return NextResponse.json({
|
||||
synced: false,
|
||||
reason: "no-data-from-eterra",
|
||||
total: dbTotalUats,
|
||||
});
|
||||
}
|
||||
|
||||
// Batch upsert into DB
|
||||
await prisma.$transaction(
|
||||
enriched.map((u) =>
|
||||
prisma.gisUat.upsert({
|
||||
where: { siruta: u.siruta },
|
||||
update: {
|
||||
name: u.name,
|
||||
county: u.county,
|
||||
workspacePk: u.workspacePk,
|
||||
},
|
||||
create: {
|
||||
siruta: u.siruta,
|
||||
name: u.name,
|
||||
county: u.county,
|
||||
workspacePk: u.workspacePk,
|
||||
},
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
// Populate in-memory cache
|
||||
populateWorkspaceCache(enriched);
|
||||
console.log(`[uats] Seeded ${inserted} UATs from uat.json`);
|
||||
|
||||
return NextResponse.json({
|
||||
synced: true,
|
||||
total: enriched.length,
|
||||
counties: eterraCountyCount,
|
||||
total: inserted,
|
||||
source: "uat-json",
|
||||
});
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : "Eroare server";
|
||||
|
||||
Reference in New Issue
Block a user