"""Referral Attribution APIs — attribute/convert/reward/cancel (Phase 7.5).""" from __future__ import annotations from uuid import UUID from fastapi import APIRouter, Depends, status from sqlalchemy.ext.asyncio import AsyncSession from app.api.deps import get_db, get_pagination, require_tenant from app.api.permissions import require_permissions from app.permissions.definitions import ( LOYALTY_REFERRALS_ATTRIBUTE, LOYALTY_REFERRALS_CANCEL, LOYALTY_REFERRALS_CONVERT, LOYALTY_REFERRALS_REWARD, LOYALTY_REFERRALS_VIEW, ) from app.schemas.referral import ( ReferralAttributeRequest, ReferralAttributionPage, ReferralAttributionRead, ReferralCancelRequest, ) from app.services.referral_engine import ReferralEngineService from shared.pagination import PaginationParams from shared.security import CurrentUser router = APIRouter() @router.post( "/attribute", response_model=ReferralAttributionRead, status_code=status.HTTP_201_CREATED, ) async def attribute_referral( body: ReferralAttributeRequest, tenant_id: UUID = Depends(require_tenant), db: AsyncSession = Depends(get_db), user: CurrentUser = Depends(require_permissions(LOYALTY_REFERRALS_ATTRIBUTE)), ): return await ReferralEngineService(db).attribute(tenant_id, body, actor=user) @router.get("", response_model=ReferralAttributionPage) async def list_referral_attributions( referral_program_id: UUID | None = None, tenant_id: UUID = Depends(require_tenant), pagination: PaginationParams = Depends(get_pagination), db: AsyncSession = Depends(get_db), _user: CurrentUser = Depends(require_permissions(LOYALTY_REFERRALS_VIEW)), ): rows, total = await ReferralEngineService(db).list_attributions( tenant_id, offset=pagination.offset, limit=pagination.page_size, referral_program_id=referral_program_id, ) return ReferralAttributionPage( items=rows, total=total, offset=pagination.offset, limit=pagination.page_size ) @router.get("/{attribution_id}", response_model=ReferralAttributionRead) async def get_referral_attribution( attribution_id: UUID, tenant_id: UUID = Depends(require_tenant), db: AsyncSession = Depends(get_db), _user: CurrentUser = Depends(require_permissions(LOYALTY_REFERRALS_VIEW)), ): return await ReferralEngineService(db).get_attribution(tenant_id, attribution_id) @router.post("/{attribution_id}/convert", response_model=ReferralAttributionRead) async def convert_referral( attribution_id: UUID, tenant_id: UUID = Depends(require_tenant), db: AsyncSession = Depends(get_db), user: CurrentUser = Depends(require_permissions(LOYALTY_REFERRALS_CONVERT)), ): return await ReferralEngineService(db).convert(tenant_id, attribution_id, actor=user) @router.post("/{attribution_id}/reward", response_model=ReferralAttributionRead) async def reward_referral( attribution_id: UUID, tenant_id: UUID = Depends(require_tenant), db: AsyncSession = Depends(get_db), user: CurrentUser = Depends(require_permissions(LOYALTY_REFERRALS_REWARD)), ): return await ReferralEngineService(db).reward(tenant_id, attribution_id, actor=user) @router.post("/{attribution_id}/cancel", response_model=ReferralAttributionRead) async def cancel_referral( attribution_id: UUID, body: ReferralCancelRequest, tenant_id: UUID = Depends(require_tenant), db: AsyncSession = Depends(get_db), user: CurrentUser = Depends(require_permissions(LOYALTY_REFERRALS_CANCEL)), ): return await ReferralEngineService(db).cancel( tenant_id, attribution_id, body, actor=user )