✅ New functionality added (soft delete system) ✅ Backward compatible (existing features unchanged) ✅ Significant enhancement (complete temporal tracking system) ✅ API additions (new endpoints, parameters) ✅ UI enhancements (new components, visual indicators)
255 lines
6.1 KiB
Python
255 lines
6.1 KiB
Python
from pydantic import BaseModel, Field
|
|
from typing import Optional, List
|
|
from datetime import datetime, date
|
|
|
|
# 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):
|
|
valid_from: Optional[date] = None # If not provided, will use current date
|
|
|
|
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
|
|
valid_from: Optional[date] = None # If not provided, will use current date
|
|
|
|
class Product(ProductBase):
|
|
id: int
|
|
created_at: datetime
|
|
updated_at: Optional[datetime] = None
|
|
category: GroceryCategory
|
|
brand: Optional[Brand] = None
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
# Historical Product schemas
|
|
class ProductHistory(BaseModel):
|
|
history_id: int
|
|
id: int # Original product ID
|
|
name: str
|
|
category_id: int
|
|
brand_id: Optional[int] = None
|
|
organic: bool = False
|
|
weight: Optional[float] = None
|
|
weight_unit: str = "g"
|
|
created_at: Optional[datetime] = None
|
|
updated_at: Optional[datetime] = None
|
|
valid_from: date
|
|
valid_to: date
|
|
deleted: bool
|
|
operation: str # 'U' for Update, 'D' for Delete
|
|
archived_at: datetime
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
class ProductAtDate(BaseModel):
|
|
id: int
|
|
name: str
|
|
category_id: int
|
|
category: GroceryCategory
|
|
brand_id: Optional[int] = None
|
|
brand: Optional[Brand] = None
|
|
organic: bool = False
|
|
weight: Optional[float] = None
|
|
weight_unit: str = "g"
|
|
valid_from: date
|
|
valid_to: date
|
|
deleted: bool
|
|
was_current: bool # True if from current table, False if from history
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
class ProductAtPurchase(BaseModel):
|
|
product: ProductAtDate
|
|
amount: float
|
|
price: float
|
|
discount: bool
|
|
|
|
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)
|
|
discount: bool = False # Whether this product was purchased with a discount
|
|
|
|
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
|
|
discount: bool # Whether this product was purchased with a discount
|
|
|
|
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()
|
|
|
|
# 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
|
|
|
|
# Update forward references for classes that reference other classes
|
|
ProductWithRelated.model_rebuild() |