fix(contacts): stabilize contacts pagination and company enrichment

This commit is contained in:
Christian 2026-05-16 10:28:05 +02:00
parent aa87285cab
commit 0ed450451d
2 changed files with 56 additions and 14 deletions

19
RELEASE_NOTES_v2.3.1.md Normal file
View File

@ -0,0 +1,19 @@
# v2.3.1 — 16. maj 2026
## Fix: contacts pagination and company enrichment
- **Hotfix:** Contacts showing too few rows (contacts pagination bug)
- **Fix:** File `app/contacts/backend/router_simple.py` to stabilize pagination and company enrichment
## Contacts list
- Fixed bug where contacts list showed too few rows (pagination issue)
- Stabilized company enrichment data for contacts
## File changed
- `app/contacts/backend/router_simple.py`
## Affected versions
- v2.3.1

View File

@ -120,31 +120,54 @@ async def get_contacts(
where_clauses.append("c.is_active = %s") where_clauses.append("c.is_active = %s")
params.append(is_active) params.append(is_active)
if customer_id is not None:
where_clauses.append(
"EXISTS (SELECT 1 FROM contact_companies cc WHERE cc.contact_id = c.id AND cc.customer_id = %s)"
)
params.append(customer_id)
where_sql = "WHERE " + " AND ".join(where_clauses) if where_clauses else "" where_sql = "WHERE " + " AND ".join(where_clauses) if where_clauses else ""
# Count total (needs alias c for consistency) # Count total (distinct id for consistency with optional filters/joins)
count_query = f"SELECT COUNT(*) as count FROM contacts c {where_sql}" count_query = f"SELECT COUNT(DISTINCT c.id) as count FROM contacts c {where_sql}"
count_result = execute_query(count_query, tuple(params)) count_result = execute_query(count_query, tuple(params))
total = count_result[0]['count'] if count_result else 0 total = count_result[0]['count'] if count_result else 0
# Get contacts with company info # Step 1: Fetch contacts only (stable pagination)
query = f""" contacts_query = f"""
SELECT SELECT
c.id, c.first_name, c.last_name, c.email, c.phone, c.mobile, c.id, c.first_name, c.last_name, c.email, c.phone, c.mobile,
c.title, c.department, c.user_company, c.is_active, c.created_at, c.updated_at,
COUNT(DISTINCT cc.customer_id) as company_count,
ARRAY_AGG(DISTINCT cu.name ORDER BY cu.name) FILTER (WHERE cu.name IS NOT NULL) as company_names
FROM contacts c
LEFT JOIN contact_companies cc ON c.id = cc.contact_id
LEFT JOIN customers cu ON cc.customer_id = cu.id
{where_sql}
GROUP BY c.id, c.first_name, c.last_name, c.email, c.phone, c.mobile,
c.title, c.department, c.user_company, c.is_active, c.created_at, c.updated_at c.title, c.department, c.user_company, c.is_active, c.created_at, c.updated_at
ORDER BY company_count DESC, c.last_name, c.first_name, c.id FROM contacts c
{where_sql}
ORDER BY c.last_name, c.first_name, c.id
LIMIT %s OFFSET %s LIMIT %s OFFSET %s
""" """
params.extend([limit, offset]) contacts_params = list(params)
contacts = execute_query(query, tuple(params)) contacts_params.extend([limit, offset])
contacts = execute_query(contacts_query, tuple(contacts_params)) or []
# Step 2: Enrich page contacts with aggregated company info
if contacts:
contact_ids = [row["id"] for row in contacts]
placeholders = ",".join(["%s"] * len(contact_ids))
companies_query = f"""
SELECT
cc.contact_id,
COUNT(DISTINCT cc.customer_id) AS company_count,
ARRAY_AGG(DISTINCT cu.name ORDER BY cu.name) FILTER (WHERE cu.name IS NOT NULL) AS company_names
FROM contact_companies cc
LEFT JOIN customers cu ON cc.customer_id = cu.id
WHERE cc.contact_id IN ({placeholders})
GROUP BY cc.contact_id
"""
company_rows = execute_query(companies_query, tuple(contact_ids)) or []
company_map = {row["contact_id"]: row for row in company_rows}
for contact in contacts:
info = company_map.get(contact["id"])
contact["company_count"] = int(info["company_count"]) if info and info.get("company_count") is not None else 0
contact["company_names"] = info.get("company_names") if info and info.get("company_names") else []
return { return {
"total": total, "total": total,