fix(dashboard): resolve 500 internal server error on production server

- Add SafeStats fallback wrapper to prevent QWeb KeyError exceptions
- Safely resolve dictionary keys with .get() across all dashboard templates
- Add support for production SaaS master database 'dine360db'
- Add route mapping for '/dashboard' alongside '/'
- Remove invalid tracking attribute from restaurant.table is_occupied field
This commit is contained in:
Alaguraj0361 2026-10-12 12:42:32 +05:30
parent 1929e81878
commit 42abb214ac
6 changed files with 67 additions and 59 deletions

View File

@ -17,14 +17,19 @@ class MenuWrapper:
class SafeStats(dict):
def __missing__(self, key):
if any(term in key for term in ['list', 'recent', 'products', 'orders', 'tables', 'reservations']):
if any(term in key for term in ['list', 'recent', 'products', 'orders', 'tables', 'reservations', 'floors', 'activities']):
return []
if any(term in key for term in ['count', 'total', 'capacity', 'rate', 'active', 'provisioning', 'expired']):
if any(term in key for term in ['count', 'total', 'capacity', 'rate', 'active', 'provisioning', 'expired', 'occupied', 'available', 'seats', 'percent']):
return 0
if 'formatted' in key:
return '$0.00'
if any(term in key for term in ['formatted', 'value', 'avg', 'revenue', 'price', 'ticket']):
return '₹0.00'
return ''
def get(self, key, default=None):
if key in self:
return self[key]
return self.__missing__(key) if default is None else default
class CustomHome(Home):
@http.route('/web/login', type='http', auth="public")
def web_login(self, *args, **kw):
@ -35,9 +40,12 @@ class CustomHome(Home):
def get_dashboard_context(active_page='dashboard'):
"""Helper to collect unified metrics and data for all Dine360 dashboard pages."""
db_name = request.env.cr.dbname or ''
is_saas_master = ('Dine360Restaurants' in db_name) or (
'saas.restaurant' in request.env and bool(request.env['saas.restaurant'].sudo().search_count([]))
db_name = (request.env.cr.dbname or '').lower()
is_saas_master = (
'dine360restaurants' in db_name or
'dine360db' in db_name or
'saas' in db_name or
('saas.restaurant' in request.env)
)
user = request.env.user.sudo()
@ -345,17 +353,17 @@ def get_dashboard_context(active_page='dashboard'):
'active_page': active_page,
'user_id': user,
'is_saas_master': is_saas_master,
'saas_stats': saas_stats,
'saas_dashboard_data': saas_dashboard_data,
'saas_stats': SafeStats(saas_stats),
'saas_dashboard_data': SafeStats(saas_dashboard_data),
'onboarded_restaurants': onboarded_restaurants,
'plans': plans,
'table_stats': table_stats,
'table_stats': SafeStats(table_stats),
'tables': tables_list,
'available_tables': [t for t in tables_list if not t.get('is_occupied')],
'floors': floors_list,
'reservation_stats': reservation_stats,
'reservation_stats': SafeStats(reservation_stats),
'reservations': reservations_list,
'online_orders_data': online_orders_data,
'online_orders_data': SafeStats(online_orders_data),
'current_date_str': datetime.now().strftime('%d %b %Y'),
'stats': stats,
'low_stock_products': low_stock,
@ -384,7 +392,7 @@ class Dine360DashboardController(http.Controller):
# -------------------------------------------------------------
# 1. Main Home & Overview
# -------------------------------------------------------------
@http.route('/', type='http', auth='user', website=True)
@http.route(['/', '/dashboard'], type='http', auth='user', website=True)
def index(self, **kwargs):
return render_dashboard(request)

View File

@ -62,7 +62,7 @@
<span class="o_kpi_trend text-danger"><i class="fa fa-arrow-up"/> +0%</span>
</div>
<div class="o_kpi_label">Total Restaurants</div>
<div class="o_kpi_number"><t t-esc="saas_stats['total']"/></div>
<div class="o_kpi_number"><t t-esc="saas_stats.get('total', 0)"/></div>
<div class="o_kpi_footer">
<span class="o_kpi_sub">Currently onboarded</span>
<svg class="o_sparkline" viewBox="0 0 100 30" preserveAspectRatio="none">
@ -80,7 +80,7 @@
<span class="o_kpi_trend text-success"><i class="fa fa-arrow-up"/> +0%</span>
</div>
<div class="o_kpi_label">Active Subscriptions</div>
<div class="o_kpi_number"><t t-esc="saas_stats['active']"/></div>
<div class="o_kpi_number"><t t-esc="saas_stats.get('active', 0)"/></div>
<div class="o_kpi_footer">
<span class="o_kpi_sub">Running smoothly</span>
<svg class="o_sparkline" viewBox="0 0 100 30" preserveAspectRatio="none">
@ -98,7 +98,7 @@
<span class="o_kpi_trend text-warning"><i class="fa fa-arrow-up"/> +0%</span>
</div>
<div class="o_kpi_label">Provisioning</div>
<div class="o_kpi_number"><t t-esc="saas_stats['provisioning']"/></div>
<div class="o_kpi_number"><t t-esc="saas_stats.get('provisioning', 0)"/></div>
<div class="o_kpi_footer">
<span class="o_kpi_sub">In progress</span>
<svg class="o_sparkline" viewBox="0 0 100 30" preserveAspectRatio="none">
@ -116,7 +116,7 @@
<span class="o_kpi_trend text-muted"><i class="fa fa-arrow-up"/> +0%</span>
</div>
<div class="o_kpi_label">Expired / Suspended</div>
<div class="o_kpi_number"><t t-esc="saas_stats['expired']"/></div>
<div class="o_kpi_number"><t t-esc="saas_stats.get('expired', 0)"/></div>
<div class="o_kpi_footer">
<span class="o_kpi_sub">Requires attention</span>
<svg class="o_sparkline" viewBox="0 0 100 30" preserveAspectRatio="none">
@ -197,7 +197,7 @@
<div>
<div class="o_substat_title">Active Restaurants</div>
<div class="d-flex align-items-center gap-2">
<span class="o_substat_val"><t t-esc="saas_stats['active']"/></span>
<span class="o_substat_val"><t t-esc="saas_stats.get('active', 0)"/></span>
<span class="o_substat_pct text-success"><i class="fa fa-arrow-up"/> 100%</span>
</div>
</div>
@ -210,7 +210,7 @@
<div>
<div class="o_substat_title">Total Orders</div>
<div class="d-flex align-items-center gap-2">
<span class="o_substat_val"><t t-esc="saas_dashboard_data['orders_count']"/></span>
<span class="o_substat_val"><t t-esc="saas_dashboard_data.get('orders_count', 0)"/></span>
<span class="o_substat_pct text-success"><i class="fa fa-arrow-up"/> +8%</span>
</div>
</div>
@ -223,7 +223,7 @@
<div>
<div class="o_substat_title">Avg. Order Value</div>
<div class="d-flex align-items-center gap-2">
<span class="o_substat_val"><t t-esc="saas_dashboard_data['avg_order_value']"/></span>
<span class="o_substat_val"><t t-esc="saas_dashboard_data.get('avg_order_value', '₹0.00')"/></span>
<span class="o_substat_pct text-success"><i class="fa fa-arrow-up"/> +6%</span>
</div>
</div>
@ -344,7 +344,7 @@
<div class="o_card_header">
<div class="d-flex align-items-center gap-2">
<h3 class="o_card_title mb-0">Onboarded Restaurants</h3>
<span class="o_count_pill"><t t-esc="saas_stats['total']"/> Registered</span>
<span class="o_count_pill"><t t-esc="saas_stats.get('total', 0)"/> Registered</span>
</div>
<div class="d-flex align-items-center gap-2">
<button type="button" class="o_btn_red_small" data-open-modal="modalOnboardRestaurant">
@ -507,7 +507,7 @@
<!-- Page Title & Status Header -->
<section class="o_page_header">
<div>
<h1 class="o_heading_title"><t t-esc="stats['company_name']"/> Dashboard</h1>
<h1 class="o_heading_title"><t t-esc="stats.get('company_name', 'Dine360')"/> Dashboard</h1>
<p class="o_heading_subtitle">Live restaurant operations, online orders, and table status</p>
</div>
<div class="o_header_controls">
@ -541,7 +541,7 @@
<span class="o_kpi_trend text-danger"><i class="fa fa-arrow-up"/> +14%</span>
</div>
<div class="o_kpi_label">Online Orders</div>
<div class="o_kpi_number"><t t-esc="online_orders_data['today_count']"/></div>
<div class="o_kpi_number"><t t-esc="online_orders_data.get('today_count', 0)"/></div>
<div class="o_kpi_footer">
<span class="o_kpi_sub">Received from website</span>
<svg class="o_sparkline" viewBox="0 0 100 30" preserveAspectRatio="none">
@ -559,7 +559,7 @@
<span class="o_kpi_trend text-success"><i class="fa fa-arrow-up"/> +8%</span>
</div>
<div class="o_kpi_label">Today's Revenue</div>
<div class="o_kpi_number"><t t-esc="online_orders_data['total_revenue_formatted']"/></div>
<div class="o_kpi_number"><t t-esc="online_orders_data.get('total_revenue_formatted', '₹0.00')"/></div>
<div class="o_kpi_footer">
<span class="o_kpi_sub">Across POS &amp; Online</span>
<svg class="o_sparkline" viewBox="0 0 100 30" preserveAspectRatio="none">
@ -577,7 +577,7 @@
<span class="o_kpi_trend text-warning"><i class="fa fa-arrow-up"/> 67%</span>
</div>
<div class="o_kpi_label">Occupied Tables</div>
<div class="o_kpi_number"><t t-esc="table_stats['occupied']"/> / <t t-esc="table_stats['total']"/></div>
<div class="o_kpi_number"><t t-esc="table_stats.get('occupied', 0)"/> / <t t-esc="table_stats.get('total', 0)"/></div>
<div class="o_kpi_footer">
<span class="o_kpi_sub">Active floor guests</span>
<svg class="o_sparkline" viewBox="0 0 100 30" preserveAspectRatio="none">
@ -595,7 +595,7 @@
<span class="o_kpi_trend text-danger"><i class="fa fa-exclamation-circle"/> Action</span>
</div>
<div class="o_kpi_label">Pending Orders</div>
<div class="o_kpi_number"><t t-esc="online_orders_data['pending_count']"/></div>
<div class="o_kpi_number"><t t-esc="online_orders_data.get('pending_count', 0)"/></div>
<div class="o_kpi_footer">
<span class="o_kpi_sub">Requires kitchen action</span>
<svg class="o_sparkline" viewBox="0 0 100 30" preserveAspectRatio="none">
@ -676,7 +676,7 @@
<div>
<div class="o_substat_title">Reservations</div>
<div class="d-flex align-items-center gap-2">
<span class="o_substat_val"><t t-esc="reservation_stats['total']"/></span>
<span class="o_substat_val"><t t-esc="reservation_stats.get('total', 0)"/></span>
<span class="o_substat_pct text-success"><i class="fa fa-arrow-up"/> Live</span>
</div>
</div>
@ -689,7 +689,7 @@
<div>
<div class="o_substat_title">Online Orders</div>
<div class="d-flex align-items-center gap-2">
<span class="o_substat_val"><t t-esc="online_orders_data['today_count']"/></span>
<span class="o_substat_val"><t t-esc="online_orders_data.get('today_count', 0)"/></span>
<span class="o_substat_pct text-success"><i class="fa fa-arrow-up"/> Live</span>
</div>
</div>
@ -702,7 +702,7 @@
<div>
<div class="o_substat_title">Avg. Ticket Value</div>
<div class="d-flex align-items-center gap-2">
<span class="o_substat_val"><t t-esc="online_orders_data['avg_order_value']"/></span>
<span class="o_substat_val"><t t-esc="online_orders_data.get('avg_order_value', '₹0.00')"/></span>
<span class="o_substat_pct text-success"><i class="fa fa-arrow-up"/> Live</span>
</div>
</div>
@ -859,7 +859,7 @@
<div class="o_card_header">
<div class="d-flex align-items-center gap-2">
<h3 class="o_card_title mb-0">Live Restaurant Online Orders</h3>
<span class="o_count_pill"><t t-esc="online_orders_data['today_count']"/> Active</span>
<span class="o_count_pill"><t t-esc="online_orders_data.get('today_count', 0)"/> Active</span>
</div>
<div class="d-flex align-items-center gap-2">
<a href="/shop" target="_blank" class="o_btn_red_small">

View File

@ -36,7 +36,7 @@
<span class="o_kpi_trend text-danger"><i class="fa fa-arrow-up"/> Live</span>
</div>
<div class="o_kpi_label">Total Bookings</div>
<div class="o_kpi_number"><t t-esc="reservation_stats['total']"/></div>
<div class="o_kpi_number"><t t-esc="reservation_stats.get('total', 0)"/></div>
<div class="o_kpi_footer">
<span class="o_kpi_sub">All scheduled guests</span>
<svg class="o_sparkline" viewBox="0 0 100 30" preserveAspectRatio="none">
@ -54,7 +54,7 @@
<span class="o_kpi_trend text-success"><i class="fa fa-arrow-up"/> Confirmed</span>
</div>
<div class="o_kpi_label">Confirmed Bookings</div>
<div class="o_kpi_number"><t t-esc="reservation_stats['confirmed']"/></div>
<div class="o_kpi_number"><t t-esc="reservation_stats.get('confirmed', 0)"/></div>
<div class="o_kpi_footer">
<span class="o_kpi_sub">Ready for seating</span>
<svg class="o_sparkline" viewBox="0 0 100 30" preserveAspectRatio="none">
@ -72,7 +72,7 @@
<span class="o_kpi_trend text-warning">Pending</span>
</div>
<div class="o_kpi_label">Draft / Pending</div>
<div class="o_kpi_number"><t t-esc="reservation_stats['draft']"/></div>
<div class="o_kpi_number"><t t-esc="reservation_stats.get('draft', 0)"/></div>
<div class="o_kpi_footer">
<span class="o_kpi_sub">Requires confirmation</span>
<svg class="o_sparkline" viewBox="0 0 100 30" preserveAspectRatio="none">
@ -90,7 +90,7 @@
<span class="o_kpi_trend text-primary">Completed</span>
</div>
<div class="o_kpi_label">Seated / Done</div>
<div class="o_kpi_number"><t t-esc="reservation_stats['completed']"/></div>
<div class="o_kpi_number"><t t-esc="reservation_stats.get('completed', 0)"/></div>
<div class="o_kpi_footer">
<span class="o_kpi_sub">Guests dined</span>
<svg class="o_sparkline" viewBox="0 0 100 30" preserveAspectRatio="none">
@ -103,11 +103,11 @@
<!-- Row 2: Toolbar (Filters & Search) -->
<div class="o_page_toolbar">
<div class="o_filter_pills">
<div class="o_filter_pill active" data-filter="all">All Bookings (<t t-esc="reservation_stats['total']"/>)</div>
<div class="o_filter_pill" data-filter="confirmed">Confirmed (<t t-esc="reservation_stats['confirmed']"/>)</div>
<div class="o_filter_pill" data-filter="draft">Draft / Pending (<t t-esc="reservation_stats['draft']"/>)</div>
<div class="o_filter_pill" data-filter="completed">Completed (<t t-esc="reservation_stats['completed']"/>)</div>
<div class="o_filter_pill" data-filter="cancelled">Cancelled (<t t-esc="reservation_stats['cancelled']"/>)</div>
<div class="o_filter_pill active" data-filter="all">All Bookings (<t t-esc="reservation_stats.get('total', 0)"/>)</div>
<div class="o_filter_pill" data-filter="confirmed">Confirmed (<t t-esc="reservation_stats.get('confirmed', 0)"/>)</div>
<div class="o_filter_pill" data-filter="draft">Draft / Pending (<t t-esc="reservation_stats.get('draft', 0)"/>)</div>
<div class="o_filter_pill" data-filter="completed">Completed (<t t-esc="reservation_stats.get('completed', 0)"/>)</div>
<div class="o_filter_pill" data-filter="cancelled">Cancelled (<t t-esc="reservation_stats.get('cancelled', 0)"/>)</div>
</div>
<div class="o_toolbar_search">
@ -121,7 +121,7 @@
<div class="o_card_header">
<div class="d-flex align-items-center gap-2">
<h3 class="o_card_title mb-0">Live Guest Bookings List</h3>
<span class="o_count_pill"><t t-esc="reservation_stats['total']"/> Reservations</span>
<span class="o_count_pill"><t t-esc="reservation_stats.get('total', 0)"/> Reservations</span>
</div>
<div class="d-flex align-items-center gap-2">
<button type="button" class="o_btn_red_small" data-open-modal="modalNewReservation">

View File

@ -38,7 +38,7 @@
<span class="o_kpi_trend text-danger"><i class="fa fa-arrow-up"/> +0%</span>
</div>
<div class="o_kpi_label">Total Restaurants</div>
<div class="o_kpi_number"><t t-esc="saas_stats['total']"/></div>
<div class="o_kpi_number"><t t-esc="saas_stats.get('total', 0)"/></div>
<div class="o_kpi_footer">
<span class="o_kpi_sub">Currently onboarded</span>
<svg class="o_sparkline" viewBox="0 0 100 30" preserveAspectRatio="none">
@ -58,7 +58,7 @@
<span class="o_kpi_trend text-success"><i class="fa fa-arrow-up"/> +0%</span>
</div>
<div class="o_kpi_label">Active Subscriptions</div>
<div class="o_kpi_number"><t t-esc="saas_stats['active']"/></div>
<div class="o_kpi_number"><t t-esc="saas_stats.get('active', 0)"/></div>
<div class="o_kpi_footer">
<span class="o_kpi_sub">Running smoothly</span>
<svg class="o_sparkline" viewBox="0 0 100 30" preserveAspectRatio="none">
@ -76,7 +76,7 @@
<span class="o_kpi_trend text-warning"><i class="fa fa-arrow-up"/> +0%</span>
</div>
<div class="o_kpi_label">Provisioning</div>
<div class="o_kpi_number"><t t-esc="saas_stats['provisioning']"/></div>
<div class="o_kpi_number"><t t-esc="saas_stats.get('provisioning', 0)"/></div>
<div class="o_kpi_footer">
<span class="o_kpi_sub">In progress</span>
<svg class="o_sparkline" viewBox="0 0 100 30" preserveAspectRatio="none">
@ -94,7 +94,7 @@
<span class="o_kpi_trend text-secondary"><i class="fa fa-arrow-up"/> +0%</span>
</div>
<div class="o_kpi_label">Expired / Suspended</div>
<div class="o_kpi_number"><t t-esc="saas_stats['expired']"/></div>
<div class="o_kpi_number"><t t-esc="saas_stats.get('expired', 0)"/></div>
<div class="o_kpi_footer">
<span class="o_kpi_sub">Requires attention</span>
<svg class="o_sparkline" viewBox="0 0 100 30" preserveAspectRatio="none">
@ -107,10 +107,10 @@
<!-- Row 2: Toolbar (Filters & Search) -->
<div class="o_page_toolbar">
<div class="o_filter_pills">
<div class="o_filter_pill active" data-filter="all">All Restaurants (<t t-esc="saas_stats['total']"/>)</div>
<div class="o_filter_pill" data-filter="active">Active (<t t-esc="saas_stats['active']"/>)</div>
<div class="o_filter_pill" data-filter="provisioning">Provisioning (<t t-esc="saas_stats['provisioning']"/>)</div>
<div class="o_filter_pill" data-filter="expired">Expired / Inactive (<t t-esc="saas_stats['expired']"/>)</div>
<div class="o_filter_pill active" data-filter="all">All Restaurants (<t t-esc="saas_stats.get('total', 0)"/>)</div>
<div class="o_filter_pill" data-filter="active">Active (<t t-esc="saas_stats.get('active', 0)"/>)</div>
<div class="o_filter_pill" data-filter="provisioning">Provisioning (<t t-esc="saas_stats.get('provisioning', 0)"/>)</div>
<div class="o_filter_pill" data-filter="expired">Expired / Inactive (<t t-esc="saas_stats.get('expired', 0)"/>)</div>
</div>
<div class="o_toolbar_search">
@ -124,7 +124,7 @@
<div class="o_card_header">
<div class="d-flex align-items-center gap-2">
<h3 class="o_card_title mb-0">Onboarded Restaurant Databases</h3>
<span class="o_count_pill"><t t-esc="saas_stats['total']"/> Registered</span>
<span class="o_count_pill"><t t-esc="saas_stats.get('total', 0)"/> Registered</span>
</div>
<div class="d-flex align-items-center gap-2">
<button type="button" class="o_btn_red_small" data-open-modal="modalOnboardRestaurant">
@ -154,7 +154,7 @@
<path d="M18 2C14.5 2 12 4.5 12 7.5C10 7.8 8.5 9.5 8.5 11.5C8.5 13.2 9.6 14.6 11.2 15.1C11.1 15.5 11 16 11 16.5C11 19.5 13.5 22 16.5 22H19.5C22.5 22 25 19.5 25 16.5C25 16 24.9 15.5 24.8 15.1C26.4 14.6 27.5 13.2 27.5 11.5C27.5 9.5 26 7.8 24 7.5C24 4.5 21.5 2 18 2Z" fill="none" stroke="#e50000" stroke-width="2.5"/>
<path d="M12 22V25C12 26 13 27 14 27H22C23 27 24 26 24 25V22" stroke="#e50000" stroke-width="2.5"/>
</svg>
<span class="o_res_avatar_letter"><t t-esc="restaurant['name'][0].upper() if restaurant['name'] else 'R'"/></span>
<span class="o_res_avatar_letter"><t t-esc="restaurant['name'][0].upper() if restaurant.get('name') else 'R'"/></span>
</div>
<div>
<div class="o_res_title"><t t-esc="restaurant['name']"/></div>

View File

@ -32,7 +32,7 @@
<span class="o_kpi_trend text-danger">Configured</span>
</div>
<div class="o_kpi_label">Total Tables</div>
<div class="o_kpi_number"><t t-esc="table_stats['total']"/></div>
<div class="o_kpi_number"><t t-esc="table_stats.get('total', 0)"/></div>
<div class="o_kpi_footer">
<span class="o_kpi_sub">Across all dining zones</span>
<svg class="o_sparkline" viewBox="0 0 100 30" preserveAspectRatio="none">
@ -50,7 +50,7 @@
<span class="o_kpi_trend text-success">Ready</span>
</div>
<div class="o_kpi_label">Available Tables</div>
<div class="o_kpi_number"><t t-esc="table_stats['available']"/></div>
<div class="o_kpi_number"><t t-esc="table_stats.get('available', 0)"/></div>
<div class="o_kpi_footer">
<span class="o_kpi_sub">Ready for walk-in guests</span>
<svg class="o_sparkline" viewBox="0 0 100 30" preserveAspectRatio="none">
@ -68,7 +68,7 @@
<span class="o_kpi_trend text-danger">Dining</span>
</div>
<div class="o_kpi_label">Occupied Tables</div>
<div class="o_kpi_number"><t t-esc="table_stats['occupied']"/></div>
<div class="o_kpi_number"><t t-esc="table_stats.get('occupied', 0)"/></div>
<div class="o_kpi_footer">
<span class="o_kpi_sub">Currently in service</span>
<svg class="o_sparkline" viewBox="0 0 100 30" preserveAspectRatio="none">
@ -99,14 +99,14 @@
<!-- Row 2: Floor Filters & Search -->
<div class="o_page_toolbar">
<div class="o_filter_pills">
<div class="o_filter_pill active" data-filter="all">All Floors (<t t-esc="table_stats['total']"/>)</div>
<div class="o_filter_pill active" data-filter="all">All Floors (<t t-esc="table_stats.get('total', 0)"/>)</div>
<t t-foreach="floors" t-as="fl">
<div class="o_filter_pill" t-att-data-filter="fl['name'].lower()">
<t t-esc="fl['name']"/> (<t t-esc="fl['table_count']"/>)
<div class="o_filter_pill" t-att-data-filter="fl.get('name', '').lower()">
<t t-esc="fl.get('name', '')"/> (<t t-esc="fl.get('table_count', 0)"/>)
</div>
</t>
<div class="o_filter_pill" data-filter="available">Available Only (<t t-esc="table_stats['available']"/>)</div>
<div class="o_filter_pill" data-filter="occupied">Occupied Only (<t t-esc="table_stats['occupied']"/>)</div>
<div class="o_filter_pill" data-filter="available">Available Only (<t t-esc="table_stats.get('available', 0)"/>)</div>
<div class="o_filter_pill" data-filter="occupied">Occupied Only (<t t-esc="table_stats.get('occupied', 0)"/>)</div>
</div>
<div class="o_toolbar_search">

View File

@ -3,7 +3,7 @@ from odoo import models, fields, api
class RestaurantTable(models.Model):
_inherit = 'restaurant.table'
is_occupied = fields.Boolean(string='Is Occupied', default=False, tracking=True)
is_occupied = fields.Boolean(string='Is Occupied', default=False)
is_reservation_enabled = fields.Boolean(string='Enabled for Reservation', default=True)
min_party_size = fields.Integer(string='Min Party Size', default=1)
max_party_size = fields.Integer(string='Max Party Size', default=1)