from datetime import datetime from typing import Optional, List, Any, Dict, Union from uuid import UUID from pydantic import BaseModel, Field, field_validator, model_validator from app.models.gift import GiftStatus, GiftPriority # Base Gift Schema class GiftItemBase(BaseModel): name: str description: Optional[str] = None price: Optional[float] = None currency: Optional[str] = "USD" quantity_requested: Optional[int] = 1 quantity_received: Optional[int] = 0 status: Optional[GiftStatus] = GiftStatus.AVAILABLE priority: Optional[GiftPriority] = GiftPriority.MEDIUM purchase_url: Optional[str] = None store_name: Optional[str] = None brand: Optional[str] = None model: Optional[str] = None image_url: Optional[str] = None display_order: Optional[int] = None is_visible: Optional[bool] = True notes: Optional[str] = None custom_fields: Optional[Dict[str, Any]] = None # Schema for creating a gift class GiftItemCreate(GiftItemBase): event_id: UUID added_by: UUID category_id: Optional[UUID] = None @field_validator('price') @classmethod def validate_price(cls, v: Optional[float]) -> Optional[float]: if v is not None and v < 0: raise ValueError("Price cannot be negative") return v @field_validator('quantity_requested') @classmethod def validate_quantity(cls, v: Optional[int]) -> Optional[int]: if v is not None and v < 1: raise ValueError("Quantity requested must be at least 1") return v # Schema for updating a gift class GiftItemUpdate(BaseModel): name: Optional[str] = None description: Optional[str] = None price: Optional[float] = None currency: Optional[str] = None quantity_requested: Optional[int] = None quantity_received: Optional[int] = None status: Optional[GiftStatus] = None priority: Optional[GiftPriority] = None purchase_url: Optional[str] = None store_name: Optional[str] = None brand: Optional[str] = None model: Optional[str] = None image_url: Optional[str] = None display_order: Optional[int] = None is_visible: Optional[bool] = None notes: Optional[str] = None custom_fields: Optional[Dict[str, Any]] = None category_id: Optional[UUID] = None @field_validator('price') @classmethod def validate_price(cls, v: Optional[float]) -> Optional[float]: if v is not None and v < 0: raise ValueError("Price cannot be negative") return v @field_validator('quantity_requested') @classmethod def validate_quantity(cls, v: Optional[int]) -> Optional[int]: if v is not None and v < 1: raise ValueError("Quantity requested must be at least 1") return v # Schema for reading a gift class GiftItemInDB(GiftItemBase): id: UUID event_id: UUID added_by: UUID category_id: Optional[UUID] = None last_status_change: Optional[datetime] = None created_at: datetime updated_at: datetime class Config: from_attributes = True # Public gift item response class GiftItem(GiftItemInDB): remaining_quantity: int is_fully_received: bool formatted_price: str reserved: bool = False class Config: from_attributes = True # Gift Category Schemas class GiftCategoryBase(BaseModel): name: str description: Optional[str] = None icon: Optional[str] = None color: Optional[str] = None custom_fields: Optional[Dict[str, Any]] = None # Schema for creating a category class GiftCategoryCreate(GiftCategoryBase): created_by: UUID # Schema for updating a category class GiftCategoryUpdate(BaseModel): name: Optional[str] = None description: Optional[str] = None icon: Optional[str] = None color: Optional[str] = None custom_fields: Optional[Dict[str, Any]] = None # Schema for reading a category class GiftCategoryInDB(GiftCategoryBase): id: UUID created_by: UUID created_at: datetime updated_at: datetime class Config: from_attributes = True # Event-Category association schemas class EventGiftCategoryBase(BaseModel): event_id: UUID category_id: UUID display_order: int = 0 is_visible: bool = True # Schema for creating an event-category association class EventGiftCategoryCreate(EventGiftCategoryBase): pass # Schema for updating an event-category association class EventGiftCategoryUpdate(BaseModel): display_order: Optional[int] = None is_visible: Optional[bool] = None # Schema for reading an event-category association class EventGiftCategoryInDB(EventGiftCategoryBase): created_at: datetime class Config: from_attributes = True # Public category response with statistics class GiftCategory(GiftCategoryInDB): # These properties will be calculated for a specific event in the API total_gifts: Optional[int] = None available_gifts: Optional[int] = None gifts: Optional[List[GiftItem]] = None # For display in a specific event context display_order: Optional[int] = None is_visible: Optional[bool] = None class Config: from_attributes = True # Gift Purchase Schemas class GiftPurchaseBase(BaseModel): gift_id: UUID guest_id: UUID quantity: int = 1 purchase_price: Optional[float] = None purchase_currency: Optional[str] = None notes: Optional[str] = None # Schema for creating a purchase class GiftPurchaseCreate(GiftPurchaseBase): pass # Schema for updating a purchase class GiftPurchaseUpdate(BaseModel): quantity: Optional[int] = None purchase_price: Optional[float] = None purchase_currency: Optional[str] = None notes: Optional[str] = None # Schema for reading a purchase class GiftPurchaseInDB(GiftPurchaseBase): id: UUID purchased_at: datetime class Config: from_attributes = True # Public gift purchase response class GiftPurchase(GiftPurchaseInDB): class Config: from_attributes = True