713 lines
32 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 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 'N/A'
onboarded_restaurants.append({
'id': r.id,
'name': r.name,
'owner_name': r.owner_name or 'Admin',
'email': r.email or '',
'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 'Standard',
'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)
first_res = onboarded_restaurants[0] if onboarded_restaurants else None
# SaaS master real activities and counts
currency = request.env.company.currency_id if request.env.company else None
symbol = currency.symbol if currency and currency.symbol else '₹'
res_count = 0
if 'restaurant.reservation' in request.env:
try:
res_count = request.env['restaurant.reservation'].sudo().search_count([])
except Exception:
pass
orders_count = 0
total_sales = 0.0
if 'sale.order' in request.env:
try:
orders = request.env['sale.order'].sudo().search([])
orders_count += len(orders)
total_sales += sum(orders.mapped('amount_total'))
except Exception:
pass
if 'pos.order' in request.env:
try:
pos_orders = request.env['pos.order'].sudo().search([])
orders_count += len(pos_orders)
total_sales += sum(pos_orders.mapped('amount_total'))
except Exception:
pass
avg_val = (total_sales / orders_count) if orders_count else 0.0
recent_activities = []
if is_saas_master and 'saas.restaurant' in request.env:
try:
for r in request.env['saas.restaurant'].sudo().search([], order='create_date desc', limit=5):
recent_activities.append({
'title': f"Restaurant {r.status.capitalize() if r.status else 'Registered'}",
'subtitle': f"{r.name} ({r.database_name or 'N/A'})",
'time': r.create_date.strftime('%d %b, %H:%M') if getattr(r, 'create_date', False) else '',
'badge': (r.status or 'active').capitalize(),
'badge_type': 'completed' if r.status == 'active' else 'info',
'icon': 'fa fa-cutlery'
})
except Exception:
pass
tot_restaurants = saas_stats.get('total', 0)
act_restaurants = saas_stats.get('active', 0)
onboard_pct = int((act_restaurants / tot_restaurants) * 100) if tot_restaurants > 0 else 0
saas_dashboard_data = {
'first_restaurant': first_res,
'reservations_count': res_count,
'orders_count': f"{orders_count:,}",
'avg_order_value': f"{symbol}{avg_val:,.2f}",
'onboarding_percent': onboard_pct,
'date_range': f"{(datetime.now() - timedelta(days=30)).strftime('%b %d, %Y')} - {datetime.now().strftime('%b %d, %Y')}",
'system_status': 'All systems operational',
'recent_activities': recent_activities,
}
# 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
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)
# 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 ''
date_fmt = r.start_time.strftime('%d %b %Y') if r.start_time else ''
whatsapp_url = getattr(r, 'whatsapp_url', False)
if not whatsapp_url and getattr(r, 'phone', False):
cleaned_phone = r.phone.replace('+', '').replace(' ', '').replace('-', '')
whatsapp_url = f"https://wa.me/{cleaned_phone}?text=Hello%20{r.customer_name or 'Guest'},%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 getattr(r, 'floor_id', False) else '',
'table_name': r.table_id.name if getattr(r, 'table_id', False) else (r.table_ids[0].name if getattr(r, 'table_ids', False) 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)
# 4. Online Orders Data
online_orders_data = {
'has_online_orders': False,
'pending_count': 0,
'confirmed_count': 0,
'today_count': 0,
'total_revenue_formatted': f"{symbol}0.00",
'avg_order_value': f"{symbol}0.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)]
all_online = SaleOrder.search(domain)
online_orders_data['has_online_orders'] = bool(all_online)
pending_domain = domain + [('state', 'in', ['draft', 'sent'])]
confirmed_domain = domain + [('state', 'in', ['sale', 'done'])]
online_orders_data['pending_count'] = SaleOrder.search_count(pending_domain)
online_orders_data['confirmed_count'] = SaleOrder.search_count(confirmed_domain)
today_start = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
today_orders = SaleOrder.search(domain + [('date_order', '>=', today_start)])
online_orders_data['today_count'] = len(today_orders) if today_orders else len(all_online)
revenue_orders = today_orders if today_orders else all_online
tot_rev = sum(revenue_orders.mapped('amount_total')) if revenue_orders else 0.0
online_orders_data['total_revenue_formatted'] = f"{symbol}{tot_rev:,.2f}"
if revenue_orders:
avg_ticket = tot_rev / len(revenue_orders)
online_orders_data['avg_order_value'] = f"{symbol}{avg_ticket:,.2f}"
recent = SaleOrder.search(domain, limit=20, 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 '',
'url': f"/web#id={o.id}&model=sale.order&view_type=form",
})
online_orders_data['orders'] = orders_list
except Exception as e:
_logger.warning("Error fetching sale.order: %s", e)
# 5. Backups Data
backups_list = []
if is_saas_master and 'saas.backup' in request.env:
try:
records = request.env['saas.backup'].sudo().search([], order='timestamp desc', limit=20)
for b in records:
db_name = b.database_name or (b.restaurant_id.database_name if getattr(b, 'restaurant_id', False) else '')
fname = b.backup_file or f"{db_name}_backup.zip"
backups_list.append({
'id': b.id,
'database_name': db_name,
'filename': fname,
'backup_type': b.storage_type.upper() if getattr(b, 'storage_type', False) else 'Local',
'size': 'Archive',
'date': b.timestamp.strftime('%d %b %Y, %I:%M %p') if getattr(b, 'timestamp', False) else '',
'download_url': b.s3_url or '#',
})
except Exception as e:
_logger.warning("Error fetching saas.backup: %s", e)
# 6. Low stock products
low_stock = []
if 'product.product' in request.env:
try:
low_stock = request.env['product.product'].sudo().search([
('type', '=', 'product'),
('qty_available', '<=', 5)
], limit=5)
except Exception:
pass
stats = SafeStats({
'company_name': company_name,
'low_stock_products': low_stock,
})
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': [t for t in tables_list if not t.get('is_occupied')],
'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,
'low_stock_products': low_stock,
'backups': backups_list,
}
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')
if values.get('is_saas_master'):
return request.redirect('/dashboard/restaurants')
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')
if values.get('is_saas_master'):
return request.redirect('/dashboard/restaurants')
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',
'is_admin_override': True,
'override_reason': 'Dashboard Booking',
}
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')]
)