Files
gexp/services/search_service.py
T

153 lines
4.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from database.connection import get_db
def normalize_arabic(text: str) -> str:
"""Normalize Arabic text for search: collapse alef variants, ta marbuta, alef maqsura."""
if not text:
return text
for ch in "أإآ":
text = text.replace(ch, "ا")
text = text.replace("ة", "ه")
text = text.replace("ى", "ي")
return text
def search_persons(query: str) -> list[dict]:
"""Search persons by name (first, family, or father name)."""
norm = normalize_arabic(query.strip())
pattern = f"%{norm}%"
raw_pattern = f"%{query.strip()}%"
with get_db() as conn:
rows = conn.execute(
"""
SELECT p.*,
COUNT(DISTINCT pr.id) AS property_count,
COUNT(DISTINCT d.id) AS document_count,
GROUP_CONCAT(DISTINCT d.search_scope) AS search_scopes
FROM persons p
LEFT JOIN properties pr ON pr.person_id = p.id
LEFT JOIN documents d ON d.person_id = p.id
WHERE p.first_name_norm LIKE ?
OR p.family_name_norm LIKE ?
OR p.father_name LIKE ?
OR p.first_name LIKE ?
OR p.family_name LIKE ?
GROUP BY p.id
ORDER BY
CASE WHEN p.first_name_norm = ? THEN 0
WHEN p.family_name_norm = ? THEN 0
ELSE 1 END,
p.first_name
""",
(pattern, pattern, raw_pattern, raw_pattern, raw_pattern, norm, norm),
).fetchall()
return [dict(r) for r in rows]
def search_properties(
property_number: str = "",
district: str = "",
block: str = "",
) -> list[dict]:
"""Search properties by number, district, or block."""
conditions = []
params = []
if property_number:
conditions.append("pr.property_number LIKE ?")
params.append(f"{property_number}%")
if district:
conditions.append("pr.real_estate_district LIKE ?")
params.append(f"%{district}%")
if block:
conditions.append("pr.block LIKE ?")
params.append(f"%{block}%")
if not conditions:
return []
where = " AND ".join(conditions)
with get_db() as conn:
rows = conn.execute(
f"""
SELECT pr.*,
p.first_name, p.father_name, p.family_name, p.family_origin,
d.search_scope
FROM properties pr
LEFT JOIN persons p ON p.id = pr.person_id
LEFT JOIN documents d ON d.id = pr.document_id
WHERE {where}
ORDER BY pr.real_estate_district, pr.property_number
""",
params,
).fetchall()
results = []
for r in rows:
row_dict = dict(r)
if not row_dict.get("qaza") and row_dict.get("search_scope"):
row_dict["qaza"] = row_dict["search_scope"]
results.append(row_dict)
return results
def get_person_with_properties(person_id: int) -> dict | None:
"""Fetch a person and all their properties."""
with get_db() as conn:
person = conn.execute(
"SELECT * FROM persons WHERE id = ?", (person_id,)
).fetchone()
if not person:
return None
props = conn.execute(
"""
SELECT pr.*, d.image_path, d.id AS document_id, d.search_scope
FROM properties pr
LEFT JOIN documents d ON d.id = pr.document_id
WHERE pr.person_id = ?
ORDER BY pr.real_estate_district, pr.row_order
""",
(person_id,),
).fetchall()
docs = conn.execute(
"SELECT id, image_path, request_number, request_date, status, page_info, search_scope FROM documents WHERE person_id = ?",
(person_id,),
).fetchall()
properties_list = []
doc_ids_with_props = set()
for p in props:
p_dict = dict(p)
if not p_dict.get("qaza") and p_dict.get("search_scope"):
p_dict["qaza"] = p_dict["search_scope"]
properties_list.append(p_dict)
doc_ids_with_props.add(p_dict.get("document_id"))
# Add a "no properties" dummy row for documents that yielded no properties
# so the search request is still recorded in the properties table
docs_list = [dict(d) for d in docs]
for d in docs_list:
if d["id"] not in doc_ids_with_props:
properties_list.append({
"document_id": d["id"],
"party_name": "-",
"property_number": "-",
"section": "-",
"block": "-",
"real_estate_district": "-",
"qaza": d.get("search_scope") or "غير محدد",
"num_shares": "-",
"ownership_type": "لا يملك"
})
return {
"person": dict(person),
"properties": properties_list,
"documents": docs_list,
}