Enforce partner client ownership and partner-scoped imports

This commit is contained in:
A R R R Associates
2026-07-29 06:05:10 +05:30
parent 83f4cd2d4f
commit a58ec7b807
9 changed files with 205 additions and 108 deletions
+22 -4
View File
@@ -1,10 +1,11 @@
from __future__ import annotations
from sqlalchemy import func, select
from sqlalchemy import exists, func, or_, select
from sqlalchemy.orm import Session
from app.modules.client_groups.models import ClientGroup
from app.modules.clients.models import Client
from app.modules.services.models import ClientServiceSubscription
GROUP_TYPES = ("Family", "Business Group", "Promoter Group", "Trust Group", "Common Management", "Other")
@@ -13,7 +14,7 @@ def normalise_group_code(value: str | None) -> str:
return (value or "").strip().upper()
def list_groups(db: Session, *, tenant_id: int, include_inactive: bool = False):
def list_groups(db: Session, *, tenant_id: int, include_inactive: bool = False, viewer_partner_id: int | None = None):
stmt = (
select(ClientGroup, func.count(Client.id).label("client_count"))
.outerjoin(Client, Client.client_group_id == ClientGroup.id)
@@ -21,6 +22,14 @@ def list_groups(db: Session, *, tenant_id: int, include_inactive: bool = False):
.group_by(ClientGroup.id)
.order_by(ClientGroup.group_name.asc())
)
if viewer_partner_id is not None:
review_access = exists(select(ClientServiceSubscription.id).where(
ClientServiceSubscription.tenant_id == tenant_id,
ClientServiceSubscription.client_id == Client.id,
ClientServiceSubscription.review_partner_user_id == viewer_partner_id,
ClientServiceSubscription.is_active.is_(True),
))
stmt = stmt.where(or_(Client.partner_id == viewer_partner_id, review_access))
if not include_inactive:
stmt = stmt.where(ClientGroup.is_active.is_(True))
return [{"group": group, "client_count": int(count or 0)} for group, count in db.execute(stmt).all()]
@@ -37,8 +46,17 @@ def get_group_by_code(db: Session, *, tenant_id: int, group_code: str):
return db.execute(select(ClientGroup).where(ClientGroup.tenant_id == tenant_id, ClientGroup.group_code == code)).scalar_one_or_none()
def list_group_clients(db: Session, *, tenant_id: int, group_id: int):
return db.execute(select(Client).where(Client.tenant_id == tenant_id, Client.client_group_id == group_id, Client.is_archived.is_(False)).order_by(Client.is_group_head.desc(), Client.client_name.asc())).scalars().all()
def list_group_clients(db: Session, *, tenant_id: int, group_id: int, viewer_partner_id: int | None = None):
stmt = select(Client).where(Client.tenant_id == tenant_id, Client.client_group_id == group_id, Client.is_archived.is_(False))
if viewer_partner_id is not None:
review_access = exists(select(ClientServiceSubscription.id).where(
ClientServiceSubscription.tenant_id == tenant_id,
ClientServiceSubscription.client_id == Client.id,
ClientServiceSubscription.review_partner_user_id == viewer_partner_id,
ClientServiceSubscription.is_active.is_(True),
))
stmt = stmt.where(or_(Client.partner_id == viewer_partner_id, review_access))
return db.execute(stmt.order_by(Client.is_group_head.desc(), Client.client_name.asc())).scalars().all()
def create_group(db: Session, *, tenant_id: int, actor_user_id: int, payload: dict):