# -*- 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')] )