fix(search): address [object Object], suprafata from folosinte, owner tree separation

- Address: handle street/locality/county as objects (extract .name)
  Fixes 'Str. [object Object], Feleacu'  'Str. X, Feleacu'
- Suprafata: fallback to total area from folosinte endpoint when
  immovable list and documentation APIs return null
- Owners: use tree traversal (nodeId/parentNodeId) to detect radiated
  inscriptions. Walk up parent chain to check radiationDate/cancelled/
  isActive/closed/status on ancestor inscription nodes.
- Enhanced logging: first/last 3 partTwoRegs entries + node types
  for debugging owner structure in Dozzle
This commit is contained in:
AI Assistant
2026-03-06 22:06:28 +02:00
parent 6eae4fa1c5
commit 79c45adc37
2 changed files with 113 additions and 44 deletions
+100 -35
View File
@@ -105,13 +105,26 @@ function formatAddress(item?: any) {
// addressDescription may contain the full text address already // addressDescription may contain the full text address already
if (address.addressDescription) { if (address.addressDescription) {
const desc = String(address.addressDescription).trim(); const desc = String(address.addressDescription).trim();
// If it looks like a complete address (has comma or street), use it directly if (desc.length > 3 && !desc.includes("[object")) return desc;
if (desc.length > 3) return desc;
} }
if (address.street) parts.push(`Str. ${address.street}`); // street can be a string OR an object { name: "..." }
const streetName =
typeof address.street === "string"
? address.street
: address.street?.name ?? "";
if (streetName) parts.push(`Str. ${streetName}`);
if (address.buildingNo) parts.push(`Nr. ${address.buildingNo}`); if (address.buildingNo) parts.push(`Nr. ${address.buildingNo}`);
if (address.locality?.name) parts.push(address.locality.name); // locality can also be a string or object
if (address.county?.name) parts.push(`Jud. ${address.county.name}`); const localityName =
typeof address.locality === "string"
? address.locality
: address.locality?.name ?? "";
if (localityName) parts.push(localityName);
const countyName =
typeof address.county === "string"
? address.county
: address.county?.name ?? "";
if (countyName) parts.push(`Jud. ${countyName}`);
return parts.length ? parts.join(", ") : ""; return parts.length ? parts.join(", ") : "";
} }
@@ -298,15 +311,23 @@ export async function POST(req: Request) {
let suprafata: number | null = null; let suprafata: number | null = null;
// Try multiple area fields // Try multiple area fields
const areaStr = item?.area ?? item?.areaValue ?? item?.areaMP ?? item?.suprafata; const areaStr =
item?.area ?? item?.areaValue ?? item?.areaMP ?? item?.suprafata;
if (areaStr != null) { if (areaStr != null) {
const parsed = Number(areaStr); const parsed = Number(areaStr);
if (Number.isFinite(parsed) && parsed > 0) suprafata = parsed; if (Number.isFinite(parsed) && parsed > 0) suprafata = parsed;
} }
// Log raw item keys once for debugging (first item only) // Log raw item keys once for debugging (first item only)
if (results.length === 0) { if (results.length === 0) {
console.log("[search] immovable item keys:", Object.keys(item ?? {})); console.log(
console.log("[search] area fields:", { area: item?.area, areaValue: item?.areaValue, areaMP: item?.areaMP }); "[search] immovable item keys:",
Object.keys(item ?? {}),
);
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)
@@ -336,40 +357,74 @@ export async function POST(req: Request) {
} }
// 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
// inscription nodes. If a parent inscription has radiationDate,
// its person entries are former owners.
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 = docResponse?.partTwoRegs ?? []; const regs: any[] = docResponse?.partTwoRegs ?? [];
if (regs.length > 0) { if (regs.length > 0 && results.length === 0) {
console.log("[search] partTwoRegs[0] keys:", Object.keys(regs[0])); console.log(
console.log("[search] partTwoRegs sample:", JSON.stringify(regs[0]).slice(0, 500)); "[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
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
regs.forEach((reg: any) => { const nodeMap = new Map<string | number, any>();
if ( for (const reg of regs) {
String(reg?.nodeType ?? "").toUpperCase() === "P" && const nid = reg?.nodeId ?? reg?.id;
reg?.nodeName if (nid != null) nodeMap.set(nid, reg);
) { }
const name = String(reg.nodeName).trim();
if (!name) return; // Check if an entry or any ancestor is radiated
// Check if this entry is cancelled/radiated // eslint-disable-next-line @typescript-eslint/no-explicit-any
const isCancelled = const isRadiated = (entry: any): boolean => {
reg?.cancelled === true || // Direct checks on the entry itself
reg?.isActive === false || if (entry?.radiationDate != null) return true;
reg?.radiat === true || if (entry?.cancelled === true) return true;
String(reg?.status ?? "").toUpperCase() === "RADIAT" || if (entry?.isActive === false) return true;
String(reg?.status ?? "").toUpperCase() === "CANCELLED" || if (entry?.closed === true) return true;
reg?.radiationDate != null; const st = String(entry?.status ?? "").toUpperCase();
if (isCancelled) { if (st === "RADIAT" || st === "CANCELLED" || st === "CLOSED") return true;
cancelledOwners.push(name); // Walk up to parent
} else { const pid = entry?.parentNodeId ?? entry?.parentId;
activeOwners.push(name); if (pid != null) {
} const parent = nodeMap.get(pid);
if (parent) return isRadiated(parent);
} }
}); return false;
};
for (const reg of regs) {
if (
String(reg?.nodeType ?? "").toUpperCase() !== "P" ||
!reg?.nodeName
) continue;
const name = String(reg.nodeName).trim();
if (!name) continue;
if (isRadiated(reg)) {
cancelledOwners.push(name);
} else {
activeOwners.push(name);
}
}
proprietariActuali = Array.from(new Set(activeOwners)); proprietariActuali = Array.from(new Set(activeOwners));
proprietariVechi = Array.from(new Set(cancelledOwners)) proprietariVechi = Array.from(new Set(cancelledOwners)).filter(
.filter((n) => !proprietariActuali.includes(n)); (n) => !proprietariActuali.includes(n),
);
} catch { } catch {
// Documentation fetch failed — continue with basic data // Documentation fetch failed — continue with basic data
} }
@@ -408,6 +463,16 @@ export async function POST(req: Request) {
(fol ?? []).map((f: any) => f?.intravilan ?? ""), (fol ?? []).map((f: any) => f?.intravilan ?? ""),
); );
categorie = formatCategories(fol ?? []); categorie = formatCategories(fol ?? []);
// Extract total area from folosinte as fallback
if (suprafata == null || suprafata <= 0) {
let totalArea = 0;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
for (const f of (fol ?? []) as any[]) {
const a = Number(f?.suprafata ?? 0);
if (Number.isFinite(a)) totalArea += a;
}
if (totalArea > 0) suprafata = totalArea;
}
} catch { } catch {
// folosinta fetch failed // folosinta fetch failed
} }
@@ -1034,7 +1034,9 @@ export function ParcelSyncModule() {
p.proprietariVechi p.proprietariVechi
? `Proprietari vechi: ${p.proprietariVechi}` ? `Proprietari vechi: ${p.proprietariVechi}`
: null, : null,
!p.proprietariActuali && !p.proprietariVechi && p.proprietari !p.proprietariActuali &&
!p.proprietariVechi &&
p.proprietari
? `Proprietari: ${p.proprietari}` ? `Proprietari: ${p.proprietari}`
: null, : null,
p.solicitant p.solicitant
@@ -1142,14 +1144,16 @@ export function ParcelSyncModule() {
</span> </span>
</div> </div>
)} )}
{!p.proprietariActuali && !p.proprietariVechi && p.proprietari && ( {!p.proprietariActuali &&
<div> !p.proprietariVechi &&
<span className="text-xs text-muted-foreground block"> p.proprietari && (
Proprietari <div>
</span> <span className="text-xs text-muted-foreground block">
<span>{p.proprietari}</span> Proprietari
</div> </span>
)} <span>{p.proprietari}</span>
</div>
)}
</div> </div>
)} )}
{p.solicitant && ( {p.solicitant && (