# app/modules/loyalty/schemas/points.py """ Pydantic schemas for points operations. Merchant-based points: - Points earned at any store count toward merchant total - Points can be redeemed at any store within the merchant - Supports voiding points for returns """ from pydantic import BaseModel, Field class PointsEarnRequest(BaseModel): """Schema for earning points from a purchase.""" card_id: int | None = Field( None, description="Card ID (use this or qr_code)", ) qr_code: str | None = Field( None, description="QR code data from card scan", ) card_number: str | None = Field( None, description="Card number (manual entry)", ) # Purchase info purchase_amount_cents: int = Field( ..., gt=0, description="Purchase amount in cents", ) order_reference: str | None = Field( None, max_length=100, description="Order reference for tracking", ) # Authentication staff_pin: str | None = Field( None, min_length=4, max_length=6, description="Staff PIN for verification", ) # Optional metadata notes: str | None = Field( None, max_length=500, description="Optional note", ) class PointsEarnResponse(BaseModel): """Schema for points earning response.""" success: bool = True message: str = "Points earned successfully" # Points info points_earned: int points_per_euro: int purchase_amount_cents: int # Card state after earning card_id: int card_number: str points_balance: int total_points_earned: int # Location store_id: int | None = None class PointsRedeemRequest(BaseModel): """Schema for redeeming points for a reward.""" card_id: int | None = Field( None, description="Card ID (use this or qr_code)", ) qr_code: str | None = Field( None, description="QR code data from card scan", ) card_number: str | None = Field( None, description="Card number (manual entry)", ) # Reward selection reward_id: str = Field( ..., description="ID of the reward to redeem", ) # Authentication staff_pin: str | None = Field( None, min_length=4, max_length=6, description="Staff PIN for verification", ) # Optional metadata notes: str | None = Field( None, max_length=500, description="Optional note", ) class PointsRedeemResponse(BaseModel): """Schema for points redemption response.""" success: bool = True message: str = "Reward redeemed successfully" # Reward info reward_id: str reward_name: str points_spent: int # Card state after redemption card_id: int card_number: str points_balance: int total_points_redeemed: int # Location store_id: int | None = None class PointsVoidRequest(BaseModel): """Schema for voiding points (for returns).""" card_id: int | None = Field( None, description="Card ID (use this or qr_code)", ) qr_code: str | None = Field( None, description="QR code data from card scan", ) card_number: str | None = Field( None, description="Card number (manual entry)", ) # Points to void (use one method) points_to_void: int | None = Field( None, gt=0, description="Number of points to void", ) original_transaction_id: int | None = Field( None, description="ID of original transaction to void", ) order_reference: str | None = Field( None, max_length=100, description="Order reference to find and void", ) # Authentication staff_pin: str | None = Field( None, min_length=4, max_length=6, description="Staff PIN for verification", ) # Required metadata notes: str | None = Field( None, max_length=500, description="Reason for voiding", ) class PointsVoidResponse(BaseModel): """Schema for points void response.""" success: bool = True message: str = "Points voided successfully" # Void info points_voided: int # Card state after void card_id: int card_number: str points_balance: int # Location store_id: int | None = None class PointsAdjustRequest(BaseModel): """Schema for manual points adjustment (admin).""" points_delta: int = Field( ..., ge=-100000, le=100000, description="Points to add (positive) or remove (negative)", ) reason: str = Field( ..., min_length=5, max_length=500, description="Reason for adjustment (required)", ) staff_pin: str | None = Field( None, min_length=4, max_length=6, description="Staff PIN for verification", ) class PointsAdjustResponse(BaseModel): """Schema for points adjustment response.""" success: bool = True message: str = "Points adjusted successfully" # Adjustment info points_delta: int # Card state after adjustment card_id: int card_number: str points_balance: int