kitchen/backend/models/cover_override.py
jtricerolph 8d688b459d 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>
2026-07-12 12:15:39 +00:00

88 lines
4 KiB
Python

"""
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"),
)