Backend:
- OrderItemInput accepts option objects {id,name,price_delta} instead of int IDs
- extra_cost from selected options added to unit_price snapshot
- GET /api/products/?all=true for manager (includes unavailable)
- PUT /api/products/{id} now replaces options, ingredients, preference_sets
- POST /api/products/{id}/image — persistent image upload to /app/data/product_images
- New models: ProductPreferenceSet, ProductPreferenceChoice, TableGroup
- tables: group_id FK, hard delete (?hard=true), batch create POST /api/tables/batch
- GET /api/tables/groups + POST/PUT/DELETE groups endpoints
- POST /api/auth/me endpoint for token rehydration
- Auto-migration on startup for new columns
PWA:
- AuthRehydrator: fetches /auth/me on load so isMyOrder works after page reload
- 401 response force-logs out (covers blocked waiters)
- ItemOptionsModal: uses extra_cost correctly, shows preferences as radio buttons
Manager:
- ProductsPage: shows unavailable products greyed out, category color picker + reorder,
full option/ingredient/preference editing, image upload
- TablesPage: table groups, auto-increment, deactivate vs hard delete, batch add
58 lines
1.1 KiB
Python
58 lines
1.1 KiB
Python
from pydantic import BaseModel
|
|
from typing import Optional, List
|
|
|
|
|
|
class TableGroupCreate(BaseModel):
|
|
name: str
|
|
|
|
|
|
class TableGroupUpdate(BaseModel):
|
|
name: Optional[str] = None
|
|
|
|
|
|
class TableGroupOut(BaseModel):
|
|
id: int
|
|
name: str
|
|
sort_order: int = 0
|
|
|
|
model_config = {"from_attributes": True}
|
|
|
|
|
|
class TableBase(BaseModel):
|
|
number: int
|
|
label: Optional[str] = None
|
|
group_id: Optional[int] = None
|
|
is_active: bool = True
|
|
|
|
|
|
class TableCreate(TableBase):
|
|
pass
|
|
|
|
|
|
class TableBatchCreate(BaseModel):
|
|
group_id: Optional[int] = None
|
|
count: int
|
|
name_prefix: str # e.g. "Out-" → Out-1, Out-2 ...
|
|
start_number: int = 1
|
|
|
|
|
|
class TableUpdate(BaseModel):
|
|
number: Optional[int] = None
|
|
label: Optional[str] = None
|
|
group_id: Optional[int] = None
|
|
is_active: Optional[bool] = None
|
|
|
|
|
|
class TableFloorplanUpdate(BaseModel):
|
|
floor_x: float
|
|
floor_y: float
|
|
|
|
|
|
class TableOut(TableBase):
|
|
id: int
|
|
floor_x: Optional[float] = None
|
|
floor_y: Optional[float] = None
|
|
group: Optional[TableGroupOut] = None
|
|
|
|
model_config = {"from_attributes": True}
|