# app/modules/loyalty/schemas/stamp.py """ Pydantic schemas for stamp operations. Merchant-based stamps: - Stamps earned at any store count toward merchant total - Stamps can be redeemed at any store within the merchant - Supports voiding stamps for returns """ from datetime import datetime from pydantic import BaseModel, Field class StampRequest(BaseModel): """Schema for adding a stamp to a card.""" 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)", ) # 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 about this stamp", ) class StampResponse(BaseModel): """Schema for stamp operation response.""" success: bool = True message: str = "Stamp added successfully" # Card state after stamp card_id: int card_number: str stamp_count: int stamps_target: int stamps_until_reward: int # Did this trigger a reward? reward_earned: bool = False reward_description: str | None = None # Cooldown info next_stamp_available_at: datetime | None = None # Today's activity stamps_today: int stamps_remaining_today: int # Location store_id: int | None = None class StampRedeemRequest(BaseModel): """Schema for redeeming stamps 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)", ) # 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 about this redemption", ) class StampRedeemResponse(BaseModel): """Schema for stamp redemption response.""" success: bool = True message: str = "Reward redeemed successfully" # Card state after redemption card_id: int card_number: str stamp_count: int # Should be 0 after redemption stamps_target: int # Reward info reward_description: str total_redemptions: int # Lifetime redemptions for this card # Location store_id: int | None = None class StampVoidRequest(BaseModel): """Schema for voiding stamps (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)", ) # Stamps to void (use one method) stamps_to_void: int | None = Field( None, gt=0, description="Number of stamps to void", ) original_transaction_id: int | None = Field( None, description="ID of original transaction to 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 StampVoidResponse(BaseModel): """Schema for stamp void response.""" success: bool = True message: str = "Stamps voided successfully" # Void info stamps_voided: int # Card state after void card_id: int card_number: str stamp_count: int # Location store_id: int | None = None