pos_kds_fix/models/pos_order.py
2026-06-01 14:33:58 +07:00

86 lines
3.8 KiB
Python

# -*- coding: utf-8 -*-
"""
Fix for KDS (Kitchen Display System) / Preparation Display bug:
Problem:
When Table X has N items that are already in the "Completed" stage on the KDS,
and the customer adds a new item, Odoo creates a new pos.prep.order for the
same pos.order. The KDS frontend receives a LOAD_ORDERS notification and reloads
all open prep states for that pos.order via get_preparation_display_order().
The _get_open_orderlines_in_display() filter excludes ONLY states where:
todo=False AND stage=last_stage
Items that were advanced to the last stage via the stage-advance button have:
todo=True, stage=last_stage <-- these ARE returned and shown as "To Prepare"
So the previously completed items (stage-advanced to last stage, todo=True) reappear
on the KDS card alongside the new item, effectively resetting their visual status.
Fix:
When a new pos.prep.order is created for an existing pos.order (meaning new items
are being added to a table that already sent items to the kitchen), we find all
existing prep states for all PREVIOUS prep orders of the same pos.order that are
currently at the LAST stage (regardless of todo status). These represent items
the kitchen staff already processed. We set their todo=False to ensure the filter
in _get_open_orderlines_in_display() correctly excludes them from future reloads.
"""
from odoo import models
class PosOrder(models.Model):
_inherit = 'pos.order'
def _process_preparation_changes(self, options):
"""
Override to fix KDS stage reset bug.
Before calling super(), we record existing prep orders for this pos.order.
After super() runs (which may create a new prep order for new items),
we mark all states in the OLD prep orders that are at the last stage
as todo=False so they won't reappear on the KDS display.
"""
self.ensure_one()
# Capture existing prep orders BEFORE super() creates a new one
existing_prep_orders = self.env['pos.prep.order'].search([
('pos_order_id', '=', self.id)
])
# Run the original logic (may create new pos.prep.order + lines + states)
result = super()._process_preparation_changes(options)
# If new items were added (flag_order_added), super() created a new prep order
if result.get('order_added') and existing_prep_orders:
# Fetch all prep displays relevant to this order
prep_displays = self.env['pos.prep.display'].search([
'|',
('pos_config_ids', '=', False),
('pos_config_ids', 'in', self.config_id.id),
])
for prep_display in prep_displays:
last_stage_id = (
prep_display.stage_ids.ids[-1]
if prep_display.stage_ids.ids else False
)
if not last_stage_id:
continue
# Find all states from the OLD prep orders that are at the last stage
# with todo=True — these are items the kitchen advanced to "Completed"
# stage but which would still be returned by _get_open_orderlines_in_display
# because the filter only excludes (todo=False AND stage=last).
old_prep_lines = existing_prep_orders.mapped('prep_line_ids')
states_at_last_stage = self.env['pos.prep.state'].search([
('prep_line_id', 'in', old_prep_lines.ids),
('stage_id', '=', last_stage_id),
('todo', '=', True),
])
if states_at_last_stage:
# Mark them as done so the KDS filter hides them
states_at_last_stage.write({'todo': False})
return result