"""Referral Engine DTOs — Phase 7.5.""" from __future__ import annotations from datetime import datetime from uuid import UUID from pydantic import BaseModel, ConfigDict, Field from app.models.types import ( ReferralAttributionStatus, ReferralCodeStatus, ReferralProgramStatus, ) from app.schemas.common import ORMBase _FORBID = ConfigDict(extra="forbid") class ReferralProgramCreate(BaseModel): model_config = _FORBID program_id: UUID code: str = Field(max_length=50) name: str = Field(max_length=255) status: ReferralProgramStatus = ReferralProgramStatus.DRAFT referrer_bonus_points: int = Field(default=0, ge=0) referee_bonus_points: int = Field(default=0, ge=0) max_referrals_per_member: int | None = Field(default=None, ge=1) class ReferralProgramUpdate(BaseModel): model_config = _FORBID name: str | None = Field(default=None, max_length=255) status: ReferralProgramStatus | None = None referrer_bonus_points: int | None = Field(default=None, ge=0) referee_bonus_points: int | None = Field(default=None, ge=0) max_referrals_per_member: int | None = Field(default=None, ge=1) class ReferralProgramRead(ORMBase): id: UUID tenant_id: UUID program_id: UUID code: str name: str status: ReferralProgramStatus referrer_bonus_points: int referee_bonus_points: int max_referrals_per_member: int | None is_deleted: bool created_by: str | None updated_by: str | None created_at: datetime updated_at: datetime class ReferralProgramPage(BaseModel): items: list[ReferralProgramRead] total: int offset: int limit: int class ReferralCodeIssueRequest(BaseModel): model_config = _FORBID referral_program_id: UUID member_id: UUID code: str | None = Field(default=None, max_length=50) class ReferralCodeRead(ORMBase): id: UUID tenant_id: UUID referral_program_id: UUID program_id: UUID member_id: UUID code: str status: ReferralCodeStatus uses_count: int created_by: str | None created_at: datetime updated_at: datetime class ReferralCodePage(BaseModel): items: list[ReferralCodeRead] total: int offset: int limit: int class ReferralAttributeRequest(BaseModel): model_config = _FORBID code: str = Field(max_length=50) referee_member_id: UUID idempotency_key: str | None = Field(default=None, max_length=100) class ReferralCancelRequest(BaseModel): model_config = _FORBID reason: str | None = Field(default=None, max_length=500) class ReferralAttributionRead(ORMBase): id: UUID tenant_id: UUID referral_program_id: UUID referral_code_id: UUID program_id: UUID referrer_member_id: UUID referee_member_id: UUID status: ReferralAttributionStatus referrer_ledger_entry_id: UUID | None referee_ledger_entry_id: UUID | None idempotency_key: str | None converted_at: datetime | None rewarded_at: datetime | None cancelled_at: datetime | None cancel_reason: str | None actor_user_id: str | None created_at: datetime updated_at: datetime class ReferralAttributionPage(BaseModel): items: list[ReferralAttributionRead] total: int offset: int limit: int