"""Member APIs — Phase 7.0 foundation + Phase 7.1 membership lifecycle.""" from __future__ import annotations from uuid import UUID from fastapi import APIRouter, Depends, Query, 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_MEMBERS_ACTIVATE, LOYALTY_MEMBERS_CANCEL, LOYALTY_MEMBERS_CREATE, LOYALTY_MEMBERS_DELETE, LOYALTY_MEMBERS_ENROLL, LOYALTY_MEMBERS_EXPIRE, LOYALTY_MEMBERS_FREEZE, LOYALTY_MEMBERS_LIFECYCLE_VIEW, LOYALTY_MEMBERS_RENEW, LOYALTY_MEMBERS_RESUME, LOYALTY_MEMBERS_TRANSFER, LOYALTY_MEMBERS_UPDATE, LOYALTY_MEMBERS_VIEW, ) from app.schemas.foundation import ( MemberActivateRequest, MemberCancelRequest, MemberCreate, MemberEnrollRequest, MemberExpireRequest, MemberFreezeRequest, MemberRead, MemberRenewRequest, MemberResumeRequest, MembershipLifecycleEventRead, MemberTransferRequest, MemberUpdate, ) from app.services.foundation import MemberService from app.services.membership_engine import MembershipEngineService from shared.pagination import PaginationParams from shared.security import CurrentUser router = APIRouter() @router.post("", response_model=MemberRead, status_code=status.HTTP_201_CREATED) async def create_member( body: MemberCreate, tenant_id: UUID = Depends(require_tenant), db: AsyncSession = Depends(get_db), user: CurrentUser = Depends(require_permissions(LOYALTY_MEMBERS_CREATE)), ): return await MemberService(db).create(tenant_id, body, actor=user) @router.get("", response_model=list[MemberRead]) async def list_members( tenant_id: UUID = Depends(require_tenant), pagination: PaginationParams = Depends(get_pagination), db: AsyncSession = Depends(get_db), _user: CurrentUser = Depends(require_permissions(LOYALTY_MEMBERS_VIEW)), ): return await MemberService(db).list( tenant_id, offset=pagination.offset, limit=pagination.page_size ) @router.get("/{member_id}", response_model=MemberRead) async def get_member( member_id: UUID, tenant_id: UUID = Depends(require_tenant), db: AsyncSession = Depends(get_db), _user: CurrentUser = Depends(require_permissions(LOYALTY_MEMBERS_VIEW)), ): return await MemberService(db).get(tenant_id, member_id) @router.patch("/{member_id}", response_model=MemberRead) async def update_member( member_id: UUID, body: MemberUpdate, tenant_id: UUID = Depends(require_tenant), db: AsyncSession = Depends(get_db), user: CurrentUser = Depends(require_permissions(LOYALTY_MEMBERS_UPDATE)), ): return await MemberService(db).update(tenant_id, member_id, body, actor=user) @router.post("/{member_id}/enroll", response_model=MemberRead) async def enroll_member( member_id: UUID, body: MemberEnrollRequest, tenant_id: UUID = Depends(require_tenant), db: AsyncSession = Depends(get_db), user: CurrentUser = Depends(require_permissions(LOYALTY_MEMBERS_ENROLL)), ): return await MemberService(db).enroll(tenant_id, member_id, body, actor=user) @router.post("/{member_id}/activate", response_model=MemberRead) async def activate_member( member_id: UUID, body: MemberActivateRequest, tenant_id: UUID = Depends(require_tenant), db: AsyncSession = Depends(get_db), user: CurrentUser = Depends(require_permissions(LOYALTY_MEMBERS_ACTIVATE)), ): return await MembershipEngineService(db).activate( tenant_id, member_id, body, actor=user ) @router.post("/{member_id}/renew", response_model=MemberRead) async def renew_member( member_id: UUID, body: MemberRenewRequest, tenant_id: UUID = Depends(require_tenant), db: AsyncSession = Depends(get_db), user: CurrentUser = Depends(require_permissions(LOYALTY_MEMBERS_RENEW)), ): return await MembershipEngineService(db).renew( tenant_id, member_id, body, actor=user ) @router.post("/{member_id}/freeze", response_model=MemberRead) async def freeze_member( member_id: UUID, body: MemberFreezeRequest, tenant_id: UUID = Depends(require_tenant), db: AsyncSession = Depends(get_db), user: CurrentUser = Depends(require_permissions(LOYALTY_MEMBERS_FREEZE)), ): return await MembershipEngineService(db).freeze( tenant_id, member_id, body, actor=user ) @router.post("/{member_id}/resume", response_model=MemberRead) async def resume_member( member_id: UUID, body: MemberResumeRequest, tenant_id: UUID = Depends(require_tenant), db: AsyncSession = Depends(get_db), user: CurrentUser = Depends(require_permissions(LOYALTY_MEMBERS_RESUME)), ): return await MembershipEngineService(db).resume( tenant_id, member_id, body, actor=user ) @router.post("/{member_id}/cancel", response_model=MemberRead) async def cancel_member( member_id: UUID, body: MemberCancelRequest, tenant_id: UUID = Depends(require_tenant), db: AsyncSession = Depends(get_db), user: CurrentUser = Depends(require_permissions(LOYALTY_MEMBERS_CANCEL)), ): return await MembershipEngineService(db).cancel( tenant_id, member_id, body, actor=user ) @router.post("/{member_id}/expire", response_model=MemberRead) async def expire_member( member_id: UUID, body: MemberExpireRequest, tenant_id: UUID = Depends(require_tenant), db: AsyncSession = Depends(get_db), user: CurrentUser = Depends(require_permissions(LOYALTY_MEMBERS_EXPIRE)), ): return await MembershipEngineService(db).expire( tenant_id, member_id, body, actor=user ) @router.post("/{member_id}/transfer", response_model=MemberRead) async def transfer_member( member_id: UUID, body: MemberTransferRequest, tenant_id: UUID = Depends(require_tenant), db: AsyncSession = Depends(get_db), user: CurrentUser = Depends(require_permissions(LOYALTY_MEMBERS_TRANSFER)), ): return await MembershipEngineService(db).transfer( tenant_id, member_id, body, actor=user ) @router.get( "/{member_id}/lifecycle", response_model=list[MembershipLifecycleEventRead], ) async def list_member_lifecycle( member_id: UUID, limit: int = Query(default=100, ge=1, le=500), tenant_id: UUID = Depends(require_tenant), db: AsyncSession = Depends(get_db), _user: CurrentUser = Depends(require_permissions(LOYALTY_MEMBERS_LIFECYCLE_VIEW)), ): return await MembershipEngineService(db).list_lifecycle( tenant_id, member_id, limit=limit ) @router.post("/{member_id}/delete", response_model=MemberRead) async def soft_delete_member( member_id: UUID, tenant_id: UUID = Depends(require_tenant), db: AsyncSession = Depends(get_db), user: CurrentUser = Depends(require_permissions(LOYALTY_MEMBERS_DELETE)), ): return await MemberService(db).soft_delete(tenant_id, member_id, actor=user)