121 lines
4.0 KiB
Python
121 lines
4.0 KiB
Python
from __future__ import annotations
|
|
|
|
from sqlalchemy import select
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.modules.core.iam.models import User
|
|
from app.modules.core.iam.profile_service import profile_photo_url
|
|
from app.modules.core.tenancy.models import Branch, Tenant
|
|
|
|
|
|
def _initials(name: str | None, email: str | None = None) -> str:
|
|
source = (name or email or "Auditor").strip()
|
|
parts = [p for p in source.replace("@", " ").replace(".", " ").split() if p]
|
|
if not parts:
|
|
return "AU"
|
|
if len(parts) == 1:
|
|
return parts[0][:2].upper()
|
|
return (parts[0][:1] + parts[-1][:1]).upper()
|
|
|
|
|
|
def _contact_card_from_user(
|
|
*,
|
|
user: User | None,
|
|
tenant_name: str | None,
|
|
branch_name: str | None,
|
|
source_label: str,
|
|
) -> dict:
|
|
if not user:
|
|
return {
|
|
"available": False,
|
|
"name": "Firm team",
|
|
"designation": "Audit support team",
|
|
"qualification": None,
|
|
"email": None,
|
|
"mobile": None,
|
|
"photo_url": None,
|
|
"initials": "FT",
|
|
"firm_name": tenant_name,
|
|
"branch_name": branch_name,
|
|
"source_label": source_label,
|
|
}
|
|
|
|
name = getattr(user, "full_name", None) or getattr(user, "email", None) or "Firm team"
|
|
designation = getattr(user, "designation", None) or source_label or "Auditor"
|
|
return {
|
|
"available": True,
|
|
"name": name,
|
|
"designation": designation,
|
|
"qualification": getattr(user, "qualification", None),
|
|
"email": getattr(user, "email", None),
|
|
"mobile": getattr(user, "mobile", None),
|
|
"photo_url": profile_photo_url(user),
|
|
"initials": _initials(name, getattr(user, "email", None)),
|
|
"firm_name": tenant_name,
|
|
"branch_name": branch_name,
|
|
"source_label": source_label,
|
|
}
|
|
|
|
|
|
def build_client_auditor_card(db: Session, client_row: dict | None) -> dict:
|
|
"""Return a client-facing contact card for the assigned auditor/partner.
|
|
|
|
Priority:
|
|
1. Client assigned partner (`partner_id`).
|
|
2. Default review partner, if no assigned partner exists.
|
|
3. Firm team fallback using tenant/branch names.
|
|
|
|
This reuses Phase 7Q.3 user profile fields and does not create new tables.
|
|
"""
|
|
if not client_row:
|
|
return _contact_card_from_user(
|
|
user=None,
|
|
tenant_name=None,
|
|
branch_name=None,
|
|
source_label="Firm team",
|
|
)
|
|
|
|
tenant_name = client_row.get("tenant_name")
|
|
branch_name = client_row.get("branch_name")
|
|
tenant_id = client_row.get("tenant_id")
|
|
branch_id = client_row.get("branch_id")
|
|
|
|
partner_id = client_row.get("partner_id") or client_row.get("assoc_partner_user_id")
|
|
review_partner_id = client_row.get("default_review_partner_user_id")
|
|
|
|
target_user_id = partner_id or review_partner_id
|
|
source_label = "Assigned Auditor" if partner_id else "Review Partner"
|
|
|
|
if not target_user_id:
|
|
return _contact_card_from_user(
|
|
user=None,
|
|
tenant_name=tenant_name,
|
|
branch_name=branch_name,
|
|
source_label="Firm team",
|
|
)
|
|
|
|
stmt = (
|
|
select(User, Tenant.name.label("tenant_name"), Branch.name.label("branch_name"))
|
|
.join(Tenant, Tenant.id == User.tenant_id, isouter=True)
|
|
.join(Branch, Branch.id == User.branch_id, isouter=True)
|
|
.where(User.id == int(target_user_id), User.deleted_at.is_(None))
|
|
)
|
|
if tenant_id:
|
|
stmt = stmt.where(User.tenant_id == int(tenant_id))
|
|
result = db.execute(stmt).first()
|
|
if not result:
|
|
return _contact_card_from_user(
|
|
user=None,
|
|
tenant_name=tenant_name,
|
|
branch_name=branch_name,
|
|
source_label="Firm team",
|
|
)
|
|
|
|
user, resolved_tenant_name, resolved_branch_name = result
|
|
return _contact_card_from_user(
|
|
user=user,
|
|
tenant_name=resolved_tenant_name or tenant_name,
|
|
branch_name=resolved_branch_name or branch_name,
|
|
source_label=source_label,
|
|
)
|