106 lines
3.7 KiB
Python
106 lines
3.7 KiB
Python
"""Wallet Engine repositories — Phase 7.6."""
|
|
from __future__ import annotations
|
|
|
|
from uuid import UUID
|
|
|
|
from sqlalchemy import func, select
|
|
|
|
from app.models.types import WalletLedgerEntryType
|
|
from app.models.wallet import WalletAccount, WalletLedgerEntry
|
|
from app.repositories.base import TenantBaseRepository
|
|
|
|
|
|
class WalletAccountRepository(TenantBaseRepository[WalletAccount]):
|
|
model = WalletAccount
|
|
|
|
async def get_by_member_program(
|
|
self, tenant_id: UUID, program_id: UUID, member_id: UUID
|
|
) -> WalletAccount | None:
|
|
stmt = select(WalletAccount).where(
|
|
WalletAccount.tenant_id == tenant_id,
|
|
WalletAccount.program_id == program_id,
|
|
WalletAccount.member_id == member_id,
|
|
WalletAccount.is_deleted.is_(False),
|
|
)
|
|
result = await self.session.execute(stmt)
|
|
return result.scalar_one_or_none()
|
|
|
|
async def get_by_account_number(
|
|
self, tenant_id: UUID, account_number: str
|
|
) -> WalletAccount | None:
|
|
stmt = select(WalletAccount).where(
|
|
WalletAccount.tenant_id == tenant_id,
|
|
WalletAccount.account_number == account_number,
|
|
WalletAccount.is_deleted.is_(False),
|
|
)
|
|
result = await self.session.execute(stmt)
|
|
return result.scalar_one_or_none()
|
|
|
|
|
|
class WalletLedgerRepository(TenantBaseRepository[WalletLedgerEntry]):
|
|
model = WalletLedgerEntry
|
|
|
|
async def balance_for_account(
|
|
self, tenant_id: UUID, wallet_account_id: UUID
|
|
) -> int:
|
|
stmt = select(func.coalesce(func.sum(WalletLedgerEntry.amount), 0)).where(
|
|
WalletLedgerEntry.tenant_id == tenant_id,
|
|
WalletLedgerEntry.wallet_account_id == wallet_account_id,
|
|
)
|
|
result = await self.session.execute(stmt)
|
|
return int(result.scalar_one())
|
|
|
|
async def get_by_idempotency(
|
|
self, tenant_id: UUID, idempotency_key: str | None
|
|
) -> WalletLedgerEntry | None:
|
|
if not idempotency_key:
|
|
return None
|
|
stmt = select(WalletLedgerEntry).where(
|
|
WalletLedgerEntry.tenant_id == tenant_id,
|
|
WalletLedgerEntry.idempotency_key == idempotency_key,
|
|
)
|
|
result = await self.session.execute(stmt)
|
|
return result.scalar_one_or_none()
|
|
|
|
async def list_for_account(
|
|
self,
|
|
tenant_id: UUID,
|
|
wallet_account_id: UUID,
|
|
*,
|
|
entry_type: WalletLedgerEntryType | None = None,
|
|
offset: int = 0,
|
|
limit: int = 50,
|
|
):
|
|
clauses = [
|
|
WalletLedgerEntry.tenant_id == tenant_id,
|
|
WalletLedgerEntry.wallet_account_id == wallet_account_id,
|
|
]
|
|
if entry_type is not None:
|
|
clauses.append(WalletLedgerEntry.entry_type == entry_type)
|
|
stmt = (
|
|
select(WalletLedgerEntry)
|
|
.where(*clauses)
|
|
.order_by(WalletLedgerEntry.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,
|
|
wallet_account_id: UUID,
|
|
*,
|
|
entry_type: WalletLedgerEntryType | None = None,
|
|
) -> int:
|
|
clauses = [
|
|
WalletLedgerEntry.tenant_id == tenant_id,
|
|
WalletLedgerEntry.wallet_account_id == wallet_account_id,
|
|
]
|
|
if entry_type is not None:
|
|
clauses.append(WalletLedgerEntry.entry_type == entry_type)
|
|
stmt = select(func.count()).select_from(WalletLedgerEntry).where(*clauses)
|
|
result = await self.session.execute(stmt)
|
|
return int(result.scalar_one())
|