fix: scan math consistency + stale enrichment detection + re-enrichment

- withGeometry = matched immovable count (not GIS feature count) — numbers always add up
- Added remoteGisCount to show raw GIS layer count separately
- Enrichment completeness check: ENRICHMENT_REQUIRED_KEYS 7-field schema
- localDbEnrichedComplete vs localDbEnriched detects stale enrichment
- UI: orange warning when enrichment incomplete (missing PROPRIETARI_VECHI)
- UI: workflow preview uses enrichedComplete for accurate time estimate
- UI: note when GIS feature count differs from matched immovable count
- enrich-service: re-enriches features with incomplete schema instead of skipping
This commit is contained in:
AI Assistant
2026-03-07 18:29:03 +02:00
parent ba579d75c1
commit 53914c7fc3
4 changed files with 157 additions and 46 deletions
@@ -389,11 +389,13 @@ export function ParcelSyncModule() {
const [noGeomScan, setNoGeomScan] = useState<{
totalImmovables: number;
withGeometry: number;
remoteGisCount: number;
noGeomCount: number;
localDbTotal: number;
localDbWithGeom: number;
localDbNoGeom: number;
localDbEnriched: number;
localDbEnrichedComplete: number;
localSyncFresh: boolean;
} | null>(null);
const [noGeomScanSiruta, setNoGeomScanSiruta] = useState(""); // siruta for which scan was done
@@ -694,11 +696,13 @@ export function ParcelSyncModule() {
const emptyResult = {
totalImmovables: 0,
withGeometry: 0,
remoteGisCount: 0,
noGeomCount: 0,
localDbTotal: 0,
localDbWithGeom: 0,
localDbNoGeom: 0,
localDbEnriched: 0,
localDbEnrichedComplete: 0,
localSyncFresh: false,
};
try {
@@ -718,11 +722,13 @@ export function ParcelSyncModule() {
setNoGeomScan({
totalImmovables: Number(data.totalImmovables ?? 0),
withGeometry: Number(data.withGeometry ?? 0),
remoteGisCount: Number(data.remoteGisCount ?? 0),
noGeomCount: Number(data.noGeomCount ?? 0),
localDbTotal: Number(data.localDbTotal ?? 0),
localDbWithGeom: Number(data.localDbWithGeom ?? 0),
localDbNoGeom: Number(data.localDbNoGeom ?? 0),
localDbEnriched: Number(data.localDbEnriched ?? 0),
localDbEnrichedComplete: Number(data.localDbEnrichedComplete ?? 0),
localSyncFresh: Boolean(data.localSyncFresh),
});
}
@@ -2400,39 +2406,65 @@ export function ParcelSyncModule() {
);
// Helper: local DB status line
const staleEnrichment =
scanDone &&
noGeomScan.localDbEnriched > 0 &&
noGeomScan.localDbEnrichedComplete < noGeomScan.localDbEnriched;
const staleCount = scanDone
? noGeomScan.localDbEnriched - noGeomScan.localDbEnrichedComplete
: 0;
const localDbLine = scanDone && noGeomScan.localDbTotal > 0 && (
<div className="flex items-center gap-1.5 flex-wrap text-[11px] text-muted-foreground mt-1">
<Database className="h-3 w-3 shrink-0" />
<span>
Baza de date locală:{" "}
<span className="font-medium text-foreground">
{noGeomScan.localDbWithGeom.toLocaleString("ro-RO")}
</span>{" "}
cu geometrie
{noGeomScan.localDbNoGeom > 0 && (
<>
{" + "}
<span className="font-medium text-amber-600 dark:text-amber-400">
{noGeomScan.localDbNoGeom.toLocaleString("ro-RO")}
</span>{" "}
fără geometrie
</>
)}
{noGeomScan.localDbEnriched > 0 && (
<>
{" · "}
<span className="font-medium text-teal-600 dark:text-teal-400">
{noGeomScan.localDbEnriched.toLocaleString("ro-RO")}
</span>{" "}
îmbogățite
</>
)}
{noGeomScan.localSyncFresh && (
<span className="text-emerald-600 dark:text-emerald-400 ml-1">
(proaspăt)
<div className="space-y-0.5 mt-1">
<div className="flex items-center gap-1.5 flex-wrap text-[11px] text-muted-foreground">
<Database className="h-3 w-3 shrink-0" />
<span>
Baza de date locală:{" "}
<span className="font-medium text-foreground">
{noGeomScan.localDbWithGeom.toLocaleString("ro-RO")}
</span>{" "}
cu geometrie
{noGeomScan.localDbNoGeom > 0 && (
<>
{" + "}
<span className="font-medium text-amber-600 dark:text-amber-400">
{noGeomScan.localDbNoGeom.toLocaleString("ro-RO")}
</span>{" "}
fără geometrie
</>
)}
{noGeomScan.localDbEnriched > 0 && (
<>
{" · "}
<span className="font-medium text-teal-600 dark:text-teal-400">
{noGeomScan.localDbEnriched.toLocaleString("ro-RO")}
</span>{" "}
îmbogățite
{staleEnrichment && (
<span className="text-orange-600 dark:text-orange-400">
{" "}
({staleCount.toLocaleString("ro-RO")} incomplete)
</span>
)}
</>
)}
{noGeomScan.localSyncFresh && (
<span className="text-emerald-600 dark:text-emerald-400 ml-1">
(proaspăt)
</span>
)}
</span>
</div>
{staleEnrichment && (
<div className="flex items-center gap-1.5 text-[11px] text-orange-600 dark:text-orange-400 ml-[18px]">
<AlertTriangle className="h-3 w-3 shrink-0" />
<span>
{staleCount.toLocaleString("ro-RO")} parcele au îmbogățire
veche (lipsă PROPRIETARI_VECHI). Vor fi re-îmbogățite la
următorul export Magic.
</span>
)}
</span>
</div>
)}
</div>
);
@@ -2491,8 +2523,11 @@ export function ParcelSyncModule() {
noGeomScan.localDbNoGeom,
)
: 0);
// Use enrichedComplete (not enriched) — stale
// enrichment (missing PROPRIETARI_VECHI etc.)
// will be re-processed
const remaining =
totalToEnrich - noGeomScan.localDbEnriched;
totalToEnrich - noGeomScan.localDbEnrichedComplete;
return remaining > 0
? `~${remaining.toLocaleString("ro-RO")} de procesat (~${Math.ceil((remaining * 0.25) / 60)} min)`
: "deja îmbogățite";
@@ -2535,6 +2570,19 @@ export function ParcelSyncModule() {
</span>{" "}
<span className="font-medium">fără geometrie</span>
</p>
{noGeomScan.remoteGisCount > 0 &&
noGeomScan.remoteGisCount !==
noGeomScan.withGeometry && (
<p className="text-[10px] text-muted-foreground/70 mt-0.5">
Layerul GIS are{" "}
{noGeomScan.remoteGisCount.toLocaleString(
"ro-RO",
)}{" "}
features, dar doar{" "}
{noGeomScan.withGeometry.toLocaleString("ro-RO")}{" "}
se potrivesc cu lista de imobile
</p>
)}
<p className="text-[11px] text-muted-foreground mt-0.5">
Cele fără geometrie există în baza de date eTerra dar
nu au contur desenat în layerul GIS.
@@ -2595,6 +2643,13 @@ export function ParcelSyncModule() {
în DB local
{noGeomScan.localDbEnriched > 0 &&
`, ${noGeomScan.localDbEnriched.toLocaleString("ro-RO")} îmbogățite`}
{noGeomScan.localDbEnriched > 0 &&
noGeomScan.localDbEnrichedComplete <
noGeomScan.localDbEnriched && (
<span className="text-orange-600 dark:text-orange-400">
{` (${(noGeomScan.localDbEnriched - noGeomScan.localDbEnrichedComplete).toLocaleString("ro-RO")} incomplete)`}
</span>
)}
{noGeomScan.localSyncFresh && ", proaspăt"})
</span>
)}