groceries/backend/schemas.py
lasse 2fadb2d991 feat: Implement comprehensive edit functionality and standardize UI components
• Add full edit functionality for groceries with modal support
• Standardize delete confirmations across all components using ConfirmDeleteModal
• Implement complete shopping event edit functionality:
  - Create EditShoppingEvent component with full form capabilities
  - Add missing backend PUT endpoint for shopping events
  - Support editing all event data (shop, date, groceries, amounts, prices, notes)
• Add inline grocery edit functionality in shopping event forms:
  - Allow editing grocery items within add/edit forms
  - Load selected items back into input fields for modification
• Fix date timezone issues in edit forms to prevent date shifting
• Remove non-functional "View Details" button in favor of working Edit button
• Enhance user experience with consistent edit/delete patterns across the app

Breaking changes: None
Backend: Added PUT /shopping-events/{id} and DELETE /shopping-events/{id} endpoints
Frontend: Complete edit workflow for all entities with improved UX
2025-05-25 18:51:47 +02:00

107 lines
2.5 KiB
Python

from pydantic import BaseModel, Field
from typing import Optional, List
from datetime import datetime
# Base schemas
class GroceryBase(BaseModel):
name: str
category: str
organic: bool = False
weight: Optional[float] = None
weight_unit: str = "g"
class GroceryCreate(GroceryBase):
pass
class GroceryUpdate(BaseModel):
name: Optional[str] = None
category: Optional[str] = None
organic: Optional[bool] = None
weight: Optional[float] = None
weight_unit: Optional[str] = None
class Grocery(GroceryBase):
id: int
created_at: datetime
updated_at: Optional[datetime] = 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
class Config:
from_attributes = True
# Shopping Event schemas
class GroceryInEvent(BaseModel):
grocery_id: int
amount: float = Field(..., gt=0)
price: float = Field(..., gt=0) # Price at the time of this shopping event
class GroceryWithEventData(BaseModel):
id: int
name: str
category: str
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):
groceries: List[GroceryInEvent] = []
class ShoppingEventUpdate(BaseModel):
shop_id: Optional[int] = None
date: Optional[datetime] = None
total_amount: Optional[float] = Field(None, ge=0)
notes: Optional[str] = None
groceries: Optional[List[GroceryInEvent]] = None
class ShoppingEventResponse(ShoppingEventBase):
id: int
created_at: datetime
shop: Shop
groceries: List[GroceryWithEventData] = []
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