Initial commit: Real Estate Registry app
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
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,
|
||||
}
|
||||
Reference in New Issue
Block a user