Fix Client Groups circular imports and module dependencies

This commit is contained in:
A R R R Associates
2026-07-25 22:58:07 +05:30
parent ea0f3a1802
commit 2ea0ba907a
3 changed files with 37 additions and 6 deletions
+3 -2
View File
@@ -5,9 +5,10 @@ from fastapi.responses import RedirectResponse
from app.core.db.common import CommonSessionLocal
from app.core.security.csrf import get_or_create_csrf_token, validate_csrf
from app.core.security.deps import get_current_user
from app.core.security.session_auth import get_current_user
from app.core.templating import templates
from app.modules.core.rbac.service import get_user_permissions, get_user_roles, require_permission
from app.modules.core.rbac.deps import get_user_permissions, get_user_roles
from app.modules.core.rbac.permission_guard import require_permission
from app.modules.client_groups.service import GROUP_TYPES, create_group, get_group, list_group_clients, list_groups, update_group
from app.modules.clients.access import build_scope
from app.modules.clients import repository
+27 -2
View File
@@ -1,4 +1,29 @@
from .api import router as api_router
from .ui import router as ui_router
"""Clients module.
Routers are exposed lazily so importing ``app.modules.clients.models`` does
not initialise the clients API, UI, importer, and related modules. This keeps
the existing ``api_router`` and ``ui_router`` public exports while preventing
circular imports with client groups.
"""
from __future__ import annotations
from typing import Any
__all__ = ["api_router", "ui_router"]
def __getattr__(name: str) -> Any:
if name == "api_router":
from .api import router
return router
if name == "ui_router":
from .ui import router
return router
raise AttributeError(
f"module {__name__!r} has no attribute {name!r}"
)
+7 -2
View File
@@ -30,11 +30,16 @@ 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
def _get_client_group(*args, **kwargs):
# Imported lazily to prevent clients ↔ client_groups circular imports.
from app.modules.client_groups.service import get_group
return get_group(*args, **kwargs)
def _payload_from_schema(data):
payload = data.model_dump(exclude_none=True) if hasattr(data, "model_dump") else data.dict(exclude_none=True)
# primary_consultant_id belongs to ClientConsultantLink, not the clients table.
@@ -50,7 +55,7 @@ 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))
group = _get_client_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: