184 lines
7.6 KiB
Python
184 lines
7.6 KiB
Python
from odoo import http, _
|
|
from odoo.http import request
|
|
import json
|
|
import logging
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
class Dine360SelfOrderController(http.Controller):
|
|
|
|
@http.route('/dine360/menu', type='http', auth='public', website=True)
|
|
def self_order_menu(self, **kwargs):
|
|
"""Displays the self-order menu for a specific table/kiosk"""
|
|
table_id = kwargs.get('table_id')
|
|
pos_table = False
|
|
if table_id:
|
|
try:
|
|
pos_table_id = int(table_id)
|
|
pos_table = request.env['restaurant.table'].sudo().browse(pos_table_id)
|
|
if not pos_table.exists():
|
|
pos_table = False
|
|
except (ValueError, TypeError):
|
|
pos_table = False
|
|
|
|
values = {
|
|
'pos_table': pos_table,
|
|
'pos_floor': pos_table.floor_id if pos_table else False,
|
|
}
|
|
return request.render('dine360_self_order.self_order_menu_template', values)
|
|
|
|
@http.route('/dine360/self_order/products', type='json', auth='public', methods=['POST'])
|
|
def get_products(self):
|
|
"""API to fetch products for the self-order menu"""
|
|
# We only show items available in POS
|
|
products = request.env['product.product'].sudo().search([
|
|
('available_in_pos', '=', True),
|
|
('sale_ok', '=', True)
|
|
])
|
|
|
|
# Group by category if needed, but for now simple list
|
|
result = []
|
|
for p in products:
|
|
result.append({
|
|
'id': p.id,
|
|
'display_name': p.display_name,
|
|
'list_price': p.list_price,
|
|
'pos_categ_id': p.pos_categ_ids[0].id if p.pos_categ_ids else False,
|
|
'pos_categ_name': p.pos_categ_ids[0].name if p.pos_categ_ids else 'General',
|
|
'description': p.description_sale or '',
|
|
# Image URL helper
|
|
'image_url': f"/web/image/product.product/{p.id}/image_128",
|
|
'is_kitchen_item': p.is_kitchen_item,
|
|
})
|
|
return result
|
|
|
|
@http.route('/dine360/self_order/submit_order', type='json', auth='public', methods=['POST'])
|
|
def submit_self_order(self, **kwargs):
|
|
"""API to submit a self-order and create a pos.order"""
|
|
data = kwargs.get('order_data')
|
|
if not data:
|
|
return {'error': 'No order data received'}
|
|
|
|
try:
|
|
# We need an active session to link the order
|
|
session = request.env['pos.session'].sudo().search([
|
|
('state', '=', 'opened'),
|
|
('config_id.module_pos_restaurant', '=', True)
|
|
], limit=1)
|
|
|
|
if not session:
|
|
# Fallback to any open session
|
|
session = request.env['pos.session'].sudo().search([
|
|
('state', '=', 'opened')
|
|
], limit=1)
|
|
|
|
if not session:
|
|
return {'error': 'No open POS session found. Please wait for staff to open the store.'}
|
|
|
|
partner = request.env.user.partner_id if not request.env.user._is_public() else False
|
|
|
|
table_id = data.get('table_id')
|
|
pos_table = False
|
|
if table_id:
|
|
try:
|
|
pos_table = request.env['restaurant.table'].sudo().browse(int(table_id))
|
|
if not pos_table.exists():
|
|
pos_table = False
|
|
except (ValueError, TypeError):
|
|
pos_table = False
|
|
|
|
import datetime
|
|
now_str = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
|
|
table_part = pos_table.id if pos_table else 0
|
|
pos_reference = f"Order {now_str}-{session.id}-{table_part}"
|
|
|
|
currency = session.config_id.pricelist_id.currency_id if session.config_id.pricelist_id else session.company_id.currency_id
|
|
|
|
order_lines = []
|
|
total_untaxed = 0.0
|
|
total_tax = 0.0
|
|
|
|
for line in data.get('lines', []):
|
|
product_id = int(line['product_id'])
|
|
qty = float(line.get('qty', 1))
|
|
product = request.env['product.product'].sudo().browse(product_id)
|
|
if not product.exists():
|
|
continue
|
|
|
|
price_unit = float(line.get('price_unit', product.list_price))
|
|
taxes = product.taxes_id.compute_all(price_unit, currency, qty, product=product, partner=partner)
|
|
subtotal = taxes['total_excluded']
|
|
subtotal_incl = taxes['total_included']
|
|
total_untaxed += subtotal
|
|
total_tax += (subtotal_incl - subtotal)
|
|
|
|
order_lines.append((0, 0, {
|
|
'product_id': product.id,
|
|
'full_product_name': product.display_name or product.name,
|
|
'qty': qty,
|
|
'price_unit': price_unit,
|
|
'price_subtotal': subtotal,
|
|
'price_subtotal_incl': subtotal_incl,
|
|
'tax_ids': [(6, 0, product.taxes_id.ids)],
|
|
'customer_note': line.get('note', '') or (f"Table {pos_table.name}" if pos_table else ''),
|
|
'preparation_status': 'waiting',
|
|
}))
|
|
|
|
if not order_lines:
|
|
return {'error': 'No valid products in order'}
|
|
|
|
amount_total = total_untaxed + total_tax
|
|
|
|
order_vals = {
|
|
'session_id': session.id,
|
|
'company_id': session.company_id.id,
|
|
'pricelist_id': session.config_id.pricelist_id.id if session.config_id.pricelist_id else False,
|
|
'partner_id': partner.id if partner else False,
|
|
'table_id': pos_table.id if pos_table else False,
|
|
'order_source': 'qr' if pos_table else 'kiosk',
|
|
'fulfilment_type': data.get('fulfilment_type', 'dine_in'),
|
|
'pos_reference': pos_reference,
|
|
'amount_tax': total_tax,
|
|
'amount_total': amount_total,
|
|
'amount_paid': 0.0,
|
|
'amount_return': 0.0,
|
|
'note': f"Self-Order from {'Table ' + pos_table.name if pos_table else 'Kiosk'}",
|
|
'lines': order_lines,
|
|
}
|
|
|
|
order = request.env['pos.order'].sudo().create([order_vals])
|
|
request.env.flush_all()
|
|
|
|
# Ensure related fields are populated and notify KDS
|
|
kitchen_lines = order.lines.filtered(
|
|
lambda l: l.product_id.is_kitchen_item and l.product_id.type != 'service'
|
|
)
|
|
if hasattr(kitchen_lines, '_notify_kds'):
|
|
kitchen_lines._notify_kds()
|
|
|
|
if hasattr(order.lines, '_notify_pos'):
|
|
order.lines._notify_pos()
|
|
|
|
# Notify POS channel of the new QR/Kiosk order
|
|
if session.config_id:
|
|
channel = f"pos_config_Channel_{session.config_id.id}"
|
|
request.env['bus.bus'].sudo()._sendone(channel, 'new_qr_order', {
|
|
'order_id': order.id,
|
|
'order_name': order.pos_reference or order.name,
|
|
'table_id': order.table_id.id if order.table_id else False,
|
|
'table_name': order.table_id.name if order.table_id else '',
|
|
'amount_total': order.amount_total,
|
|
})
|
|
|
|
return {
|
|
'success': True,
|
|
'order_id': order.id,
|
|
'order_name': order.pos_reference or order.name,
|
|
'message': _("Your order has been sent to the kitchen!")
|
|
}
|
|
|
|
except Exception as e:
|
|
_logger.error("Error submitting self-order: %s", str(e))
|
|
return {'error': str(e)}
|