"""Point ledger APIs — Phase 7.2.""" from __future__ import annotations from uuid import UUID from fastapi import APIRouter, Depends, Query from sqlalchemy.ext.asyncio import AsyncSession from app.api.deps import get_db, require_tenant from app.api.permissions import require_permissions from app.models.types import LedgerEntryType from app.permissions.definitions import ( LOYALTY_POINTS_ADJUST, LOYALTY_POINTS_EARN, LOYALTY_POINTS_EXPIRE, LOYALTY_POINTS_REDEEM, LOYALTY_POINTS_VIEW, ) from app.schemas.ledger import ( PointAdjustRequest, PointBalanceRead, PointEarnRequest, PointExpireRequest, PointLedgerEntryRead, PointLedgerPage, PointRedeemRequest, ) from app.services.point_engine import PointEngineService from shared.security import CurrentUser router = APIRouter() @router.get("/{account_id}/balance", response_model=PointBalanceRead) async def get_balance( account_id: UUID, tenant_id: UUID = Depends(require_tenant), db: AsyncSession = Depends(get_db), _user: CurrentUser = Depends(require_permissions(LOYALTY_POINTS_VIEW)), ): return await PointEngineService(db).get_balance(tenant_id, account_id) @router.get("/{account_id}/ledger", response_model=PointLedgerPage) async def list_ledger( account_id: UUID, offset: int = Query(default=0, ge=0), limit: int = Query(default=50, ge=1, le=200), entry_type: LedgerEntryType | None = None, q: str | None = Query(default=None, max_length=100), tenant_id: UUID = Depends(require_tenant), db: AsyncSession = Depends(get_db), _user: CurrentUser = Depends(require_permissions(LOYALTY_POINTS_VIEW)), ): rows, total = await PointEngineService(db).list_entries( tenant_id, account_id, entry_type=entry_type, offset=offset, limit=limit, q=q, ) return PointLedgerPage( items=rows, total=total, offset=offset, limit=limit ) @router.post("/{account_id}/earn", response_model=PointLedgerEntryRead) async def earn_points( account_id: UUID, body: PointEarnRequest, tenant_id: UUID = Depends(require_tenant), db: AsyncSession = Depends(get_db), user: CurrentUser = Depends(require_permissions(LOYALTY_POINTS_EARN)), ): return await PointEngineService(db).earn(tenant_id, account_id, body, actor=user) @router.post("/{account_id}/redeem", response_model=PointLedgerEntryRead) async def redeem_points( account_id: UUID, body: PointRedeemRequest, tenant_id: UUID = Depends(require_tenant), db: AsyncSession = Depends(get_db), user: CurrentUser = Depends(require_permissions(LOYALTY_POINTS_REDEEM)), ): return await PointEngineService(db).redeem( tenant_id, account_id, body, actor=user ) @router.post("/{account_id}/adjust", response_model=PointLedgerEntryRead) async def adjust_points( account_id: UUID, body: PointAdjustRequest, tenant_id: UUID = Depends(require_tenant), db: AsyncSession = Depends(get_db), user: CurrentUser = Depends(require_permissions(LOYALTY_POINTS_ADJUST)), ): return await PointEngineService(db).adjust( tenant_id, account_id, body, actor=user ) @router.post("/{account_id}/expire-points", response_model=PointLedgerEntryRead) async def expire_points( account_id: UUID, body: PointExpireRequest, tenant_id: UUID = Depends(require_tenant), db: AsyncSession = Depends(get_db), user: CurrentUser = Depends(require_permissions(LOYALTY_POINTS_EXPIRE)), ): return await PointEngineService(db).expire( tenant_id, account_id, body, actor=user )