Add client groups and family tracking
This commit is contained in:
@@ -30,6 +30,8 @@ from app.modules.core.iam.models import User
|
||||
from app.modules.core.rbac.models import Role, UserRole
|
||||
from app.modules.documents.models import PermanentClientDocument
|
||||
from app.modules.consultants.service import sync_primary_client_consultant_link
|
||||
from app.modules.client_groups.service import get_group
|
||||
from app.modules.clients.models import Client
|
||||
|
||||
|
||||
|
||||
@@ -43,6 +45,26 @@ def _payload_from_schema(data):
|
||||
|
||||
|
||||
|
||||
|
||||
def _validate_client_group_assignment(db, *, payload: dict, existing_row=None):
|
||||
group_id = payload.get("client_group_id")
|
||||
tenant_id = payload.get("tenant_id") or getattr(existing_row, "tenant_id", None)
|
||||
if group_id:
|
||||
group = get_group(db, tenant_id=int(tenant_id), group_id=int(group_id))
|
||||
if not group or not group.is_active:
|
||||
raise HTTPException(status_code=400, detail="Selected client group is invalid or inactive for this firm.")
|
||||
if payload.get("is_group_head") and group_id:
|
||||
stmt = select(Client).where(Client.tenant_id == int(tenant_id), Client.client_group_id == int(group_id), Client.is_group_head.is_(True))
|
||||
if existing_row is not None:
|
||||
stmt = stmt.where(Client.id != existing_row.id)
|
||||
existing_head = db.execute(stmt).scalar_one_or_none()
|
||||
if existing_head:
|
||||
raise HTTPException(status_code=400, detail=f"This group already has group head {existing_head.client_code} - {existing_head.client_name}.")
|
||||
if not group_id:
|
||||
payload["group_relationship"] = None
|
||||
payload["is_group_head"] = False
|
||||
|
||||
|
||||
def _is_high_risk(risk_category: str | None) -> bool:
|
||||
return (risk_category or "").strip().lower() in CLIENT_ACCEPTANCE_APPROVAL_REQUIRED_RISKS
|
||||
|
||||
@@ -271,6 +293,7 @@ def create_client_service(db, *, data, actor_user_id: int, scope, current_user_r
|
||||
|
||||
payload = _payload_from_schema(data)
|
||||
_enforce_client_acceptance_controls(payload)
|
||||
_validate_client_group_assignment(db, payload=payload)
|
||||
row = repository.create_client(db, payload)
|
||||
row = _sync_client_portal_user(db, row=row, portal_password=portal_password, portal_password_confirm=portal_password_confirm)
|
||||
sync_primary_client_consultant_link(db, client=row, consultant_id=getattr(data, "primary_consultant_id", None), actor_user_id=actor_user_id)
|
||||
@@ -301,6 +324,7 @@ def update_client_service(db, *, row, data, actor_user_id: int, scope, current_u
|
||||
|
||||
payload = _payload_from_schema(data)
|
||||
_enforce_client_acceptance_controls(payload, existing_row=row)
|
||||
_validate_client_group_assignment(db, payload=payload, existing_row=row)
|
||||
|
||||
if payload.get("pan"):
|
||||
existing_pan = repository.get_client_by_pan(db, tenant_id=payload["tenant_id"], pan=payload["pan"])
|
||||
@@ -441,6 +465,10 @@ def export_clients_csv(payload: dict) -> str:
|
||||
"pan",
|
||||
"gstin",
|
||||
"partner",
|
||||
"client_group_code",
|
||||
"client_group_name",
|
||||
"group_relationship",
|
||||
"is_group_head",
|
||||
"association_type",
|
||||
"association_source",
|
||||
]
|
||||
@@ -455,6 +483,10 @@ def export_clients_csv(payload: dict) -> str:
|
||||
row.get("pan"),
|
||||
row.get("gstin"),
|
||||
row.get("partner_name") or row.get("effective_partner_id"),
|
||||
row.get("client_group_code"),
|
||||
row.get("client_group_name"),
|
||||
row.get("group_relationship"),
|
||||
row.get("is_group_head"),
|
||||
row.get("association_type"),
|
||||
row.get("assoc_created_source"),
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user