diff --git a/src/app/api/eterra/export-bundle/route.ts b/src/app/api/eterra/export-bundle/route.ts index f0aea75..539234d 100644 --- a/src/app/api/eterra/export-bundle/route.ts +++ b/src/app/api/eterra/export-bundle/route.ts @@ -696,8 +696,12 @@ export async function POST(req: Request) { ...(hasNoGeom ? [ ` 3. Import fără geometrie: ${fmt(noGeomImported)} noi importate` + - (noGeomCleaned > 0 ? `, ${fmt(noGeomCleaned)} vechi șterse` : "") + - (noGeomSkipped > 0 ? `, ${fmt(noGeomSkipped)} filtrate/skip` : ""), + (noGeomCleaned > 0 + ? `, ${fmt(noGeomCleaned)} vechi șterse` + : "") + + (noGeomSkipped > 0 + ? `, ${fmt(noGeomSkipped)} filtrate/skip` + : ""), ] : [` 3. Import fără geometrie: dezactivat`]), ` 4. Îmbogățire (CF, prop.): da`, diff --git a/src/modules/parcel-sync/components/parcel-sync-module.tsx b/src/modules/parcel-sync/components/parcel-sync-module.tsx index f33827c..940c8ce 100644 --- a/src/modules/parcel-sync/components/parcel-sync-module.tsx +++ b/src/modules/parcel-sync/components/parcel-sync-module.tsx @@ -390,6 +390,7 @@ export function ParcelSyncModule() { totalImmovables: number; withGeometry: number; remoteGisCount: number; + remoteCladiriCount: number; noGeomCount: number; matchedByRef: number; matchedById: number; @@ -720,6 +721,7 @@ export function ParcelSyncModule() { totalImmovables: 0, withGeometry: 0, remoteGisCount: 0, + remoteCladiriCount: 0, noGeomCount: 0, matchedByRef: 0, matchedById: 0, @@ -751,6 +753,7 @@ export function ParcelSyncModule() { totalImmovables: Number(data.totalImmovables ?? 0), withGeometry: Number(data.withGeometry ?? 0), remoteGisCount: Number(data.remoteGisCount ?? 0), + remoteCladiriCount: Number(data.remoteCladiriCount ?? 0), noGeomCount: Number(data.noGeomCount ?? 0), matchedByRef: Number(data.matchedByRef ?? 0), matchedById: Number(data.matchedById ?? 0), @@ -2430,7 +2433,13 @@ export function ParcelSyncModule() { session.connected && (() => { const scanDone = noGeomScan !== null && noGeomScanSiruta === siruta; - const hasNoGeomParcels = scanDone && noGeomScan.noGeomCount > 0; + const estimatedNoGeom = scanDone + ? Math.max( + 0, + noGeomScan.totalImmovables - noGeomScan.remoteGisCount, + ) + : 0; + const hasNoGeomParcels = scanDone && estimatedNoGeom > 0; const scanning = noGeomScanning; // Still scanning @@ -2517,9 +2526,7 @@ export function ParcelSyncModule() {

  1. - {noGeomScan.localSyncFresh && noGeomScan.localDbWithGeom > 0 - ? "Sync terenuri + clădiri — " - : "Sync terenuri + clădiri — "} + {"Sync GIS — "} 0 ? "skip (date proaspete în DB)" - : `descarcă ${noGeomScan.remoteGisCount.toLocaleString("ro-RO")} features`} + : `descarcă ${noGeomScan.remoteGisCount.toLocaleString("ro-RO")} terenuri` + + (noGeomScan.remoteCladiriCount > 0 + ? ` + ${noGeomScan.remoteCladiriCount.toLocaleString("ro-RO")} clădiri` + : "")}
  2. {includeNoGeom && ( @@ -2540,7 +2550,6 @@ export function ParcelSyncModule() { Import parcele fără geometrie —{" "} {(() => { - // Only useful items will be imported (quality filter) const usefulNoGeom = noGeomScan.qualityBreakdown.useful; const newNoGeom = Math.max( @@ -2562,20 +2571,23 @@ export function ParcelSyncModule() { Îmbogățire CF, proprietari, adrese —{" "} {(() => { - const usefulNoGeom = noGeomScan.qualityBreakdown.useful; - const totalToEnrich = - noGeomScan.localDbTotal + - (includeNoGeom - ? Math.max( - 0, - usefulNoGeom - noGeomScan.localDbNoGeom, - ) - : 0); - // Use enrichedComplete (not enriched) — stale - // enrichment (missing PROPRIETARI_VECHI etc.) - // will be re-processed + // What will be in DB after sync + optional no-geom import: + // If DB is empty: sync will add remoteGisCount geo features + // If DB is fresh: keep localDbTotal + const geoAfterSync = + noGeomScan.localSyncFresh && + noGeomScan.localDbWithGeom > 0 + ? noGeomScan.localDbWithGeom + : noGeomScan.remoteGisCount; + const noGeomAfterImport = includeNoGeom + ? Math.max( + noGeomScan.localDbNoGeom, + noGeomScan.qualityBreakdown.useful, + ) + : noGeomScan.localDbNoGeom; + const totalAfter = geoAfterSync + noGeomAfterImport; const remaining = - totalToEnrich - noGeomScan.localDbEnrichedComplete; + totalAfter - noGeomScan.localDbEnrichedComplete; return remaining > 0 ? `~${remaining.toLocaleString("ro-RO")} de procesat (~${Math.ceil((remaining * 0.25) / 60)} min)` : "deja îmbogățite"; @@ -2604,38 +2616,37 @@ export function ParcelSyncModule() {

    - Din{" "} - - {noGeomScan.totalImmovables.toLocaleString("ro-RO")} - {" "} - imobile în eTerra:{" "} - - {noGeomScan.withGeometry.toLocaleString("ro-RO")} - {" "} - cu geometrie,{" "} - - {noGeomScan.noGeomCount.toLocaleString("ro-RO")} - {" "} - fără geometrie -

    -

    Layer GIS:{" "} - + {noGeomScan.remoteGisCount.toLocaleString("ro-RO")} - - {" features (se descarcă toate)"} - {noGeomScan.remoteGisCount !== noGeomScan.withGeometry && ( + {" "} + terenuri + {noGeomScan.remoteCladiriCount > 0 && ( <> - {" · "} - {noGeomScan.withGeometry.toLocaleString("ro-RO")} potrivite - cu lista de imobile - {noGeomScan.matchedByRef > 0 && noGeomScan.matchedById > 0 && ( - - {" "}({noGeomScan.matchedByRef} cadRef + {noGeomScan.matchedById} ID) - - )} + {" + "} + + {noGeomScan.remoteCladiriCount.toLocaleString( + "ro-RO", + )} + {" "} + clădiri )} + {" · "} + Lista imobile:{" "} + + {noGeomScan.totalImmovables.toLocaleString("ro-RO")} + + {" (estimat "} + + ~ + {Math.max( + 0, + noGeomScan.totalImmovables - + noGeomScan.remoteGisCount, + ).toLocaleString("ro-RO")} + + {" fără geometrie)"}

    Cele fără geometrie există în baza de date eTerra dar diff --git a/src/modules/parcel-sync/services/no-geom-sync.ts b/src/modules/parcel-sync/services/no-geom-sync.ts index ac85ab7..1a9a73d 100644 --- a/src/modules/parcel-sync/services/no-geom-sync.ts +++ b/src/modules/parcel-sync/services/no-geom-sync.ts @@ -113,10 +113,12 @@ export type NoGeomQuality = { export type NoGeomScanResult = { totalImmovables: number; - /** Immovables that matched a remote GIS feature (have geometry) */ + /** Immovables that matched a remote GIS feature (cross-ref, may vary) */ withGeometry: number; - /** Total features in the remote ArcGIS TERENURI_ACTIVE layer */ + /** Total features in the remote ArcGIS TERENURI_ACTIVE layer (stable) */ remoteGisCount: number; + /** Total features in the remote ArcGIS CLADIRI_ACTIVE layer (stable) */ + remoteCladiriCount: number; noGeomCount: number; /** Match quality: how many matched by cadastral ref vs immovable ID */ matchedByRef: number; @@ -185,6 +187,7 @@ export async function scanNoGeometryParcels( totalImmovables: 0, withGeometry: 0, remoteGisCount: 0, + remoteCladiriCount: 0, noGeomCount: 0, matchedByRef: 0, matchedById: 0, @@ -233,6 +236,25 @@ export async function scanNoGeometryParcels( pageSize: 2000, }); + // 2b. Also fetch CLADIRI_ACTIVE count (lightweight, just OBJECTID) + const cladiriLayer = { + id: "CLADIRI_ACTIVE", + name: "CLADIRI_ACTIVE", + endpoint: "aut" as const, + whereTemplate: "{{adminField}}={{siruta}} AND IS_ACTIVE=1", + }; + let remoteCladiriCount = 0; + try { + const cladiriFeatures = await client.fetchAllLayer(cladiriLayer, siruta, { + returnGeometry: false, + outFields: "OBJECTID", + pageSize: 2000, + }); + remoteCladiriCount = cladiriFeatures.length; + } catch { + // Non-fatal — just won't show clădiri count + } + const remoteCadRefs = new Set(); const remoteImmIds = new Set(); for (const f of remoteFeatures) { @@ -392,6 +414,7 @@ export async function scanNoGeometryParcels( totalImmovables: allImmovables.length, withGeometry: matchedCount, remoteGisCount: remoteFeatures.length, + remoteCladiriCount, noGeomCount: noGeomItems.length, matchedByRef, matchedById,