TorbatYar/backend/services/healthcare/app/repositories/foundation.py
Mortezakoohjani 625275e55b feat(healthcare): add backend service and finalize frontend build
Add the Healthcare platform backend (phases 13.0–13.7) with Alembic migration revision fix, production deploy script, validation reports, shared UI exports, and loyalty list page client directives so Next.js build succeeds.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-27 11:38:31 +03:30

151 lines
4.6 KiB
Python

"""Healthcare foundation repositories."""
from __future__ import annotations
from typing import Sequence
from uuid import UUID
from sqlalchemy import select
from app.models.foundation import (
Branch,
Clinic,
Department,
ExternalProviderConfig,
HealthcareAuditLog,
HealthcareConfiguration,
HealthcarePermission,
HealthcareRole,
HealthcareSetting,
)
from app.repositories.base import TenantBaseRepository
class ClinicRepository(TenantBaseRepository[Clinic]):
model = Clinic
async def get_by_code(self, tenant_id: UUID, code: str) -> Clinic | None:
stmt = select(self.model).where(
self.model.tenant_id == tenant_id,
self.model.code == code,
self.model.is_deleted.is_(False),
)
result = await self.session.execute(stmt)
return result.scalar_one_or_none()
class BranchRepository(TenantBaseRepository[Branch]):
model = Branch
async def list_by_clinic(
self, tenant_id: UUID, clinic_id: UUID, *, offset: int = 0, limit: int = 20
) -> Sequence[Branch]:
stmt = (
select(self.model)
.where(
self.model.tenant_id == tenant_id,
self.model.clinic_id == clinic_id,
self.model.is_deleted.is_(False),
)
.offset(offset)
.limit(limit)
)
result = await self.session.execute(stmt)
return result.scalars().all()
class DepartmentRepository(TenantBaseRepository[Department]):
model = Department
async def get_by_code(
self, tenant_id: UUID, clinic_id: UUID, code: str
) -> Department | None:
stmt = select(self.model).where(
self.model.tenant_id == tenant_id,
self.model.clinic_id == clinic_id,
self.model.code == code,
self.model.is_deleted.is_(False),
)
result = await self.session.execute(stmt)
return result.scalar_one_or_none()
class HealthcareRoleRepository(TenantBaseRepository[HealthcareRole]):
model = HealthcareRole
class HealthcarePermissionRepository(TenantBaseRepository[HealthcarePermission]):
model = HealthcarePermission
class ExternalProviderConfigRepository(TenantBaseRepository[ExternalProviderConfig]):
model = ExternalProviderConfig
async def get_by_code(
self, tenant_id: UUID, code: str
) -> ExternalProviderConfig | None:
stmt = select(self.model).where(
self.model.tenant_id == tenant_id,
self.model.code == code,
self.model.is_deleted.is_(False),
)
result = await self.session.execute(stmt)
return result.scalar_one_or_none()
class HealthcareConfigurationRepository(TenantBaseRepository[HealthcareConfiguration]):
model = HealthcareConfiguration
class HealthcareSettingRepository(TenantBaseRepository[HealthcareSetting]):
model = HealthcareSetting
async def get_by_key(
self,
tenant_id: UUID,
key: str,
*,
clinic_id: UUID | None = None,
branch_id: UUID | None = None,
) -> HealthcareSetting | None:
clauses = [
self.model.tenant_id == tenant_id,
self.model.key == key,
self.model.is_deleted.is_(False),
]
if clinic_id is None:
clauses.append(self.model.clinic_id.is_(None))
else:
clauses.append(self.model.clinic_id == clinic_id)
if branch_id is None:
clauses.append(self.model.branch_id.is_(None))
else:
clauses.append(self.model.branch_id == branch_id)
stmt = select(self.model).where(*clauses)
result = await self.session.execute(stmt)
return result.scalar_one_or_none()
class HealthcareAuditLogRepository(TenantBaseRepository[HealthcareAuditLog]):
model = HealthcareAuditLog
async def list_for_entity(
self,
tenant_id: UUID,
entity_type: str,
entity_id: UUID,
*,
limit: int = 100,
) -> Sequence[HealthcareAuditLog]:
stmt = (
select(self.model)
.where(
self.model.tenant_id == tenant_id,
self.model.entity_type == entity_type,
self.model.entity_id == entity_id,
)
.order_by(self.model.created_at.desc())
.limit(limit)
)
result = await self.session.execute(stmt)
return result.scalars().all()