Initial kitchen scaffold — Phase 1 kitchen port (build-verified 2026-07-11)
FastAPI backend (Python 3.11, MSSQL ODBC for SambaPOS, Azure DI OCR),
kitchen_db on central PG. React/TS/Vite frontend with navy sidebar layout.
Backend: auth.py (APP_SLUG=kitchen, SimpleNamespace — archive routes use
.kitchen_id/.is_admin without modification), main.py (51 migrations, scheduler,
internal router for KDS bookings feed), api/internal.py, full archive API
(31 routers: invoices, recipes, menus, sambapos, resos, newbook, disputes,
purchase_orders, etc.), models, migrations, OCR pipeline.
kitchen_id pinned to 1 (B1 — single hotel).
Frontend: AuthGate (app=kitchen, token shim for archive compat — B5b pending),
Layout (navy sidebar, 6 sections, Lucide icons, teal --app-primary),
App.tsx (Outlet pattern, UploadApp outside Layout), index.css (full :root block).
strict: false — archive components have type issues; build clean.
Note: 45 archive components call fetch('/api/...') without /kitchen/ prefix
(B5b). Runtime 404s; deferred until after initial testing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
commit
8d688b459d
10003 changed files with 1928395 additions and 0 deletions
88
backend/models/cover_override.py
Normal file
88
backend/models/cover_override.py
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
"""
|
||||
Models for cover override and forecast snapshot tables.
|
||||
|
||||
Tables:
|
||||
- cover_overrides: Per-day per-period cover overrides (lunch/dinner)
|
||||
- forecast_snapshots: Per-day per-period snapshot of forecast at snapshot time
|
||||
- forecast_week_snapshots: Weekly revenue totals at snapshot time
|
||||
- spend_rate_overrides: Per-week per-period spend rate overrides
|
||||
"""
|
||||
from sqlalchemy import Column, Integer, String, Numeric, Date, DateTime, ForeignKey, UniqueConstraint
|
||||
from sqlalchemy.sql import func
|
||||
from database import Base
|
||||
|
||||
|
||||
class CoverOverride(Base):
|
||||
__tablename__ = "cover_overrides"
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
kitchen_id = Column(Integer, ForeignKey("kitchens.id"), nullable=False)
|
||||
override_date = Column(Date, nullable=False)
|
||||
period = Column(String(20), nullable=False) # 'lunch' or 'dinner'
|
||||
override_covers = Column(Integer, nullable=False) # target total covers (0 = expect zero)
|
||||
original_forecast = Column(Integer) # snapshot at creation time
|
||||
original_otb = Column(Integer) # snapshot at creation time
|
||||
created_by = Column(Integer, ForeignKey("users.id"))
|
||||
created_at = Column(DateTime, server_default=func.now())
|
||||
updated_by = Column(Integer, ForeignKey("users.id"))
|
||||
updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now())
|
||||
|
||||
__table_args__ = (
|
||||
UniqueConstraint("kitchen_id", "override_date", "period", name="uq_cover_override_date_period"),
|
||||
)
|
||||
|
||||
|
||||
class ForecastSnapshot(Base):
|
||||
__tablename__ = "forecast_snapshots"
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
kitchen_id = Column(Integer, ForeignKey("kitchens.id"), nullable=False)
|
||||
snapshot_date = Column(Date, nullable=False) # the forecasted date
|
||||
period = Column(String(20), nullable=False) # 'breakfast', 'lunch', or 'dinner'
|
||||
forecast_covers = Column(Integer, nullable=False) # total forecast (otb+pickup)
|
||||
otb_covers = Column(Integer, nullable=False) # OTB at snapshot time
|
||||
food_spend = Column(Numeric(10, 2)) # food spend per cover (net ex VAT)
|
||||
drinks_spend = Column(Numeric(10, 2)) # drinks spend per cover (net ex VAT)
|
||||
forecast_dry_revenue = Column(Numeric(10, 2)) # forecast dry revenue for this day/period
|
||||
week_start = Column(Date, nullable=False)
|
||||
created_at = Column(DateTime, server_default=func.now())
|
||||
|
||||
__table_args__ = (
|
||||
UniqueConstraint("kitchen_id", "snapshot_date", "period", name="uq_forecast_snapshot_date_period"),
|
||||
)
|
||||
|
||||
|
||||
class ForecastWeekSnapshot(Base):
|
||||
__tablename__ = "forecast_week_snapshots"
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
kitchen_id = Column(Integer, ForeignKey("kitchens.id"), nullable=False)
|
||||
week_start = Column(Date, nullable=False)
|
||||
total_forecast_revenue = Column(Numeric(12, 2)) # total dry revenue for the week
|
||||
total_otb_revenue = Column(Numeric(12, 2)) # OTB-only revenue for the week
|
||||
gp_target = Column(Numeric(5, 2)) # GP target % at snapshot time
|
||||
created_at = Column(DateTime, server_default=func.now())
|
||||
updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now())
|
||||
|
||||
__table_args__ = (
|
||||
UniqueConstraint("kitchen_id", "week_start", name="uq_forecast_week_snapshot"),
|
||||
)
|
||||
|
||||
|
||||
class SpendRateOverride(Base):
|
||||
__tablename__ = "spend_rate_overrides"
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
kitchen_id = Column(Integer, ForeignKey("kitchens.id"), nullable=False)
|
||||
week_start = Column(Date, nullable=False)
|
||||
period = Column(String(20), nullable=False) # 'breakfast', 'lunch', or 'dinner'
|
||||
food_spend = Column(Numeric(10, 2)) # overridden food spend per cover (NULL = use snapshot/API)
|
||||
drinks_spend = Column(Numeric(10, 2)) # overridden drinks spend per cover (NULL = use snapshot/API)
|
||||
created_by = Column(Integer, ForeignKey("users.id"))
|
||||
created_at = Column(DateTime, server_default=func.now())
|
||||
updated_by = Column(Integer, ForeignKey("users.id"))
|
||||
updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now())
|
||||
|
||||
__table_args__ = (
|
||||
UniqueConstraint("kitchen_id", "week_start", "period", name="uq_spend_rate_override"),
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue