""" KDS settings endpoints served by the kitchen backend. The kitchen Settings page configures KDS (timers, GraphQL URL, course order, etc.) via /kitchen/api/kds/settings. All KDS config lives in kitchen_settings — so these endpoints belong here, not in the KDS backend. """ from datetime import datetime from typing import Optional from fastapi import APIRouter, Depends, HTTPException from pydantic import BaseModel from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from auth import get_current_user, require_cap from database import get_db from models.settings import KitchenSettings from models.user import User router = APIRouter() class KDSSettingsResponse(BaseModel): kds_enabled: bool = False kds_graphql_url: Optional[str] = None kds_graphql_username: Optional[str] = None kds_graphql_password_set: bool = False kds_graphql_client_id: Optional[str] = None kds_poll_interval_seconds: int = 6000 kds_timer_green_seconds: int = 300 kds_timer_amber_seconds: int = 600 kds_timer_red_seconds: int = 900 kds_away_timer_green_seconds: int = 600 kds_away_timer_amber_seconds: int = 900 kds_away_timer_red_seconds: int = 1200 kds_course_order: list = ["Starters", "Mains", "Desserts"] kds_show_completed_for_seconds: int = 30 kds_bookings_refresh_seconds: int = 60 class Config: from_attributes = True class KDSSettingsUpdate(BaseModel): kds_enabled: Optional[bool] = None kds_graphql_url: Optional[str] = None kds_graphql_username: Optional[str] = None kds_graphql_password: Optional[str] = None kds_graphql_client_id: Optional[str] = None kds_poll_interval_seconds: Optional[int] = None kds_timer_green_seconds: Optional[int] = None kds_timer_amber_seconds: Optional[int] = None kds_timer_red_seconds: Optional[int] = None kds_away_timer_green_seconds: Optional[int] = None kds_away_timer_amber_seconds: Optional[int] = None kds_away_timer_red_seconds: Optional[int] = None kds_course_order: Optional[list] = None kds_show_completed_for_seconds: Optional[int] = None kds_bookings_refresh_seconds: Optional[int] = None def _normalize_course_config(course_order: list, s: KitchenSettings) -> list: result = [] for entry in course_order: if isinstance(entry, str): result.append({ "name": entry, "prep_green": s.kds_timer_green_seconds or 300, "prep_amber": s.kds_timer_amber_seconds or 600, "prep_red": s.kds_timer_red_seconds or 900, "away_green": s.kds_away_timer_green_seconds or 600, "away_amber": s.kds_away_timer_amber_seconds or 900, "away_red": s.kds_away_timer_red_seconds or 1200, }) elif isinstance(entry, dict) and "name" in entry: result.append(entry) return result async def _get_settings(db: AsyncSession, kitchen_id: int): result = await db.execute( select(KitchenSettings).where(KitchenSettings.kitchen_id == kitchen_id) ) return result.scalar_one_or_none() def _to_response(s: KitchenSettings) -> KDSSettingsResponse: raw = s.kds_course_order or ["Starters", "Mains", "Desserts"] return KDSSettingsResponse( kds_enabled=s.kds_enabled or False, kds_graphql_url=s.kds_graphql_url, kds_graphql_username=s.kds_graphql_username, kds_graphql_password_set=bool(s.kds_graphql_password), kds_graphql_client_id=s.kds_graphql_client_id, kds_poll_interval_seconds=s.kds_poll_interval_seconds or 6000, kds_timer_green_seconds=s.kds_timer_green_seconds or 300, kds_timer_amber_seconds=s.kds_timer_amber_seconds or 600, kds_timer_red_seconds=s.kds_timer_red_seconds or 900, kds_away_timer_green_seconds=s.kds_away_timer_green_seconds or 600, kds_away_timer_amber_seconds=s.kds_away_timer_amber_seconds or 900, kds_away_timer_red_seconds=s.kds_away_timer_red_seconds or 1200, kds_course_order=_normalize_course_config(raw, s), kds_show_completed_for_seconds=s.kds_show_completed_for_seconds or 30, kds_bookings_refresh_seconds=s.kds_bookings_refresh_seconds or 60, ) @router.get("/settings", response_model=KDSSettingsResponse) async def get_kds_settings( current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): s = await _get_settings(db, current_user.kitchen_id) if not s: return KDSSettingsResponse() return _to_response(s) @router.patch("/settings", response_model=KDSSettingsResponse) async def update_kds_settings( update: KDSSettingsUpdate, current_user: User = Depends(require_cap("settings")), db: AsyncSession = Depends(get_db), ): s = await _get_settings(db, current_user.kitchen_id) if not s: raise HTTPException(status_code=404, detail="Kitchen settings not found") for field, value in update.model_dump(exclude_unset=True).items(): if hasattr(s, field): setattr(s, field, value) s.updated_at = datetime.utcnow() await db.commit() await db.refresh(s) return _to_response(s)