diff --git a/src/modules/parcel-sync/components/parcel-sync-module.tsx b/src/modules/parcel-sync/components/parcel-sync-module.tsx index 309d402..f370060 100644 --- a/src/modules/parcel-sync/components/parcel-sync-module.tsx +++ b/src/modules/parcel-sync/components/parcel-sync-module.tsx @@ -394,8 +394,10 @@ export function ParcelSyncModule() { qualityBreakdown: { withCadRef: number; withPaperCad: number; - withPaperCf: number; + withPaperLb: number; + withLandbook: number; withArea: number; + withActiveStatus: number; useful: number; empty: number; }; @@ -704,8 +706,10 @@ export function ParcelSyncModule() { const emptyQuality = { withCadRef: 0, withPaperCad: 0, - withPaperCf: 0, + withPaperLb: 0, + withLandbook: 0, withArea: 0, + withActiveStatus: 0, useful: 0, empty: 0, }; @@ -745,8 +749,10 @@ export function ParcelSyncModule() { qualityBreakdown: { withCadRef: Number(qb.withCadRef ?? 0), withPaperCad: Number(qb.withPaperCad ?? 0), - withPaperCf: Number(qb.withPaperCf ?? 0), + withPaperLb: Number(qb.withPaperLb ?? 0), + withLandbook: Number(qb.withLandbook ?? 0), withArea: Number(qb.withArea ?? 0), + withActiveStatus: Number(qb.withActiveStatus ?? 0), useful: Number(qb.useful ?? 0), empty: Number(qb.empty ?? 0), }, @@ -2663,9 +2669,9 @@ export function ParcelSyncModule() { - Cu nr. CF pe hârtie:{" "} + Cu nr. CF/LB:{" "} - {noGeomScan.qualityBreakdown.withPaperCf.toLocaleString( + {noGeomScan.qualityBreakdown.withPaperLb.toLocaleString( "ro-RO", )} @@ -2686,6 +2692,22 @@ export function ParcelSyncModule() { )} + + Active (status=1):{" "} + + {noGeomScan.qualityBreakdown.withActiveStatus.toLocaleString( + "ro-RO", + )} + + + + Cu carte funciară:{" "} + + {noGeomScan.qualityBreakdown.withLandbook.toLocaleString( + "ro-RO", + )} + +
{noGeomScan.qualityBreakdown.empty > 0 - ? `Din ${noGeomScan.noGeomCount.toLocaleString("ro-RO")} fără geometrie, ~${noGeomScan.qualityBreakdown.useful.toLocaleString("ro-RO")} vor fi importate (cele cu identificare sau suprafață). ${noGeomScan.qualityBreakdown.empty.toLocaleString("ro-RO")} fără nicio dată de identificare vor fi filtrate.` + ? `Din ${noGeomScan.noGeomCount.toLocaleString("ro-RO")} fără geometrie, ~${noGeomScan.qualityBreakdown.useful.toLocaleString("ro-RO")} vor fi importate (active, cu identificare sau suprafață). ${noGeomScan.qualityBreakdown.empty.toLocaleString("ro-RO")} vor fi filtrate (inactive sau fără date).` : "Vor fi importate în DB și incluse în CSV + Magic GPKG (coloana HAS_GEOMETRY=0/1)."}{" "} În GPKG de bază apar doar cele cu geometrie.
diff --git a/src/modules/parcel-sync/services/enrich-service.ts b/src/modules/parcel-sync/services/enrich-service.ts index 9bd918d..5601811 100644 --- a/src/modules/parcel-sync/services/enrich-service.ts +++ b/src/modules/parcel-sync/services/enrich-service.ts @@ -20,6 +20,8 @@ const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms)); export type EnrichResult = { siruta: string; enrichedCount: number; + totalFeatures?: number; + unenrichedCount?: number; buildingCrossRefs: number; status: "done" | "error"; error?: string; @@ -545,8 +547,21 @@ export async function enrichFeatures( const buildLegal = build.has ? (build.legal ? 1 : 0) : 0; if (hasBuilding) buildingCrossRefs += 1; - const areaValue = + // Area: prefer GIS AREA_VALUE, fall back to measuredArea/legalArea from + // immovable list (important for no-geometry features where AREA_VALUE + // may have been stored from measuredArea at import time, or may be null). + let areaValue = typeof attrs.AREA_VALUE === "number" ? attrs.AREA_VALUE : null; + if (areaValue == null && listItem) { + areaValue = + (typeof listItem.measuredArea === "number" && + listItem.measuredArea > 0 + ? listItem.measuredArea + : null) ?? + (typeof listItem.legalArea === "number" && listItem.legalArea > 0 + ? listItem.legalArea + : null); + } const enrichment: FeatureEnrichment = { NR_CAD: cadRefRaw, @@ -585,6 +600,19 @@ export async function enrichFeatures( } } + // ── Post-enrichment verification ── + // Check that ALL features now have enrichment (no gaps) + const unenriched = terenuri.length - enrichedCount; + if (unenriched > 0) { + console.warn( + `[enrich] ${unenriched}/${terenuri.length} features remain unenriched for siruta=${siruta}`, + ); + } else { + console.log( + `[enrich] ✓ 100% enrichment: ${enrichedCount}/${terenuri.length} features for siruta=${siruta}`, + ); + } + push({ phase: "Îmbogățire completă", status: "done", @@ -596,6 +624,8 @@ export async function enrichFeatures( return { siruta, enrichedCount, + totalFeatures: terenuri.length, + unenrichedCount: unenriched, buildingCrossRefs, status: "done", }; diff --git a/src/modules/parcel-sync/services/no-geom-sync.ts b/src/modules/parcel-sync/services/no-geom-sync.ts index 462f136..74bef8b 100644 --- a/src/modules/parcel-sync/services/no-geom-sync.ts +++ b/src/modules/parcel-sync/services/no-geom-sync.ts @@ -97,13 +97,17 @@ export type NoGeomQuality = { withCadRef: number; /** Have paper cadastral number */ withPaperCad: number; - /** Have paper CF (carte funciară) number */ - withPaperCf: number; - /** Have area > 0 */ + /** Have paper LB / CF (carte funciară) number — field is paperLbNo in API */ + withPaperLb: number; + /** Have hasLandbook=1 flag from eTerra */ + withLandbook: number; + /** Have area > 0 (measuredArea or legalArea) */ withArea: number; - /** "Useful" = have cadRef OR (paperCad AND paperCf) */ + /** status=1 (active) in eTerra */ + withActiveStatus: number; + /** "Useful" = active AND has identification or area */ useful: number; - /** No cadRef, no paperCad, no paperCf — likely unusable */ + /** Filtered out: inactive, or no identification AND no area */ empty: number; }; @@ -121,8 +125,10 @@ export type NoGeomScanResult = { immovablePk: number; identifierDetails: string; paperCadNo?: string; - paperCfNo?: string; paperLbNo?: string; + status?: number; + hasLandbook?: number; + measuredArea?: number; }>; /** Total features already in local DB (geometry + no-geom) */ localDbTotal: number; @@ -177,8 +183,10 @@ export async function scanNoGeometryParcels( qualityBreakdown: { withCadRef: 0, withPaperCad: 0, - withPaperCf: 0, + withPaperLb: 0, + withLandbook: 0, withArea: 0, + withActiveStatus: 0, useful: 0, empty: 0, }, @@ -232,8 +240,11 @@ export async function scanNoGeometryParcels( immovablePk: number; identifierDetails: string; paperCadNo?: string; - paperCfNo?: string; paperLbNo?: string; + status?: number; + hasLandbook?: number; + measuredArea?: number; + legalArea?: number; }> = []; for (const item of allImmovables) { @@ -251,8 +262,14 @@ export async function scanNoGeometryParcels( immovablePk: immPk, identifierDetails: String(item.identifierDetails ?? ""), paperCadNo: item.paperCadNo ?? undefined, - paperCfNo: item.paperCfNo ?? undefined, paperLbNo: item.paperLbNo ?? undefined, + status: typeof item.status === "number" ? item.status : undefined, + hasLandbook: + typeof item.hasLandbook === "number" ? item.hasLandbook : undefined, + measuredArea: + typeof item.measuredArea === "number" ? item.measuredArea : undefined, + legalArea: + typeof item.legalArea === "number" ? item.legalArea : undefined, }); } @@ -317,43 +334,33 @@ export async function scanNoGeometryParcels( const matchedCount = allImmovables.length - noGeomItems.length; // Quality analysis of no-geom items - // Build a quick lookup for area data from the immovable list (any area field) - const areaByPk = new Map