fix: resolve KDS stage reset bug by adding dependency and enforcing state closure after downstream overrides.
This commit is contained in:
parent
fe5a631a65
commit
4df8713787
@ -15,7 +15,7 @@ and todo status of previously processed prep order lines.
|
||||
'website': '',
|
||||
'category': 'Sales/Point of Sale',
|
||||
'version': '19.0.1.0.0',
|
||||
'depends': ['pos_enterprise'],
|
||||
'depends': ['pos_enterprise', 'custom_preparation_display'],
|
||||
'data': [],
|
||||
'assets': {},
|
||||
'installable': True,
|
||||
|
||||
@ -17,16 +17,26 @@ Problem:
|
||||
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.
|
||||
|
||||
Additional complication:
|
||||
The custom_preparation_display module ALSO overrides _process_preparation_changes
|
||||
and runs AFTER pos_kds_fix in the MRO (since it calls super() which reaches here).
|
||||
After super() returns, custom_preparation_display re-searches ALL prep orders
|
||||
(including old ones) and syncs parent combo states. This can revert the todo=False
|
||||
we set on old last-stage states back to todo=True, defeating the fix.
|
||||
|
||||
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.
|
||||
1. Capture existing prep orders BEFORE super() creates a new one.
|
||||
2. After all supers() have run (including custom_preparation_display's combo sync),
|
||||
do a FINAL enforcement pass that forces all old last-stage states to todo=False.
|
||||
This runs last in the call chain so no subsequent override can undo it.
|
||||
3. Only target states from genuinely OLD prep orders (pre-existing before this call).
|
||||
"""
|
||||
import logging
|
||||
|
||||
from odoo import models
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PosOrder(models.Model):
|
||||
_inherit = 'pos.order'
|
||||
@ -35,24 +45,31 @@ class PosOrder(models.Model):
|
||||
"""
|
||||
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.
|
||||
We capture existing prep orders BEFORE super() (which may include
|
||||
custom_preparation_display's combo sync and pos_enterprise's core logic).
|
||||
After the entire super() chain returns, we do a final enforcement pass
|
||||
to ensure all old last-stage states remain todo=False regardless of
|
||||
what any intermediate override may have set them to.
|
||||
"""
|
||||
self.ensure_one()
|
||||
|
||||
# Capture existing prep orders BEFORE super() creates a new one
|
||||
existing_prep_orders = self.env['pos.prep.order'].search([
|
||||
# Step 1: Capture existing prep orders BEFORE super() creates a new one.
|
||||
# These are the "old" prep orders whose states should not be reset.
|
||||
existing_prep_order_ids = self.env['pos.prep.order'].search([
|
||||
('pos_order_id', '=', self.id)
|
||||
])
|
||||
]).ids
|
||||
|
||||
# Run the original logic (may create new pos.prep.order + lines + states)
|
||||
# Step 2: Run the full super() chain.
|
||||
# This includes:
|
||||
# - custom_preparation_display._process_preparation_changes (combo sync)
|
||||
# - pos_enterprise._process_preparation_changes (new prep order creation)
|
||||
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
|
||||
# Step 3: Only act if new items were added (a new prep order was created).
|
||||
if not result.get('order_added') or not existing_prep_order_ids:
|
||||
return result
|
||||
|
||||
# Step 4: Fetch all prep displays relevant to this order's POS config.
|
||||
prep_displays = self.env['pos.prep.display'].search([
|
||||
'|',
|
||||
('pos_config_ids', '=', False),
|
||||
@ -60,26 +77,46 @@ class PosOrder(models.Model):
|
||||
])
|
||||
|
||||
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:
|
||||
stage_ids = prep_display.stage_ids.ids
|
||||
if not stage_ids:
|
||||
continue
|
||||
last_stage_id = stage_ids[-1]
|
||||
|
||||
# Step 5: Find ALL states from OLD prep orders that are at the last stage.
|
||||
# This covers both:
|
||||
# (a) States with todo=True — kitchen staff used stage-advance button
|
||||
# (b) States with todo=False — already correctly excluded by the filter
|
||||
# but may have been re-set to True by custom_preparation_display's
|
||||
# combo-parent sync logic.
|
||||
# We unconditionally force them all to todo=False so the filter
|
||||
# in _get_open_orderlines_in_display() correctly excludes them.
|
||||
old_prep_lines = self.env['pos.prep.line'].search([
|
||||
('prep_order_id', 'in', existing_prep_order_ids),
|
||||
])
|
||||
if not old_prep_lines:
|
||||
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([
|
||||
states_to_seal = self.env['pos.prep.state'].search([
|
||||
('prep_line_id', 'in', old_prep_lines.ids),
|
||||
('stage_id', '=', last_stage_id),
|
||||
('todo', '=', True),
|
||||
# Include both todo=True AND todo=False — if custom_preparation_display
|
||||
# reverted a False back to True, we need to catch it.
|
||||
# Using a simple search with no todo filter is intentional.
|
||||
])
|
||||
|
||||
if states_at_last_stage:
|
||||
# Mark them as done so the KDS filter hides them
|
||||
states_at_last_stage.write({'todo': False})
|
||||
# Separate the ones that still need updating to avoid unnecessary writes.
|
||||
states_needing_fix = states_to_seal.filtered(lambda s: s.todo)
|
||||
if states_needing_fix:
|
||||
_logger.info(
|
||||
"pos_kds_fix: Sealing %d old last-stage states as todo=False "
|
||||
"for pos.order %s (prep orders: %s)",
|
||||
len(states_needing_fix),
|
||||
self.name or self.id,
|
||||
existing_prep_order_ids,
|
||||
)
|
||||
# Use direct ORM write — no websocket notification is needed here.
|
||||
# The frontend will get a LOAD_ORDERS notification from process_order()
|
||||
# anyway, and get_preparation_display_order() will re-read from DB.
|
||||
states_needing_fix.write({'todo': False})
|
||||
|
||||
return result
|
||||
|
||||
Loading…
Reference in New Issue
Block a user