feat: add deadlock protection for prep state updates and implement status transition logic in POS KDS order component

This commit is contained in:
Suherdy Yacob 2026-06-19 10:25:24 +07:00
parent bf343df752
commit 4badd35b54
3 changed files with 67 additions and 0 deletions

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from . import pos_order from . import pos_order
from . import pos_prep_display from . import pos_prep_display
from . import pos_prep_state

22
models/pos_prep_state.py Normal file
View File

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
import logging
from odoo import models, api
_logger = logging.getLogger(__name__)
class PosPreparationState(models.Model):
_inherit = 'pos.prep.state'
def change_state_status(self, todos, prep_display_id):
if self:
# Sort IDs to guarantee consistent locking order and avoid deadlocks
sorted_ids = tuple(sorted(self.ids))
self.env.cr.execute('SELECT id FROM pos_prep_state WHERE id IN %s FOR UPDATE', [sorted_ids])
return super().change_state_status(todos, prep_display_id)
def change_state_stage(self, stages, prep_display_id):
if self:
# Sort IDs to guarantee consistent locking order and avoid deadlocks
sorted_ids = tuple(sorted(self.ids))
self.env.cr.execute('SELECT id FROM pos_prep_state WHERE id IN %s FOR UPDATE', [sorted_ids])
return super().change_state_stage(stages, prep_display_id)

View File

@ -43,6 +43,50 @@ patch(Order.prototype, {
return [{ text: String(parsed), colorIndex: 0 }]; return [{ text: String(parsed), colorIndex: 0 }];
} }
return []; return [];
},
async changeStateStageAnimation(states) {
if (states.length === this.props.order.states.length) {
await new Promise((resolve, reject) => {
this.state.changeStageTimeout = setTimeout(async () => {
try {
this.lastStageChange = await this.prepDisplay.changeStateStage(states);
this.clearChangeTimeout();
resolve();
} catch (err) {
reject(err);
}
}, 250);
});
} else {
this.lastStageChange = await this.prepDisplay.changeStateStage(states);
}
},
async changeOrderlineStatus(state) {
if (this.actionInProgress) {
return;
}
try {
this.actionInProgress = true;
const lastStage = this.prepDisplay.lastStage.id;
if (this.props.order.stage.id === lastStage) {
return;
}
const newState = !state.todo;
state.todo = newState;
if (state.prep_line_id.combo_line_ids.length > 0) {
this.getChildPreparationLineStates(state.prep_line_id).forEach((state_line) => {
state_line.todo = newState;
});
}
if (this.props.order.states.some((state) => state.todo)) {
await this.prepDisplay.syncStateStatus(this.props.order.states);
} else {
await this.changeStateStageAnimation(this.props.order.states);
}
} finally {
this.actionInProgress = false;
}
} }
}); });