"""我的团队 — a tiny, self-scoped team summary for the IT 宇宙 welcome banner. The employee IT-home banner fills its previously-empty top-right with a sense of belonging: who your manager is and how big your immediate team is. This is deliberately cheap (≤3 indexed COUNT/SELECT queries) so it can sit on the hot ``/me`` landing path without dragging in the full ``it-home`` aggregation. Semantics: * ``manager`` — your manager, skipped if they have left / been soft-deleted (a stale ``manager_person_id`` pointing at an offboarded lead shouldn't surface a ghost name). * ``peer_count`` — active people who share your manager, excluding yourself ("同事"). Zero when you have no manager. * ``direct_report_count`` — active people who report to you ("下属"). Drives the "你带领 N 位下属" line for managers who have no manager of their own. Read-only, self-scoped — the route hands in ``person`` = the caller. """ from __future__ import annotations from typing import Any from pydantic import BaseModel from sqlalchemy import func, select from sqlalchemy.ext.asyncio import AsyncSession from app.identity.person_models import IdentityPerson class TeamSummaryResponse(BaseModel): manager: dict[str, Any] | None peer_count: int direct_report_count: int def _is_active(col_status, col_deleted): # An "active" colleague: not soft-deleted and not offboarded. Mirrors the # leaver-exclusion every other people-count in the platform applies. return (col_deleted.is_(None)) & (col_status != "left") async def build_my_team_summary( db: AsyncSession, person: IdentityPerson, ) -> TeamSummaryResponse: manager_card: dict[str, Any] | None = None peer_count = 0 if person.manager_person_id is not None: manager = await db.get(IdentityPerson, person.manager_person_id) if ( manager is not None and manager.deleted_at is None and manager.employment_status != "left" ): manager_card = { "id": str(manager.id), "display_name": manager.display_name or manager.work_email, "job_title": manager.job_title, "avatar_url": manager.avatar_url, } peer_count = int( ( await db.execute( select(func.count(IdentityPerson.id)).where( IdentityPerson.manager_person_id == person.manager_person_id, IdentityPerson.id != person.id, _is_active( IdentityPerson.employment_status, IdentityPerson.deleted_at, ), ) ) ).scalar() or 0 ) direct_report_count = int( ( await db.execute( select(func.count(IdentityPerson.id)).where( IdentityPerson.manager_person_id == person.id, _is_active( IdentityPerson.employment_status, IdentityPerson.deleted_at, ), ) ) ).scalar() or 0 ) return TeamSummaryResponse( manager=manager_card, peer_count=peer_count, direct_report_count=direct_report_count, )