pos_ui_optimization/models/pos_order.py

96 lines
4.0 KiB
Python

# -*- coding: utf-8 -*-
from odoo import fields, models, api
from odoo.osv import expression
from datetime import datetime
import pytz
class PosOrder(models.Model):
_inherit = 'pos.order'
@api.model
def search_paid_order_ids(self, config_id, domain, limit, offset):
"""Limit paid orders list loaded on POS frontend to the current day."""
user_tz_name = self.env.context.get('tz') or self.env.user.tz or 'UTC'
try:
user_tz = pytz.timezone(user_tz_name)
except pytz.UnknownTimeZoneError:
user_tz = pytz.UTC
today_local = fields.Date.to_date(fields.Date.context_today(self))
today_start_local = datetime.combine(today_local, datetime.min.time())
today_start_tz = user_tz.localize(today_start_local)
today_start_utc = today_start_tz.astimezone(pytz.UTC).replace(tzinfo=None)
# Restrict domain so only orders from the current day (local timezone start) are returned
domain = expression.AND([domain, [('date_order', '>=', today_start_utc)]])
return super(PosOrder, self).search_paid_order_ids(config_id, domain, limit, offset)
@api.model
def check_table_has_real_orders(self, table_id, local_order_ids=None):
"""
Check whether a restaurant table has real (non-empty, non-cancelled) orders
on the server, excluding the empty local order IDs known to the calling device.
This is a safety guard for the multi-device "Release table" scenario:
- Device X creates an order on table T and syncs it to the server.
- Device Y opens table T and sees an empty local order (sync lag).
- Before allowing Device Y to release (cancel) the empty order, we verify
with the server that no real orderlines exist for this table.
Args:
table_id (int): The restaurant.table ID to check.
local_order_ids (list[int]): Server IDs of orders already known to the
calling device (typically the empty local order).
Returns:
dict:
- has_real_orders (bool): True if real draft orders with non-zero lines exist.
- order_count (int): Number of matching server orders found.
"""
if local_order_ids is None:
local_order_ids = []
# Find draft (non-finalized) orders for this table that have lines
domain = [
('table_id', '=', table_id),
('state', '=', 'draft'),
('lines', '!=', False),
]
if local_order_ids:
# Exclude the empty order(s) already known to the calling device so we
# don't false-positive on an order that this device itself created.
domain = expression.AND([domain, [('id', 'not in', local_order_ids)]])
orders = self.env['pos.order'].search(domain)
# Double-check: at least one line with non-zero qty must exist
real_orders = orders.filtered(lambda o: any(line.qty != 0 for line in o.lines))
return {
'has_real_orders': bool(real_orders),
'order_count': len(real_orders),
}
def _process_order(self, order, existing_order):
"""
Override to automatically concatenate orderline customer notes into the
general_customer_note so they are easily visible on the backend.
"""
if 'lines' in order:
line_notes = []
for line in order['lines']:
if len(line) >= 3 and isinstance(line[2], dict) and line[2].get('customer_note'):
line_notes.append(line[2]['customer_note'].strip())
if line_notes:
combined_notes = " / ".join(line_notes)
if order.get('general_customer_note'):
order['general_customer_note'] = f"{order['general_customer_note']} / {combined_notes}"
else:
order['general_customer_note'] = combined_notes
return super(PosOrder, self)._process_order(order, existing_order)