"""Point ledger repositories — Phase 7.2.""" from __future__ import annotations from uuid import UUID from sqlalchemy import func, select from sqlalchemy.ext.asyncio import AsyncSession from app.models.ledger import PointLedgerEntry from app.models.types import LedgerEntryType from app.repositories.base import TenantBaseRepository class PointLedgerRepository(TenantBaseRepository[PointLedgerEntry]): model = PointLedgerEntry async def get_by_idempotency( self, tenant_id: UUID, idempotency_key: str ) -> PointLedgerEntry | None: if not idempotency_key: return None stmt = select(PointLedgerEntry).where( PointLedgerEntry.tenant_id == tenant_id, PointLedgerEntry.idempotency_key == idempotency_key, ) result = await self.session.execute(stmt) return result.scalar_one_or_none() async def balance_for_account(self, tenant_id: UUID, point_account_id: UUID) -> int: stmt = select(func.coalesce(func.sum(PointLedgerEntry.amount), 0)).where( PointLedgerEntry.tenant_id == tenant_id, PointLedgerEntry.point_account_id == point_account_id, ) result = await self.session.execute(stmt) return int(result.scalar_one()) async def list_for_account( self, tenant_id: UUID, point_account_id: UUID, *, entry_type: LedgerEntryType | None = None, offset: int = 0, limit: int = 50, q: str | None = None, ): clauses = [ PointLedgerEntry.tenant_id == tenant_id, PointLedgerEntry.point_account_id == point_account_id, ] if entry_type is not None: clauses.append(PointLedgerEntry.entry_type == entry_type) if q: like = f"%{q.strip()}%" clauses.append( (PointLedgerEntry.reason.ilike(like)) | (PointLedgerEntry.reference_id.ilike(like)) | (PointLedgerEntry.idempotency_key.ilike(like)) ) stmt = ( select(PointLedgerEntry) .where(*clauses) .order_by(PointLedgerEntry.created_at.desc()) .offset(offset) .limit(limit) ) result = await self.session.execute(stmt) return result.scalars().all() async def count_for_account( self, tenant_id: UUID, point_account_id: UUID, *, entry_type: LedgerEntryType | None = None, q: str | None = None, ) -> int: clauses = [ PointLedgerEntry.tenant_id == tenant_id, PointLedgerEntry.point_account_id == point_account_id, ] if entry_type is not None: clauses.append(PointLedgerEntry.entry_type == entry_type) if q: like = f"%{q.strip()}%" clauses.append( (PointLedgerEntry.reason.ilike(like)) | (PointLedgerEntry.reference_id.ilike(like)) ) stmt = select(func.count()).select_from(PointLedgerEntry).where(*clauses) result = await self.session.execute(stmt) return int(result.scalar_one())