diff --git a/src/modules/parcel-sync/services/enrich-service.ts b/src/modules/parcel-sync/services/enrich-service.ts index 5601811..f46dee8 100644 --- a/src/modules/parcel-sync/services/enrich-service.ts +++ b/src/modules/parcel-sync/services/enrich-service.ts @@ -80,13 +80,18 @@ const normalizeIntravilan = (values: string[]) => { const formatCategories = (entries: any[]) => { const map = new Map(); for (const entry of entries) { - const key = String(entry?.categorieFolosinta ?? "").trim(); + // Support both API formats: + // fetchParcelFolosinte (via app): categorieFolosinta + suprafata + // fetchImmovableParcelDetails (direct): useCategory (no area) + const key = String( + entry?.categorieFolosinta ?? entry?.useCategory ?? "", + ).trim(); if (!key) continue; const area = Number(entry?.suprafata ?? 0); map.set(key, (map.get(key) ?? 0) + (Number.isFinite(area) ? area : 0)); } return Array.from(map.entries()) - .map(([k, a]) => `${k}:${formatNumber(a)}`) + .map(([k, a]) => (a > 0 ? `${k}:${formatNumber(a)}` : k)) .join("; "); }; @@ -482,6 +487,40 @@ export async function enrichFeatures( ); categorie = formatCategories(fol); } + + // Fallback: if no application or empty categories, use direct + // parcel details endpoint (doesn't need applicationId). + // Discovered via eTerra UI: /api/immovable/details/parcels/list/{wp}/{pk}/{page}/{size} + // Returns: [{useCategory: "arabil", intravilan: "Necunoscut", ...}] + if (categorie === "-" && immovableId) { + const immPkForDetails = + immovableListById.get(normalizeId(immovableId))?.immovablePk ?? + immovableId; + const detKey = `${workspaceId}:${immPkForDetails}:details`; + let details = folCache.get(detKey); + if (!details) { + try { + details = await throttled(() => + client.fetchImmovableParcelDetails( + workspaceId as string | number, + immPkForDetails as string | number, + ), + ); + } catch { + details = []; + } + folCache.set(detKey, details); + } + if (details && details.length > 0) { + const detIntravilan = normalizeIntravilan( + details.map((d: any) => d?.intravilan ?? ""), + ); + const detCategorie = formatCategories(details); + if (detCategorie && detCategorie !== "-") categorie = detCategorie; + if (detIntravilan && detIntravilan !== "-" && intravilan === "-") + intravilan = detIntravilan; + } + } } const cadRefRaw = (attrs.NATIONAL_CADASTRAL_REFERENCE ?? "") as string; diff --git a/src/modules/parcel-sync/services/eterra-client.ts b/src/modules/parcel-sync/services/eterra-client.ts index 2e63682..abd4076 100644 --- a/src/modules/parcel-sync/services/eterra-client.ts +++ b/src/modules/parcel-sync/services/eterra-client.ts @@ -362,9 +362,7 @@ export class EterraClient { await sleep(500); // small delay before retry with smaller page continue; } - throw new Error( - `Failed to fetch layer ${layer.name}: ${cause}`, - ); + throw new Error(`Failed to fetch layer ${layer.name}: ${cause}`); } const features = data.features ?? []; @@ -504,7 +502,7 @@ export class EterraClient { workspaceId: string | number, immovableId: string | number, page = 1, - size = 1, + size = 20, ): Promise { const url = `${BASE_URL}/api/immovable/details/parcels/list/${workspaceId}/${immovableId}/${page}/${size}`; return this.getRawJson(url);