diff --git a/src/modules/parcel-sync/services/enrich-service.ts b/src/modules/parcel-sync/services/enrich-service.ts index fa6afd2..781a0be 100644 --- a/src/modules/parcel-sync/services/enrich-service.ts +++ b/src/modules/parcel-sync/services/enrich-service.ts @@ -226,9 +226,14 @@ export async function enrichFeatures( /* ignore */ } } - // If still null, enrichment will fail gracefully with empty lists const workspacePkForApi = resolvedWsPk ?? 65; - console.log(`[enrich] siruta=${siruta} workspacePk=${workspacePkForApi}`); + if (!resolvedWsPk) { + console.warn( + `[enrich] siruta=${siruta}: workspace nu s-a rezolvat, folosesc fallback PK=${workspacePkForApi}`, + ); + } else { + console.log(`[enrich] siruta=${siruta} workspacePk=${workspacePkForApi}`); + } push({ phase: "Pregătire îmbogățire", @@ -334,6 +339,18 @@ export async function enrichFeatures( listPage += 1; } + if (immovableListById.size === 0) { + console.warn( + `[enrich] siruta=${siruta}: lista de imobile e GOALĂ (workspace=${workspacePkForApi}). ` + + `Enrichment va continua dar toate parcelele vor avea date goale. ` + + `Verifică workspace-ul corect pentru acest UAT.`, + ); + } else { + console.log( + `[enrich] siruta=${siruta}: ${immovableListById.size} imobile găsite`, + ); + } + // ── Fetch documentation/owner data ── push({ phase: "Descărcare documentații CF" }); const docByImmovable = new Map(); @@ -392,22 +409,41 @@ export async function enrichFeatures( const attrs = feature.attributes as Record; // Skip features with complete enrichment (resume after crash/interruption). - // Re-enrich if enrichment schema is incomplete (e.g., missing PROPRIETARI_VECHI - // added in a later version). + // Re-enrich if: schema incomplete, values are all "-" (empty), or older than 30 days. if (feature.enrichedAt != null) { const enrichJson = feature.enrichment as Record | null; - const isComplete = + // Structural check: all 7 core fields must exist + const coreFields = [ + "NR_CAD", + "NR_CF", + "PROPRIETARI", + "PROPRIETARI_VECHI", + "ADRESA", + "CATEGORIE_FOLOSINTA", + "HAS_BUILDING", + ]; + const structurallyComplete = enrichJson != null && - [ - "NR_CAD", - "NR_CF", - "PROPRIETARI", - "PROPRIETARI_VECHI", - "ADRESA", - "CATEGORIE_FOLOSINTA", - "HAS_BUILDING", - ].every((k) => k in enrichJson && enrichJson[k] !== undefined); - if (isComplete) { + coreFields.every((k) => k in enrichJson && enrichJson[k] !== undefined); + + // Value check: at least some fields must have real data (not just "-") + // A feature with ALL text fields === "-" is considered empty and needs re-enrichment + const valueFields = ["NR_CF", "PROPRIETARI", "ADRESA", "CATEGORIE_FOLOSINTA"]; + const hasRealValues = + enrichJson != null && + valueFields.some( + (k) => + k in enrichJson && + enrichJson[k] !== undefined && + enrichJson[k] !== "-" && + enrichJson[k] !== "", + ); + + // Age check: re-enrich if older than 30 days (catches eTerra updates) + const ageMs = Date.now() - new Date(feature.enrichedAt).getTime(); + const isTooOld = ageMs > 30 * 24 * 60 * 60 * 1000; + + if (structurallyComplete && hasRealValues && !isTooOld) { enrichedCount += 1; if (index % 50 === 0) { options?.onProgress?.( @@ -418,9 +454,12 @@ export async function enrichFeatures( } continue; } - // Stale enrichment — will be re-enriched below + // Incomplete, empty, or stale — will be re-enriched below } + // Per-feature try-catch: one feature failing should not abort the whole UAT + try { + const immovableId = attrs.IMMOVABLE_ID ?? ""; const workspaceId = attrs.WORKSPACE_ID ?? ""; const applicationId = (attrs.APPLICATION_ID as number) ?? null; @@ -474,13 +513,17 @@ export async function enrichFeatures( const folKey = `${workspaceId}:${immovableId}:${appId}`; let fol = folCache.get(folKey); if (!fol) { - fol = await throttled(() => - client.fetchParcelFolosinte( - workspaceId as string | number, - immovableId as string | number, - appId, - ), - ); + try { + fol = await throttled(() => + client.fetchParcelFolosinte( + workspaceId as string | number, + immovableId as string | number, + appId, + ), + ); + } catch { + fol = []; + } folCache.set(folKey, fol); } if (fol && fol.length > 0) { @@ -603,6 +646,16 @@ export async function enrichFeatures( }); enrichedCount += 1; + + } catch (featureErr) { + // Log and continue — don't abort the whole UAT + const cadRef = (attrs.NATIONAL_CADASTRAL_REFERENCE ?? "?") as string; + const msg = featureErr instanceof Error ? featureErr.message : String(featureErr); + console.warn( + `[enrich] Feature ${index + 1}/${terenuri.length} (cad=${cadRef}) failed: ${msg}`, + ); + } + if (index % 10 === 0) { push({ phase: "Îmbogățire parcele",