kitchen/backend/models/user.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

94 lines
4.3 KiB
Python

from datetime import datetime
from sqlalchemy import String, DateTime, ForeignKey, Boolean
from sqlalchemy.orm import Mapped, mapped_column, relationship
from database import Base
class Kitchen(Base):
__tablename__ = "kitchens"
id: Mapped[int] = mapped_column(primary_key=True, index=True)
name: Mapped[str] = mapped_column(String(255), nullable=False)
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
# Relationships
users: Mapped[list["User"]] = relationship("User", back_populates="kitchen")
suppliers: Mapped[list["Supplier"]] = relationship("Supplier", back_populates="kitchen")
invoices: Mapped[list["Invoice"]] = relationship("Invoice", back_populates="kitchen")
revenue_entries: Mapped[list["RevenueEntry"]] = relationship("RevenueEntry", back_populates="kitchen")
gp_periods: Mapped[list["GPPeriod"]] = relationship("GPPeriod", back_populates="kitchen")
settings: Mapped["KitchenSettings"] = relationship("KitchenSettings", back_populates="kitchen", uselist=False)
# Newbook relationships
newbook_gl_accounts: Mapped[list["NewbookGLAccount"]] = relationship(
"NewbookGLAccount", back_populates="kitchen", cascade="all, delete-orphan"
)
newbook_daily_revenue: Mapped[list["NewbookDailyRevenue"]] = relationship(
"NewbookDailyRevenue", back_populates="kitchen", cascade="all, delete-orphan"
)
newbook_daily_occupancy: Mapped[list["NewbookDailyOccupancy"]] = relationship(
"NewbookDailyOccupancy", back_populates="kitchen", cascade="all, delete-orphan"
)
newbook_sync_logs: Mapped[list["NewbookSyncLog"]] = relationship(
"NewbookSyncLog", back_populates="kitchen", cascade="all, delete-orphan"
)
newbook_room_categories: Mapped[list["NewbookRoomCategory"]] = relationship(
"NewbookRoomCategory", back_populates="kitchen", cascade="all, delete-orphan"
)
# Resos relationships
resos_bookings: Mapped[list["ResosBooking"]] = relationship(
"ResosBooking", back_populates="kitchen", cascade="all, delete-orphan"
)
resos_daily_stats: Mapped[list["ResosDailyStats"]] = relationship(
"ResosDailyStats", back_populates="kitchen", cascade="all, delete-orphan"
)
resos_opening_hours: Mapped[list["ResosOpeningHour"]] = relationship(
"ResosOpeningHour", back_populates="kitchen", cascade="all, delete-orphan"
)
resos_sync_logs: Mapped[list["ResosSyncLog"]] = relationship(
"ResosSyncLog", back_populates="kitchen", cascade="all, delete-orphan"
)
# Dispute tracking relationships
invoice_disputes: Mapped[list["InvoiceDispute"]] = relationship(
"InvoiceDispute", back_populates="kitchen", cascade="all, delete-orphan"
)
# Logbook relationships
logbook_entries: Mapped[list["LogbookEntry"]] = relationship(
"LogbookEntry", back_populates="kitchen", cascade="all, delete-orphan"
)
# Email processing logs (IMAP inbox sync)
email_processing_logs: Mapped[list["EmailProcessingLog"]] = relationship(
"EmailProcessingLog", back_populates="kitchen", cascade="all, delete-orphan"
)
class User(Base):
__tablename__ = "users"
id: Mapped[int] = mapped_column(primary_key=True, index=True)
email: Mapped[str] = mapped_column(String(255), unique=True, nullable=False, index=True)
password_hash: Mapped[str] = mapped_column(String(255), nullable=False)
name: Mapped[str] = mapped_column(String(255), nullable=True)
is_active: Mapped[bool] = mapped_column(Boolean, default=True)
is_admin: Mapped[bool] = mapped_column(Boolean, default=False)
kitchen_id: Mapped[int] = mapped_column(ForeignKey("kitchens.id"), nullable=False)
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
# Relationships
kitchen: Mapped["Kitchen"] = relationship("Kitchen", back_populates="users")
# Forward references for relationships
from .supplier import Supplier
from .invoice import Invoice
from .gp import RevenueEntry, GPPeriod
from .settings import KitchenSettings
from .newbook import NewbookGLAccount, NewbookDailyRevenue, NewbookDailyOccupancy, NewbookSyncLog, NewbookRoomCategory
from .resos import ResosBooking, ResosDailyStats, ResosOpeningHour, ResosSyncLog
from .dispute import InvoiceDispute
from .logbook import LogbookEntry
from .email_processing import EmailProcessingLog