TorbatYar/backend/services/loyalty/app/repositories/ledger.py
Mortezakoohjani 071c484530 Ship Loyalty phases 7.2-7.6 (points through wallet) with production deploy.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-26 21:27:22 +03:30

93 lines
3.2 KiB
Python

"""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())