fix(search): use legalArea/measuredArea + nodeStatus=-1 for radiated owners

- Area: use measuredArea/legalArea from immovable list and documentation
  (actual fields from eTerra API, not area/areaValue which don't exist)
- Owners: detect radiated via nodeStatus === -1 on ancestor I (inscription)
  nodes. Walk up parentId tree from P (person)  I  A  C.
  nodeStatus: -1=radiated, 0=active, 2=pending
- Remove debug logging (data structure now understood)
This commit is contained in:
AI Assistant
2026-03-06 22:16:14 +02:00
parent 79c45adc37
commit 4aa8e6c324
+46 -59
View File
@@ -111,19 +111,19 @@ function formatAddress(item?: any) {
const streetName = const streetName =
typeof address.street === "string" typeof address.street === "string"
? address.street ? address.street
: address.street?.name ?? ""; : (address.street?.name ?? "");
if (streetName) parts.push(`Str. ${streetName}`); if (streetName) parts.push(`Str. ${streetName}`);
if (address.buildingNo) parts.push(`Nr. ${address.buildingNo}`); if (address.buildingNo) parts.push(`Nr. ${address.buildingNo}`);
// locality can also be a string or object // locality can also be a string or object
const localityName = const localityName =
typeof address.locality === "string" typeof address.locality === "string"
? address.locality ? address.locality
: address.locality?.name ?? ""; : (address.locality?.name ?? "");
if (localityName) parts.push(localityName); if (localityName) parts.push(localityName);
const countyName = const countyName =
typeof address.county === "string" typeof address.county === "string"
? address.county ? address.county
: address.county?.name ?? ""; : (address.county?.name ?? "");
if (countyName) parts.push(`Jud. ${countyName}`); if (countyName) parts.push(`Jud. ${countyName}`);
return parts.length ? parts.join(", ") : ""; return parts.length ? parts.join(", ") : "";
} }
@@ -310,24 +310,20 @@ export async function POST(req: Request) {
let categorie = ""; let categorie = "";
let suprafata: number | null = null; let suprafata: number | null = null;
// Try multiple area fields // Area: use measuredArea first, then legalArea as fallback
const areaStr = for (const areaField of [
item?.area ?? item?.areaValue ?? item?.areaMP ?? item?.suprafata; item?.measuredArea,
if (areaStr != null) { item?.legalArea,
const parsed = Number(areaStr); item?.area,
if (Number.isFinite(parsed) && parsed > 0) suprafata = parsed; item?.areaValue,
} ]) {
// Log raw item keys once for debugging (first item only) if (areaField != null) {
if (results.length === 0) { const parsed = Number(areaField);
console.log( if (Number.isFinite(parsed) && parsed > 0) {
"[search] immovable item keys:", suprafata = parsed;
Object.keys(item ?? {}), break;
); }
console.log("[search] area fields:", { }
area: item?.area,
areaValue: item?.areaValue,
areaMP: item?.areaMP,
});
} }
// 2. Fetch documentation data (CF, proprietari) // 2. Fetch documentation data (CF, proprietari)
@@ -350,60 +346,50 @@ export async function POST(req: Request) {
if (oldCF && oldCF !== nrCF) nrCFVechi = oldCF; if (oldCF && oldCF !== nrCF) nrCFVechi = oldCF;
} }
if (docImm.topNo) nrTopo = String(docImm.topNo); if (docImm.topNo) nrTopo = String(docImm.topNo);
if (docImm.area != null) { // Try measuredArea/legalArea from doc too
const docArea = Number(docImm.area); for (const af of [
if (Number.isFinite(docArea)) suprafata = docArea; docImm.measuredArea,
docImm.legalArea,
docImm.area,
]) {
if (af != null) {
const docArea = Number(af);
if (Number.isFinite(docArea) && docArea > 0) {
suprafata = docArea;
break;
}
}
} }
} }
// Extract owners from partTwoRegs — separate active vs cancelled // Extract owners from partTwoRegs — separate active vs cancelled
// using tree structure: "P" (person) nodes are children of // Tree: C (cerere) → A (act) → I (inscription) → P (person)
// inscription nodes. If a parent inscription has radiationDate, // nodeStatus === -1 on an "I" node means it's radiated.
// its person entries are former owners. // Walk up from each "P" to its parent "I", check nodeStatus.
const activeOwners: string[] = []; const activeOwners: string[] = [];
const cancelledOwners: string[] = []; const cancelledOwners: string[] = [];
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
const regs: any[] = docResponse?.partTwoRegs ?? []; const regs: any[] = docResponse?.partTwoRegs ?? [];
if (regs.length > 0 && results.length === 0) {
console.log(
"[search] partTwoRegs count:",
regs.length,
"types:",
[...new Set(regs.map((r: any) => r?.nodeType))],
);
// Log first 3 entries fully
regs.slice(0, 3).forEach((r: any, i: number) =>
console.log(`[search] partTwoRegs[${i}]:`, JSON.stringify(r).slice(0, 600)),
);
// Log last 3 entries
regs.slice(-3).forEach((r: any, i: number) =>
console.log(`[search] partTwoRegs[${regs.length - 3 + i}]:`, JSON.stringify(r).slice(0, 600)),
);
}
// Build nodeId → entry map for tree traversal // Build nodeId → entry map for tree traversal
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
const nodeMap = new Map<string | number, any>(); const nodeMap = new Map<number, any>();
for (const reg of regs) { for (const reg of regs) {
const nid = reg?.nodeId ?? reg?.id; if (reg?.nodeId != null) nodeMap.set(Number(reg.nodeId), reg);
if (nid != null) nodeMap.set(nid, reg);
} }
// Check if an entry or any ancestor is radiated // Check if an entry or any ancestor "I" inscription is radiated
// nodeStatus: -1 = radiated, 0 = active, 2 = pending
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
const isRadiated = (entry: any): boolean => { const isRadiated = (entry: any, depth = 0): boolean => {
// Direct checks on the entry itself if (!entry || depth > 10) return false;
if (entry?.radiationDate != null) return true; // nodeStatus === -1 means radiated/cancelled
if (entry?.cancelled === true) return true; if (entry?.nodeStatus === -1) return true;
if (entry?.isActive === false) return true;
if (entry?.closed === true) return true;
const st = String(entry?.status ?? "").toUpperCase();
if (st === "RADIAT" || st === "CANCELLED" || st === "CLOSED") return true;
// Walk up to parent // Walk up to parent
const pid = entry?.parentNodeId ?? entry?.parentId; const pid = entry?.parentId;
if (pid != null) { if (pid != null) {
const parent = nodeMap.get(pid); const parent = nodeMap.get(Number(pid));
if (parent) return isRadiated(parent); if (parent) return isRadiated(parent, depth + 1);
} }
return false; return false;
}; };
@@ -412,7 +398,8 @@ export async function POST(req: Request) {
if ( if (
String(reg?.nodeType ?? "").toUpperCase() !== "P" || String(reg?.nodeType ?? "").toUpperCase() !== "P" ||
!reg?.nodeName !reg?.nodeName
) continue; )
continue;
const name = String(reg.nodeName).trim(); const name = String(reg.nodeName).trim();
if (!name) continue; if (!name) continue;
if (isRadiated(reg)) { if (isRadiated(reg)) {