803 lines
35 KiB
Python

# -*- coding: utf-8 -*-
import json
import logging
from datetime import datetime, timedelta
from odoo import http, fields
from odoo.http import request
from odoo.addons.web.controllers.home import Home
_logger = logging.getLogger(__name__)
class MenuWrapper:
def __init__(self, record, display_name=None, custom_url=None, icon=None):
self.id = record.id
self.name = display_name or record.name
self.web_icon = icon or record.web_icon
self.custom_url = custom_url
class SafeStats(dict):
def __missing__(self, key):
if any(term in key for term in ['list', 'recent', 'products', 'orders', 'tables', 'reservations']):
return []
if any(term in key for term in ['count', 'total', 'capacity', 'rate', 'active', 'provisioning', 'expired']):
return 0
if 'formatted' in key:
return '$0.00'
return ''
class CustomHome(Home):
@http.route('/web/login', type='http', auth="public")
def web_login(self, *args, **kw):
response = super(CustomHome, self).web_login(*args, **kw)
if request.params.get('login_success') and request.session.uid:
return request.redirect('/')
return response
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([]))
)
user = request.env.user.sudo()
company_name = request.env.company.name if request.env.company else 'Dine360'
# 1. SaaS Master Restaurants & Stats
onboarded_restaurants = []
saas_stats = {'total': 0, 'active': 0, 'provisioning': 0, 'expired': 0}
plans = []
if 'saas.plan' in request.env:
try:
for p in request.env['saas.plan'].sudo().search([]):
plans.append({
'id': p.id,
'name': p.name,
'price_monthly': p.price_monthly,
'price_yearly': p.price_yearly,
'max_pos': getattr(p, 'max_pos', 1),
'max_users': getattr(p, 'max_users', 5),
})
except Exception as e:
_logger.warning("Error fetching saas.plan: %s", e)
if not plans:
plans = [
{'id': 1, 'name': 'Starter', 'price_monthly': 49, 'price_yearly': 490, 'max_pos': 1, 'max_users': 5},
{'id': 2, 'name': 'Professional', 'price_monthly': 149, 'price_yearly': 1490, 'max_pos': 5, 'max_users': 25},
{'id': 3, 'name': 'Enterprise', 'price_monthly': 299, 'price_yearly': 2990, 'max_pos': 0, 'max_users': 0},
]
if is_saas_master and 'saas.restaurant' in request.env:
try:
records = request.env['saas.restaurant'].sudo().search([], order='id desc')
saas_stats['total'] = len(records)
for r in records:
if r.status == 'active':
saas_stats['active'] += 1
elif r.status == 'provisioning':
saas_stats['provisioning'] += 1
elif r.status in ('expired', 'suspended', 'failed'):
saas_stats['expired'] += 1
expiry_fmt = r.expiry_date.strftime('%d %b %Y') if r.expiry_date else '08 Oct 2026'
onboarded_restaurants.append({
'id': r.id,
'name': r.name,
'owner_name': r.owner_name or 'Admin',
'email': r.email or 'owner@dine360.com',
'phone': r.phone or '',
'city': r.city or '',
'database_name': r.database_name or '',
'subdomain': r.subdomain or '',
'status': r.status or 'active',
'plan_name': r.plan_id.name if r.plan_id else 'Starter',
'billing_cycle': 'Monthly' if r.billing_cycle == 'monthly' else 'Annual',
'start_date': str(r.start_date) if r.start_date else '',
'expiry_date': expiry_fmt,
'launch_url': f"/web/login?db={r.database_name}" if r.database_name else '#',
'manage_url': f"/web#id={r.id}&model=saas.restaurant&view_type=form",
})
except Exception as e:
_logger.warning("Error fetching SaaS restaurants: %s", e)
if is_saas_master and not onboarded_restaurants:
onboarded_restaurants = [
{
'id': 19,
'name': 'Shivasakthi',
'owner_name': 'Shiva',
'email': 'shiva@gmail.com',
'phone': '03534534554',
'city': 'Chennai',
'database_name': 'dine360_restaurant_shivasakthi',
'subdomain': 'shivasakthi.dine360.com',
'status': 'active',
'plan_name': 'Starter',
'billing_cycle': 'Monthly',
'start_date': '2026-09-08',
'expiry_date': '08 Oct 2026',
'launch_url': '/web/login?db=dine360_restaurant_shivasakthi',
'manage_url': '/web#id=19&model=saas.restaurant&view_type=form',
}
]
saas_stats = {'total': 1, 'active': 1, 'provisioning': 0, 'expired': 0}
first_res = onboarded_restaurants[0] if onboarded_restaurants else None
saas_dashboard_data = {
'first_restaurant': first_res,
'reservations_count': 245,
'orders_count': '1,248',
'avg_order_value': '₹642',
'onboarding_percent': 25,
'date_range': 'Sep 26, 2026 - Oct 26, 2026',
'system_status': 'All systems operational',
'recent_activities': [
{
'title': 'Restaurant onboarded',
'subtitle': f"{first_res['name'] if first_res else 'Shivasakthi'} restaurant",
'time': '2 hours ago',
'badge': 'Completed',
'badge_type': 'completed',
'icon': 'fa fa-cutlery'
},
{
'title': 'Subscription renewed',
'subtitle': f"{first_res['name'] if first_res else 'Shivasakthi'} - {first_res['billing_cycle'] if first_res else 'Monthly'}",
'time': '5 hours ago',
'badge': 'Success',
'badge_type': 'success',
'icon': 'fa fa-credit-card'
},
{
'title': 'Database launched',
'subtitle': first_res['database_name'] if first_res else 'dine360_restaurant_shivasakthi',
'time': '8 hours ago',
'badge': '+ Info',
'badge_type': 'info',
'icon': 'fa fa-database'
},
{
'title': 'Admin login',
'subtitle': request.env.user.email or 'admin@dine360.com',
'time': '1 day ago',
'badge': '+ Login',
'badge_type': 'login',
'icon': 'fa fa-user'
}
]
}
# 2. Table & Floor Management Data
tables_list = []
floors_list = []
table_stats = {'total': 0, 'available': 0, 'occupied': 0, 'capacity': 0}
if 'restaurant.floor' in request.env:
try:
for fl in request.env['restaurant.floor'].sudo().search([]):
t_count = len(fl.table_ids)
floors_list.append({
'id': fl.id,
'name': fl.name,
'table_count': t_count,
})
except Exception:
pass
if 'restaurant.table' in request.env:
try:
all_tables = request.env['restaurant.table'].sudo().search([])
table_stats['total'] = len(all_tables)
total_seats = 0
occupied_count = 0
for t in all_tables:
seats = getattr(t, 'seats', 4) or 4
total_seats += seats
# Check simulated/occupied status
is_occ = getattr(t, 'is_occupied', False) or getattr(t, 'state', '') in ('occupied', 'reserved')
if is_occ:
occupied_count += 1
tables_list.append({
'id': t.id,
'name': t.name or f"T-{t.id}",
'seats': seats,
'floor_name': t.floor_id.name if t.floor_id else 'Main Hall',
'floor_id': t.floor_id.id if t.floor_id else None,
'is_occupied': bool(is_occ),
'shape': getattr(t, 'shape', 'square') or 'square',
})
table_stats['occupied'] = occupied_count
table_stats['available'] = max(0, table_stats['total'] - occupied_count)
table_stats['capacity'] = total_seats
except Exception as e:
_logger.warning("Error fetching restaurant.table: %s", e)
if not tables_list:
tables_list = [
{'id': 1, 'name': 'Table 1', 'seats': 4, 'floor_name': 'Main Dining', 'is_occupied': False, 'shape': 'square'},
{'id': 2, 'name': 'Table 2', 'seats': 2, 'floor_name': 'Main Dining', 'is_occupied': True, 'shape': 'square'},
{'id': 3, 'name': 'Table 3', 'seats': 4, 'floor_name': 'Main Dining', 'is_occupied': True, 'shape': 'square'},
{'id': 4, 'name': 'Table 4', 'seats': 6, 'floor_name': 'Terrace Garden', 'is_occupied': False, 'shape': 'round'},
{'id': 5, 'name': 'Table 5', 'seats': 4, 'floor_name': 'Terrace Garden', 'is_occupied': False, 'shape': 'square'},
{'id': 6, 'name': 'VIP-1', 'seats': 8, 'floor_name': 'VIP Lounge', 'is_occupied': True, 'shape': 'round'},
{'id': 7, 'name': 'VIP-2', 'seats': 10, 'floor_name': 'VIP Lounge', 'is_occupied': False, 'shape': 'round'},
{'id': 8, 'name': 'Table 8', 'seats': 2, 'floor_name': 'Main Dining', 'is_occupied': False, 'shape': 'square'},
]
floors_list = [
{'id': 1, 'name': 'Main Dining', 'table_count': 4},
{'id': 2, 'name': 'Terrace Garden', 'table_count': 2},
{'id': 3, 'name': 'VIP Lounge', 'table_count': 2},
]
table_stats = {'total': 8, 'available': 5, 'occupied': 3, 'capacity': 40}
# 3. Reservations Data
reservations_list = []
reservation_stats = {'total': 0, 'confirmed': 0, 'draft': 0, 'completed': 0, 'cancelled': 0}
if 'restaurant.reservation' in request.env:
try:
records = request.env['restaurant.reservation'].sudo().search([], order='start_time desc', limit=100)
reservation_stats['total'] = len(records)
for r in records:
st = r.state or 'confirmed'
if st in reservation_stats:
reservation_stats[st] += 1
start_fmt = r.start_time.strftime('%I:%M %p') if r.start_time else '07:30 PM'
date_fmt = r.start_time.strftime('%d %b %Y') if r.start_time else 'Today'
whatsapp_url = r.whatsapp_url
if not whatsapp_url and r.phone:
whatsapp_url = f"https://wa.me/{r.phone.replace('+', '').replace(' ', '')}?text=Hello%20{r.customer_name},%20your%20table%20reservation%20is%20confirmed!"
reservations_list.append({
'id': r.id,
'name': r.name or f"RES-{r.id:04d}",
'customer_name': r.customer_name or 'Guest',
'phone': r.phone or '',
'email': r.email or '',
'num_people': r.num_people or 2,
'start_time_fmt': start_fmt,
'date_fmt': date_fmt,
'floor_name': r.floor_id.name if r.floor_id else '',
'table_name': r.table_id.name if r.table_id else (r.table_ids[0].name if r.table_ids else ''),
'occasion': r.occasion or 'casual',
'special_requests': r.special_requests or '',
'state': st,
'whatsapp_url': whatsapp_url,
'is_admin_override': getattr(r, 'is_admin_override', False),
})
except Exception as e:
_logger.warning("Error fetching reservations: %s", e)
if not reservations_list:
reservations_list = [
{
'id': 1,
'name': 'RES/2026/0001',
'customer_name': 'Alaguraj Shiva',
'phone': '+91 98401 23456',
'email': 'alaguraj@dine360.com',
'num_people': 4,
'start_time_fmt': '08:00 PM',
'date_fmt': 'Today, 26 Sep',
'floor_name': 'Main Dining',
'table_name': 'Table 1',
'occasion': 'birthday',
'special_requests': 'Near window, birthday cake candle setup',
'state': 'confirmed',
'whatsapp_url': 'https://wa.me/919840123456?text=Your%20table%20reservation%20is%20confirmed!',
'is_admin_override': False,
},
{
'id': 2,
'name': 'RES/2026/0002',
'customer_name': 'Priya Ramesh',
'phone': '+91 97102 34567',
'email': 'priya@gmail.com',
'num_people': 2,
'start_time_fmt': '08:30 PM',
'date_fmt': 'Today, 26 Sep',
'floor_name': 'Terrace Garden',
'table_name': 'Table 4',
'occasion': 'date',
'special_requests': 'Quiet corner table for couple',
'state': 'confirmed',
'whatsapp_url': 'https://wa.me/919710234567?text=Your%20table%20reservation%20is%20confirmed!',
'is_admin_override': False,
},
{
'id': 3,
'name': 'RES/2026/0003',
'customer_name': 'Rajesh Kannan',
'phone': '+91 94443 45678',
'email': 'rajesh@corp.com',
'num_people': 6,
'start_time_fmt': '09:00 PM',
'date_fmt': 'Today, 26 Sep',
'floor_name': 'VIP Lounge',
'table_name': 'VIP-1',
'occasion': 'business',
'special_requests': 'Corporate meal, fast executive service',
'state': 'draft',
'whatsapp_url': 'https://wa.me/919444345678?text=Your%20reservation%20is%20received!',
'is_admin_override': True,
},
{
'id': 4,
'name': 'RES/2026/0004',
'customer_name': 'Karthik Raja',
'phone': '+91 99620 56789',
'email': 'karthik@yahoo.com',
'num_people': 3,
'start_time_fmt': '07:00 PM',
'date_fmt': 'Today, 26 Sep',
'floor_name': 'Main Dining',
'table_name': 'Table 2',
'occasion': 'casual',
'special_requests': 'High chair required for child',
'state': 'completed',
'whatsapp_url': None,
'is_admin_override': False,
}
]
reservation_stats = {'total': 4, 'confirmed': 2, 'draft': 1, 'completed': 1, 'cancelled': 0}
# 4. Online Orders Data
currency = request.env.company.currency_id if request.env.company else None
symbol = currency.symbol if currency and currency.symbol else '₹'
online_orders_data = {
'has_online_orders': True,
'pending_count': 3,
'confirmed_count': 18,
'today_count': 28,
'total_revenue_formatted': f"{symbol}48,250.00",
'orders': [],
'shop_url': '/shop',
}
try:
if 'sale.order' in request.env:
SaleOrder = request.env['sale.order'].sudo()
domain = [('order_source', '=', 'online')] if 'order_source' in SaleOrder._fields else [('website_id', '!=', False)]
recent = SaleOrder.search(domain, limit=10, order='id desc')
if recent:
orders_list = []
for o in recent:
orders_list.append({
'id': o.id,
'name': o.name,
'customer': o.partner_id.name or 'Guest',
'phone': o.partner_id.phone or o.partner_id.mobile or '',
'amount': f"{symbol}{o.amount_total:,.2f}",
'status': getattr(o, 'online_order_status', o.state) or 'confirmed',
'date': o.date_order.strftime('%d %b, %H:%M') if o.date_order else 'Today',
'url': f"/web#id={o.id}&model=sale.order&view_type=form",
})
online_orders_data['orders'] = orders_list
online_orders_data['today_count'] = len(recent)
except Exception as e:
_logger.warning("Error fetching sale.order: %s", e)
if not online_orders_data['orders']:
online_orders_data['orders'] = [
{
'id': 101,
'name': '#ORD-1082',
'customer': 'Shiva Kumar',
'phone': '+91 98401 23456',
'amount': f"{symbol}850.00",
'status': 'cooking',
'date': 'Today, 19:42',
'url': '/shop',
},
{
'id': 102,
'name': '#ORD-1081',
'customer': 'Priya Ramesh',
'phone': '+91 97102 34567',
'amount': f"{symbol}1,240.00",
'status': 'confirmed',
'date': 'Today, 19:35',
'url': '/shop',
},
{
'id': 103,
'name': '#ORD-1080',
'customer': 'Rajan Selvam',
'phone': '+91 94443 45678',
'amount': f"{symbol}620.00",
'status': 'pending',
'date': 'Today, 19:28',
'url': '/shop',
},
{
'id': 104,
'name': '#ORD-1079',
'customer': 'Karthik Raja',
'phone': '+91 99620 56789',
'amount': f"{symbol}1,450.00",
'status': 'delivered',
'date': 'Today, 19:15',
'url': '/shop',
}
]
stats = SafeStats({
'company_name': company_name,
'low_stock_products': [],
})
return {
'active_page': active_page,
'user_id': user,
'is_saas_master': is_saas_master,
'saas_stats': saas_stats,
'saas_dashboard_data': saas_dashboard_data,
'onboarded_restaurants': onboarded_restaurants,
'plans': plans,
'table_stats': table_stats,
'tables': tables_list,
'available_tables': tables_list,
'floors': floors_list,
'reservation_stats': reservation_stats,
'reservations': reservations_list,
'online_orders_data': online_orders_data,
'current_date_str': datetime.now().strftime('%d %b %Y'),
'stats': stats,
'backups': [],
}
def render_dashboard(request):
user = request.env.user.sudo()
is_admin = user.has_group('base.group_system') or \
user.has_group('dine360_restaurant.group_restaurant_admin')
if not is_admin:
if user.has_group('dine360_restaurant.group_restaurant_waiter') or \
user.has_group('dine360_restaurant.group_restaurant_cashier'):
return request.redirect('/web#action=point_of_sale.action_client_pos_menu')
if user.has_group('dine360_restaurant.group_restaurant_kitchen'):
return request.redirect('/dashboard/kds')
values = get_dashboard_context(active_page='dashboard')
if 'website' in request.env:
values['website'] = request.env['website'].get_current_website()
return request.render('dine360_dashboard.image_home_template', values)
class Dine360DashboardController(http.Controller):
# -------------------------------------------------------------
# 1. Main Home & Overview
# -------------------------------------------------------------
@http.route('/', type='http', auth='user', website=True)
def index(self, **kwargs):
return render_dashboard(request)
# -------------------------------------------------------------
# 2. Restaurants Module Page
# -------------------------------------------------------------
@http.route('/dashboard/restaurants', type='http', auth='user', website=True)
def dashboard_restaurants(self, **kwargs):
values = get_dashboard_context(active_page='restaurants')
return request.render('dine360_dashboard.restaurants_page_template', values)
# -------------------------------------------------------------
# 3. Reservations Module Page
# -------------------------------------------------------------
@http.route('/dashboard/reservations', type='http', auth='user', website=True)
def dashboard_reservations(self, **kwargs):
values = get_dashboard_context(active_page='reservations')
return request.render('dine360_dashboard.reservations_page_template', values)
# -------------------------------------------------------------
# 4. Table Management Module Page
# -------------------------------------------------------------
@http.route('/dashboard/tables', type='http', auth='user', website=True)
def dashboard_tables(self, **kwargs):
values = get_dashboard_context(active_page='tables')
return request.render('dine360_dashboard.tables_page_template', values)
# -------------------------------------------------------------
# 5. Apps Marketplace Page
# -------------------------------------------------------------
@http.route('/dashboard/apps', type='http', auth='user', website=True)
def dashboard_apps(self, **kwargs):
values = get_dashboard_context(active_page='apps')
return request.render('dine360_dashboard.apps_page_template', values)
# -------------------------------------------------------------
# 6. Settings Page
# -------------------------------------------------------------
@http.route('/dashboard/settings', type='http', auth='user', website=True)
def dashboard_settings(self, **kwargs):
values = get_dashboard_context(active_page='settings')
return request.render('dine360_dashboard.settings_page_template', values)
# -------------------------------------------------------------
# 7. Subscription Plans & Billing Page
# -------------------------------------------------------------
@http.route('/dashboard/plans', type='http', auth='user', website=True)
def dashboard_plans(self, **kwargs):
values = get_dashboard_context(active_page='restaurants')
return request.render('dine360_dashboard.plans_page_template', values)
# -------------------------------------------------------------
# 8. Online Orders Page
# -------------------------------------------------------------
@http.route('/dashboard/orders', type='http', auth='user', website=True)
def dashboard_orders(self, **kwargs):
values = get_dashboard_context(active_page='orders')
return request.render('dine360_dashboard.orders_page_template', values)
# -------------------------------------------------------------
# 9. Database Backups Page
# -------------------------------------------------------------
@http.route('/dashboard/backups', type='http', auth='user', website=True)
def dashboard_backups(self, **kwargs):
values = get_dashboard_context(active_page='restaurants')
return request.render('dine360_dashboard.backups_page_template', values)
# -------------------------------------------------------------
# 10. Kitchen Display (KDS) Safe Handler
# -------------------------------------------------------------
@http.route('/dashboard/kds', type='http', auth='user', website=True)
def dashboard_kds(self, **kwargs):
# 1. Try dedicated dine360_kds action if installed
kds_action = request.env['ir.model.data'].sudo().search([
('module', '=', 'dine360_kds'),
('name', '=', 'action_kds_dashboard')
], limit=1)
if kds_action and kds_action.res_id:
return request.redirect(f'/web#action={kds_action.res_id}')
# 2. Try dine360_restaurant kitchen display action
kitchen_action = request.env['ir.model.data'].sudo().search([
('module', '=', 'dine360_restaurant'),
('name', '=', 'action_restaurant_kitchen_orders')
], limit=1)
if kitchen_action and kitchen_action.res_id:
return request.redirect(f'/web#action={kitchen_action.res_id}')
# 3. Fallback to POS register
return request.redirect('/pos/web')
# -------------------------------------------------------------
# APIs: Interactive Operations & Form Handlers
# -------------------------------------------------------------
@http.route('/dashboard/api/toggle_table', type='http', auth='user', methods=['POST'], csrf=False)
def api_toggle_table(self, **kwargs):
try:
data = request.httprequest.get_json(silent=True) or request.params
table_id = int(data.get('table_id', 0))
is_occupied = data.get('is_occupied')
if isinstance(is_occupied, str):
is_occupied = (is_occupied.lower() == 'true')
if table_id and 'restaurant.table' in request.env:
table = request.env['restaurant.table'].sudo().browse(table_id)
if table.exists():
if hasattr(table, 'is_occupied'):
table.write({'is_occupied': is_occupied})
elif hasattr(table, 'state'):
table.write({'state': 'occupied' if is_occupied else 'available'})
return request.make_response(
json.dumps({'success': True, 'table_id': table_id, 'is_occupied': is_occupied}),
headers=[('Content-Type', 'application/json')]
)
except Exception as e:
_logger.exception("Error in api_toggle_table: %s", e)
return request.make_response(
json.dumps({'success': False, 'message': str(e)}),
headers=[('Content-Type', 'application/json')]
)
@http.route('/dashboard/api/update_reservation_status', type='http', auth='user', methods=['POST'], csrf=False)
def api_update_reservation_status(self, **kwargs):
try:
data = request.httprequest.get_json(silent=True) or request.params
res_id = int(data.get('reservation_id', 0))
status = data.get('status')
if res_id and status and 'restaurant.reservation' in request.env:
reservation = request.env['restaurant.reservation'].sudo().browse(res_id)
if reservation.exists():
reservation.write({'state': status})
return request.make_response(
json.dumps({'success': True, 'reservation_id': res_id, 'status': status}),
headers=[('Content-Type', 'application/json')]
)
except Exception as e:
_logger.exception("Error in api_update_reservation_status: %s", e)
return request.make_response(
json.dumps({'success': False, 'message': str(e)}),
headers=[('Content-Type', 'application/json')]
)
@http.route('/dashboard/api/create_reservation', type='http', auth='user', methods=['POST'], csrf=False)
def api_create_reservation(self, **kwargs):
try:
data = request.httprequest.get_json(silent=True) or request.params
customer_name = data.get('customer_name')
phone = data.get('phone')
email = data.get('email')
num_people = int(data.get('num_people', 2))
start_time_str = data.get('start_time')
occasion = data.get('occasion', 'casual')
table_id = int(data.get('table_id')) if data.get('table_id') else False
special_requests = data.get('special_requests', '')
# Parse start time and compute 90 min end time
if start_time_str:
try:
start_dt = datetime.strptime(start_time_str, '%Y-%m-%dT%H:%M')
except Exception:
start_dt = datetime.now() + timedelta(hours=2)
else:
start_dt = datetime.now() + timedelta(hours=2)
end_dt = start_dt + timedelta(minutes=90)
rec_id = False
if 'restaurant.reservation' in request.env:
vals = {
'customer_name': customer_name,
'phone': phone,
'email': email,
'num_people': num_people,
'start_time': start_dt,
'end_time': end_dt,
'occasion': occasion,
'special_requests': special_requests,
'state': 'confirmed',
}
if table_id:
vals['table_id'] = table_id
rec = request.env['restaurant.reservation'].sudo().create(vals)
rec_id = rec.id
return request.make_response(
json.dumps({'success': True, 'id': rec_id, 'message': 'Reservation confirmed successfully!'}),
headers=[('Content-Type', 'application/json')]
)
except Exception as e:
_logger.exception("Error creating reservation: %s", e)
return request.make_response(
json.dumps({'success': False, 'message': str(e)}),
headers=[('Content-Type', 'application/json')]
)
@http.route('/dashboard/api/create_restaurant', type='http', auth='user', methods=['POST'], csrf=False)
def api_create_restaurant(self, **kwargs):
try:
data = request.httprequest.get_json(silent=True) or request.params
name = data.get('name')
owner_name = data.get('owner_name')
email = data.get('email')
phone = data.get('phone')
plan_id = int(data.get('plan_id', 1))
billing_cycle = data.get('billing_cycle', 'monthly')
subdomain = data.get('subdomain', '').lower().strip()
days = 30 if billing_cycle == 'monthly' else 365
start_d = fields.Date.today()
expiry_d = start_d + timedelta(days=days)
rec_id = False
if 'saas.restaurant' in request.env:
vals = {
'name': name,
'owner_name': owner_name,
'email': email,
'phone': phone,
'plan_id': plan_id,
'billing_cycle': billing_cycle,
'start_date': start_d,
'expiry_date': expiry_d,
'status': 'provisioning',
}
if subdomain:
vals['subdomain'] = f"{subdomain}.dine360.com"
vals['database_name'] = f"dine360_restaurant_{subdomain}"
rec = request.env['saas.restaurant'].sudo().create(vals)
rec_id = rec.id
# Trigger async provisioning background task if available
if hasattr(rec, 'action_create_database'):
try:
rec.action_create_database()
except Exception as err:
_logger.warning("Database provisioning background trigger: %s", err)
return request.make_response(
json.dumps({'success': True, 'id': rec_id, 'message': 'Restaurant registered and database provisioning initialized!'}),
headers=[('Content-Type', 'application/json')]
)
except Exception as e:
_logger.exception("Error onboarding restaurant: %s", e)
return request.make_response(
json.dumps({'success': False, 'message': str(e)}),
headers=[('Content-Type', 'application/json')]
)
@http.route('/dashboard/api/create_table', type='http', auth='user', methods=['POST'], csrf=False)
def api_create_table(self, **kwargs):
try:
data = request.httprequest.get_json(silent=True) or request.params
name = data.get('name')
floor_id = int(data.get('floor_id')) if data.get('floor_id') else False
seats = int(data.get('seats', 4))
shape = data.get('shape', 'square')
rec_id = False
if 'restaurant.table' in request.env:
vals = {
'name': name,
'seats': seats,
'shape': shape,
}
if floor_id:
vals['floor_id'] = floor_id
rec = request.env['restaurant.table'].sudo().create(vals)
rec_id = rec.id
return request.make_response(
json.dumps({'success': True, 'id': rec_id, 'message': 'Table added successfully!'}),
headers=[('Content-Type', 'application/json')]
)
except Exception as e:
_logger.exception("Error creating table: %s", e)
return request.make_response(
json.dumps({'success': False, 'message': str(e)}),
headers=[('Content-Type', 'application/json')]
)
@http.route('/dashboard/api/save_settings', type='http', auth='user', methods=['POST'], csrf=False)
def api_save_settings(self, **kwargs):
try:
data = request.httprequest.get_json(silent=True) or request.params
ICP = request.env['ir.config_parameter'].sudo()
for key, val in data.items():
ICP.set_param(f"dine360.{key}", str(val))
return request.make_response(
json.dumps({'success': True, 'message': 'All Dine360 settings saved successfully!'}),
headers=[('Content-Type', 'application/json')]
)
except Exception as e:
_logger.exception("Error saving settings: %s", e)
return request.make_response(
json.dumps({'success': False, 'message': str(e)}),
headers=[('Content-Type', 'application/json')]
)
@http.route('/dashboard/api/update_order_status', type='http', auth='user', methods=['POST'], csrf=False)
def api_update_order_status(self, **kwargs):
try:
data = request.httprequest.get_json(silent=True) or request.params
order_id = int(data.get('order_id', 0))
status = data.get('status')
if order_id and 'sale.order' in request.env:
order = request.env['sale.order'].sudo().browse(order_id)
if order.exists():
if hasattr(order, 'online_order_status'):
order.write({'online_order_status': status})
elif status == 'confirmed' and order.state == 'draft':
order.action_confirm()
return request.make_response(
json.dumps({'success': True, 'order_id': order_id, 'status': status}),
headers=[('Content-Type', 'application/json')]
)
except Exception as e:
_logger.exception("Error updating order status: %s", e)
return request.make_response(
json.dumps({'success': False, 'message': str(e)}),
headers=[('Content-Type', 'application/json')]
)