feat: filter no-geom by IE status (hasLandbook), add checkIfIsIE + CF PDF APIs

QUALITY GATE TIGHTENED:
No-geometry import now requires hasLandbook=1 (imobil electronic).
This filters out immovables without carte funciara — they have no
CF data, no owners, no parcel details to extract. For Cosbuc this
reduces useful no-geom from ~1916 to ~468 (only IEs with real data).

Three-tier quality gate:
1. Active (status=1)
2. Has landbook (hasLandbook=1) — is electronic immovable  [NEW]
3. Has identification (cadRef/paperLbNo/paperCadNo) OR area

CLEANUP also updated: DB cleanup now removes stale no-geom records
that don't pass the tightened gate (existing non-IE records will be
cleaned on next import run).

NEW API METHODS (eterra-client):
- checkIfIsIE(adminUnitId, paperCadNo, topNo, paperCfNo) → boolean
  Calls /api/immovable/checkIfIsIE — verifies IE status per-parcel
  Available for future per-item verification if needed
- getCfExtractUrl(immovablePk, workspaceId) → string
  Returns URL for /api/cf/landbook/copycf/get/{pk}/{ws}/0/true
  Downloads the CF extract as PDF blob (future enrichment)

UI updated: 'Filtrate' label now says 'fara CF/inactive/fara date'
to reflect the new hasLandbook filter.
This commit is contained in:
AI Assistant
2026-03-08 00:57:16 +02:00
parent f09eaaad7c
commit aee28b6768
3 changed files with 65 additions and 10 deletions
@@ -508,6 +508,53 @@ export class EterraClient {
return this.getRawJson(url);
}
/**
* Check if an immovable is an "Imobil Electronic" (IE) in eTerra.
* Uses the same endpoint the eTerra UI calls when searching by
* topNo + paperCfNo.
*
* @returns true if the immovable is registered as IE, false otherwise
*/
async checkIfIsIE(
adminUnitId: string | number,
paperCadNo: number | null,
topNo: string | number,
paperCfNo: string | number,
): Promise<boolean> {
const url = `${BASE_URL}/api/immovable/checkIfIsIE`;
const payload = {
adminUnitId: Number(adminUnitId),
paperCadNo: Number(paperCadNo ?? 0),
topNo: typeof topNo === "string" ? Number(topNo.split(",")[0]) || 0 : Number(topNo),
paperCfNo: Number(paperCfNo),
};
try {
const result = await this.requestRaw<boolean | number | string>(() =>
this.client.post(url, payload, {
headers: { "Content-Type": "application/json;charset=UTF-8" },
timeout: this.timeoutMs,
}),
);
// API may return boolean, number (1/0), or string
return result === true || result === 1 || String(result) === "true";
} catch {
return false;
}
}
/**
* Build the URL for downloading a CF (carte funciară) extract PDF.
* The eTerra UI calls this to get the landbook/CF PDF blob.
*
* @returns URL string (caller needs an authenticated session to fetch)
*/
getCfExtractUrl(
immovablePk: string | number,
workspaceId: string | number,
): string {
return `${BASE_URL}/api/cf/landbook/copycf/get/${immovablePk}/${workspaceId}/0/true`;
}
/**
* Search immovable list by exact cadastral number (identifierDetails).
* This is the eTerra application API that the web UI uses when you type