feat: initial commit — local services (backend + manager dashboard + waiter PWA)
Includes all work to date: - local_backend: FastAPI backend with products, orders, tables, shifts, cloud sync - manager_dashboard: React manager UI with product/category management, reports, settings - waiter_pwa: React PWA for waiter devices - Category reparent endpoint and UI - Waiter domain: local_ip sent on heartbeat, waiter_domain persisted from cloud response - QR code modal in AppInfoTab for waiter domain - Product form: number input spinners removed, category pre-selected on new product - Category row: count badge moved to far right Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
87
local_backend/schemas/table.py
Normal file
87
local_backend/schemas/table.py
Normal file
@@ -0,0 +1,87 @@
|
||||
from pydantic import BaseModel, field_validator
|
||||
from typing import Optional, List
|
||||
|
||||
MAX_TABLE_NAME_LENGTH = 6
|
||||
|
||||
|
||||
class TableGroupCreate(BaseModel):
|
||||
name: str
|
||||
prefix: Optional[str] = None
|
||||
color: Optional[str] = None
|
||||
|
||||
|
||||
class TableGroupUpdate(BaseModel):
|
||||
name: Optional[str] = None
|
||||
prefix: Optional[str] = None
|
||||
color: Optional[str] = None
|
||||
|
||||
|
||||
class TableGroupOut(BaseModel):
|
||||
id: int
|
||||
name: str
|
||||
prefix: Optional[str] = None
|
||||
sort_order: int = 0
|
||||
color: Optional[str] = None
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
||||
class TableBase(BaseModel):
|
||||
label: Optional[str] = None
|
||||
group_id: Optional[int] = None
|
||||
is_active: bool = True
|
||||
|
||||
|
||||
class TableCreate(BaseModel):
|
||||
label: Optional[str] = None
|
||||
group_id: Optional[int] = None
|
||||
|
||||
@field_validator("label")
|
||||
@classmethod
|
||||
def label_max_length(cls, v):
|
||||
if v is not None:
|
||||
v = v.strip()
|
||||
if len(v) > MAX_TABLE_NAME_LENGTH:
|
||||
raise ValueError(f"Table name cannot exceed {MAX_TABLE_NAME_LENGTH} characters")
|
||||
return v
|
||||
|
||||
|
||||
class TableBatchCreate(BaseModel):
|
||||
group_id: Optional[int] = None
|
||||
count: int
|
||||
name_prefix: str # e.g. "TBL-" → TBL-1, TBL-2 ...
|
||||
# start_number is computed on the backend from existing tables in the group
|
||||
|
||||
|
||||
class TableUpdate(BaseModel):
|
||||
label: Optional[str] = None
|
||||
group_id: Optional[int] = None
|
||||
is_active: Optional[bool] = None
|
||||
|
||||
@field_validator("label")
|
||||
@classmethod
|
||||
def label_max_length(cls, v):
|
||||
if v is not None:
|
||||
v = v.strip()
|
||||
if len(v) > MAX_TABLE_NAME_LENGTH:
|
||||
raise ValueError(f"Table name cannot exceed {MAX_TABLE_NAME_LENGTH} characters")
|
||||
return v
|
||||
|
||||
|
||||
class TableFloorplanUpdate(BaseModel):
|
||||
floor_x: float
|
||||
floor_y: float
|
||||
|
||||
|
||||
class TableOut(BaseModel):
|
||||
id: int
|
||||
number: int
|
||||
label: Optional[str] = None
|
||||
group_id: Optional[int] = None
|
||||
is_active: bool = True
|
||||
floor_x: Optional[float] = None
|
||||
floor_y: Optional[float] = None
|
||||
group: Optional[TableGroupOut] = None
|
||||
has_active_order: bool = False
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
Reference in New Issue
Block a user