Odoo 16 中自定义看板控制器JS方法在部分场景(含移动端)偶发失效的问题求助
Odoo 16 中自定义看板控制器JS方法在部分场景(含移动端)偶发失效的问题求助
我正在基于Odoo 16企业版的条码模块做二次开发,需求是:当特定用户组的用户点击看板卡片打开拣货单时,自动将拣货单的preparer_id(关联res.users的Many2one字段)设置为当前用户。
现有实现逻辑
条码模块的看板视图展示拣货单,我通过patch扩展了StockBarcodeKanbanController的openRecord方法:
- 判断当前拣货单的
preparer_id是否为空 - 检查当前用户是否属于指定的拣货员组
- 如果满足条件,通过RPC更新
preparer_id为当前用户ID - 刷新视图后执行原
openRecord方法跳转到明细页面
问题现象
代码在大部分场景下正常工作,但在移动端(Odoo Mobile App)偶发失效:比如先点击PICK003,再点击PICK002,之后再次点击PICK003时,明明preparer_id是空的(我有另一个开发会在返回看板时清空该字段,且这个逻辑一直正常),但代码没有触发更新,字段保持为空。
现有代码
/** @odoo-module **/ import { StockBarcodeKanbanController } from '@stock_barcode/kanban/stock_barcode_kanban_controller'; import { patch } from 'web.utils'; import { useService } from "@web/core/utils/hooks"; import { session } from "@web/session"; const originalOpenRecord = StockBarcodeKanbanController.prototype.openRecord; patch(StockBarcodeKanbanController.prototype, 'StockBarcodeKanbanControllerIchExt', { setup() { this._super.apply(this, arguments); this.rpc = useService("rpc"); }, async openRecord(record) { // Check if preparer_id is empty if (!record.data.preparer_id) { // Check if current user is preparer (belong to preparers group) const isPreparer = await this.rpc("/web/dataset/call_kw", { model: 'res.users', method: 'has_group', args: ['ich_stock_ext.group_stock_preparer'], kwargs: {} }); if(isPreparer) { // Call RPC to update preparer_id value with the current user await this.rpc('/web/dataset/call_kw/stock.picking/write', { model: 'stock.picking', method: 'write', args: [[record.resId], { 'preparer_id': session.uid }], kwargs: {} }); // Refresh view this.model.load({reload: true}); } } // Call "super" to execute whatever the original method did return originalOpenRecord.apply(this, arguments); }, });
我的疑问
为什么会出现这种偶发失效的情况?尤其是在移动端场景下?如何修改代码确保preparer_id在所有场景下都能被正确更新?
问题分析
大概率是前端本地缓存的record数据与数据库实际数据不一致导致的:
- 当你从明细页面返回看板时,虽然后端已经清空了
preparer_id,但前端看板的record数据可能还缓存着旧值(比如之前设置的用户ID) - 移动端的Odoo视图缓存机制可能比桌面端更激进,导致
record.data.preparer_id没有及时同步最新的数据库值 - 你当前的判断逻辑依赖本地
record.data.preparer_id,如果这个值是缓存的旧数据,就会跳过更新操作
另外,this.model.load({reload: true})是全局刷新视图,在移动端可能因为网络延迟或者视图生命周期的问题,没有在跳转前完成刷新,导致后续操作还是基于旧数据。
解决方案
方案1:依赖数据库最新值做判断,而非本地缓存
修改判断逻辑,先通过RPC拉取数据库中最新的preparer_id值,再决定是否执行更新:
async openRecord(record) { // 先从数据库拉取最新的preparer_id,避免本地缓存干扰 const [latestPicking] = await this.rpc('/web/dataset/call_kw', { model: 'stock.picking', method: 'read', args: [[record.resId], ['preparer_id']], kwargs: {} }); // 判断数据库中的值是否为空 if (!latestPicking.preparer_id) { const isPreparer = await this.rpc("/web/dataset/call_kw", { model: 'res.users', method: 'has_group', args: ['ich_stock_ext.group_stock_preparer'], kwargs: {} }); if(isPreparer) { await this.rpc('/web/dataset/call_kw/stock.picking/write', { model: 'stock.picking', method: 'write', args: [[record.resId], { 'preparer_id': session.uid }], kwargs: {} }); // 手动更新本地record的数据,而非全局刷新视图 record.data.preparer_id = [session.uid, session.name]; this.model.notifyChanges(record, { preparer_id: record.data.preparer_id }); } } return originalOpenRecord.apply(this, arguments); }
方案2:优化视图刷新方式
如果必须保留本地判断,可以在返回看板时强制刷新数据,但更推荐手动更新单条record而非全局reload:
- 全局
this.model.load({reload: true})会重新加载所有数据,效率低且在移动端可能有延迟 - 用
this.model.notifyChanges只更新当前修改的record,更高效且能确保前端数据及时同步
额外建议
- 可以在移动端调试时添加
console.log(record.data.preparer_id, latestPicking.preparer_id),对比本地缓存和数据库值的差异,确认问题根源 - 检查
session.uid在移动端是否正确(理论上是一致的,但可以加日志验证)
备注:内容来源于stack exchange,提问作者forvas
相关产品推荐
相关产品推荐

