from pydantic import BaseModel, Field from typing import Optional, List from datetime import datetime # Brand schemas class BrandBase(BaseModel): name: str class BrandCreate(BrandBase): pass class BrandUpdate(BaseModel): name: Optional[str] = None class Brand(BrandBase): id: int created_at: datetime updated_at: Optional[datetime] = None class Config: from_attributes = True # BrandInShop schemas class BrandInShopBase(BaseModel): shop_id: int brand_id: int class BrandInShopCreate(BrandInShopBase): pass class BrandInShopUpdate(BaseModel): shop_id: Optional[int] = None brand_id: Optional[int] = None class BrandInShop(BrandInShopBase): id: int created_at: datetime updated_at: Optional[datetime] = None shop: "Shop" brand: "Brand" class Config: from_attributes = True # Grocery Category schemas class GroceryCategoryBase(BaseModel): name: str class GroceryCategoryCreate(GroceryCategoryBase): pass class GroceryCategoryUpdate(BaseModel): name: Optional[str] = None class GroceryCategory(GroceryCategoryBase): id: int created_at: datetime updated_at: Optional[datetime] = None class Config: from_attributes = True # Product schemas class ProductBase(BaseModel): name: str category_id: int brand_id: Optional[int] = None organic: bool = False weight: Optional[float] = None weight_unit: str = "g" class ProductCreate(ProductBase): pass class ProductUpdate(BaseModel): name: Optional[str] = None category_id: Optional[int] = None brand_id: Optional[int] = None organic: Optional[bool] = None weight: Optional[float] = None weight_unit: Optional[str] = None class Product(ProductBase): id: int created_at: datetime updated_at: Optional[datetime] = None category: GroceryCategory brand: Optional[Brand] = None class Config: from_attributes = True # Shop schemas class ShopBase(BaseModel): name: str city: str address: Optional[str] = None class ShopCreate(ShopBase): pass class ShopUpdate(BaseModel): name: Optional[str] = None city: Optional[str] = None address: Optional[str] = None class Shop(ShopBase): id: int created_at: datetime updated_at: Optional[datetime] = None class Config: from_attributes = True # Shopping Event schemas class ProductInEvent(BaseModel): product_id: int amount: float = Field(..., gt=0) price: float = Field(..., ge=0) # Price at the time of this shopping event (allow free items) class ProductWithEventData(BaseModel): id: int name: str category: GroceryCategory brand: Optional[Brand] = None organic: bool weight: Optional[float] = None weight_unit: str amount: float # Amount purchased in this event price: float # Price at the time of this event class Config: from_attributes = True class ShoppingEventBase(BaseModel): shop_id: int date: Optional[datetime] = None total_amount: Optional[float] = Field(None, ge=0) notes: Optional[str] = None class ShoppingEventCreate(ShoppingEventBase): products: List[ProductInEvent] = [] class ShoppingEventUpdate(BaseModel): shop_id: Optional[int] = None date: Optional[datetime] = None total_amount: Optional[float] = Field(None, ge=0) notes: Optional[str] = None products: Optional[List[ProductInEvent]] = None class ShoppingEventResponse(ShoppingEventBase): id: int created_at: datetime updated_at: Optional[datetime] = None shop: Shop products: List[ProductWithEventData] = [] class Config: from_attributes = True # Statistics schemas class CategoryStats(BaseModel): category: str total_spent: float item_count: int avg_price: float class ShopStats(BaseModel): shop_name: str total_spent: float visit_count: int avg_per_visit: float # Update forward references BrandInShop.model_rebuild() ProductWithRelated.model_rebuild() # Related Products schemas class RelatedProductBase(BaseModel): product_id: int related_product_id: int relationship_type: Optional[str] = None class RelatedProductCreate(RelatedProductBase): pass class RelatedProductUpdate(BaseModel): relationship_type: Optional[str] = None class RelatedProduct(RelatedProductBase): id: int created_at: datetime class Config: from_attributes = True # Product with related products class ProductWithRelated(Product): related_products: List["Product"] = [] class Config: from_attributes = True