106 lines
3.7 KiB
Python
106 lines
3.7 KiB
Python
"""Reward redemption repositories — Phase 7.3."""
|
|
from __future__ import annotations
|
|
|
|
from uuid import UUID
|
|
|
|
from sqlalchemy import func, select
|
|
|
|
from app.models.rewards import RewardRedemption
|
|
from app.models.types import RedemptionStatus
|
|
from app.repositories.base import TenantBaseRepository
|
|
|
|
_NON_BLOCKING_STATUSES = (RedemptionStatus.CANCELLED,)
|
|
|
|
|
|
class RewardRedemptionRepository(TenantBaseRepository[RewardRedemption]):
|
|
model = RewardRedemption
|
|
|
|
async def get_by_idempotency(
|
|
self, tenant_id: UUID, idempotency_key: str | None
|
|
) -> RewardRedemption | None:
|
|
if not idempotency_key:
|
|
return None
|
|
stmt = select(RewardRedemption).where(
|
|
RewardRedemption.tenant_id == tenant_id,
|
|
RewardRedemption.idempotency_key == idempotency_key,
|
|
)
|
|
result = await self.session.execute(stmt)
|
|
return result.scalar_one_or_none()
|
|
|
|
async def count_for_member_reward(
|
|
self,
|
|
tenant_id: UUID,
|
|
member_id: UUID,
|
|
reward_id: UUID,
|
|
*,
|
|
exclude_statuses: tuple[RedemptionStatus, ...] = _NON_BLOCKING_STATUSES,
|
|
) -> int:
|
|
stmt = (
|
|
select(func.count())
|
|
.select_from(RewardRedemption)
|
|
.where(
|
|
RewardRedemption.tenant_id == tenant_id,
|
|
RewardRedemption.member_id == member_id,
|
|
RewardRedemption.reward_id == reward_id,
|
|
RewardRedemption.status.notin_(exclude_statuses),
|
|
)
|
|
)
|
|
result = await self.session.execute(stmt)
|
|
return int(result.scalar_one())
|
|
|
|
async def list(
|
|
self,
|
|
tenant_id: UUID,
|
|
*,
|
|
reward_id: UUID | None = None,
|
|
member_id: UUID | None = None,
|
|
status: RedemptionStatus | None = None,
|
|
offset: int = 0,
|
|
limit: int = 50,
|
|
):
|
|
clauses = [RewardRedemption.tenant_id == tenant_id]
|
|
if reward_id is not None:
|
|
clauses.append(RewardRedemption.reward_id == reward_id)
|
|
if member_id is not None:
|
|
clauses.append(RewardRedemption.member_id == member_id)
|
|
if status is not None:
|
|
clauses.append(RewardRedemption.status == status)
|
|
stmt = (
|
|
select(RewardRedemption)
|
|
.where(*clauses)
|
|
.order_by(RewardRedemption.created_at.desc())
|
|
.offset(offset)
|
|
.limit(limit)
|
|
)
|
|
result = await self.session.execute(stmt)
|
|
return result.scalars().all()
|
|
|
|
async def count(
|
|
self,
|
|
tenant_id: UUID,
|
|
*,
|
|
reward_id: UUID | None = None,
|
|
member_id: UUID | None = None,
|
|
status: RedemptionStatus | None = None,
|
|
) -> int:
|
|
clauses = [RewardRedemption.tenant_id == tenant_id]
|
|
if reward_id is not None:
|
|
clauses.append(RewardRedemption.reward_id == reward_id)
|
|
if member_id is not None:
|
|
clauses.append(RewardRedemption.member_id == member_id)
|
|
if status is not None:
|
|
clauses.append(RewardRedemption.status == status)
|
|
stmt = select(func.count()).select_from(RewardRedemption).where(*clauses)
|
|
result = await self.session.execute(stmt)
|
|
return int(result.scalar_one())
|
|
|
|
async def list_for_member(
|
|
self, tenant_id: UUID, member_id: UUID, *, offset: int = 0, limit: int = 50
|
|
):
|
|
return await self.list(tenant_id, member_id=member_id, offset=offset, limit=limit)
|
|
|
|
async def list_for_reward(
|
|
self, tenant_id: UUID, reward_id: UUID, *, offset: int = 0, limit: int = 50
|
|
):
|
|
return await self.list(tenant_id, reward_id=reward_id, offset=offset, limit=limit)
|