first commit

This commit is contained in:
Suherdy Yacob 2026-06-01 14:33:58 +07:00
commit fe5a631a65
6 changed files with 221 additions and 0 deletions

16
.gitignore vendored Normal file
View File

@ -0,0 +1,16 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.egg-info/
*.egg
# Odoo
*.pyc
.DS_Store
# IDE
.vscode/
.idea/
*.swp
*.swo

93
README.rst Normal file
View File

@ -0,0 +1,93 @@
POS KDS Stage Reset Fix
=======================
**Module:** ``pos_kds_fix``
**Version:** 19.0.1.0.0
**Author:** Suherdy Yacob
**Category:** Sales/Point of Sale
**License:** GPL-3
Overview
--------
This module fixes a bug in the Odoo 19 Preparation Display (Kitchen Display System)
where previously completed order items are incorrectly reset back to the "To Prepare"
stage when a customer adds a new item to the same table.
The Bug
-------
**Scenario:**
1. Table 1 sends 5 items to the KDS.
2. Kitchen staff advances all 5 items through the stages to "Completed".
3. Customer adds 1 new item to Table 1.
4. The new item correctly appears on the KDS in "To Prepare" stage.
5. **BUG:** The 5 previously completed items reappear on the KDS as "To Prepare".
**Root Cause:**
When a new item is added to an existing POS order that was already sent to the
kitchen, Odoo creates a new ``pos.prep.order`` record for the new item. The KDS
frontend then reloads all open prep states for that POS order via the bus
notification ``LOAD_ORDERS``.
The ``_get_open_orderlines_in_display()`` filter excludes only states where:
- ``todo = False`` AND ``stage = last_stage``
When kitchen staff advances items to the last stage using the stage-advance button,
the state is set to:
- ``todo = True``, ``stage = last_stage``
These states pass the filter and are returned to the KDS frontend, causing the
completed items to reappear.
The Fix
-------
This module overrides ``PosOrder._process_preparation_changes()`` to detect when
a new ``pos.prep.order`` is being created for an existing POS order (i.e., new
items added to an already-sent order). When that happens, all states from the
**previous** prep orders that are at the last stage (regardless of ``todo`` status)
are automatically set to ``todo=False``. This ensures the KDS filter correctly
excludes them from subsequent reloads.
Technical Details
-----------------
**Overridden Method:** ``pos.order._process_preparation_changes()``
**Model:** ``pos.order``
**Logic:**
- Capture existing ``pos.prep.order`` IDs before calling ``super()``.
- After ``super()`` runs, check if ``result['order_added']`` is ``True``
(indicating new lines were added and a new prep ticket was created).
- For each relevant prep display, find all ``pos.prep.state`` records from the
old prep orders that are at the last stage with ``todo=True``.
- Set those states to ``todo=False`` to hide them from the KDS.
Dependencies
------------
- ``pos_enterprise``
Installation
------------
1. Copy the ``pos_kds_fix`` folder into your Odoo addons directory.
2. Update the apps list in Odoo settings.
3. Search for "POS KDS Stage Reset Fix" and install it.
4. No additional configuration is required.
Compatibility
-------------
- Odoo 19 Enterprise (requires ``pos_enterprise`` module)

2
__init__.py Normal file
View File

@ -0,0 +1,2 @@
# -*- coding: utf-8 -*-
from . import models

23
__manifest__.py Normal file
View File

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
{
'name': 'POS KDS Stage Reset Fix',
'summary': 'Fix KDS bug: completed items stage reset when new items are ordered for the same table',
'description': """
Fix for Preparation Display (Kitchen Display System) bug:
When a table already has items in Completed/Done stage on the KDS, and the customer
adds a new item, the previously completed items were incorrectly reset back to
"To Prepare" stage. This module prevents that regression by preserving the stage
and todo status of previously processed prep order lines.
""",
'author': 'Suherdy Yacob',
'license': 'GPL-3',
'website': '',
'category': 'Sales/Point of Sale',
'version': '19.0.1.0.0',
'depends': ['pos_enterprise'],
'data': [],
'assets': {},
'installable': True,
'auto_install': False,
}

2
models/__init__.py Normal file
View File

@ -0,0 +1,2 @@
# -*- coding: utf-8 -*-
from . import pos_order

85
models/pos_order.py Normal file
View File

@ -0,0 +1,85 @@
# -*- 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