You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Odoo 16 中自定义看板控制器JS方法在部分场景(含移动端)偶发失效的问题求助

Odoo 16 中自定义看板控制器JS方法在部分场景(含移动端)偶发失效的问题求助

我正在基于Odoo 16企业版的条码模块做二次开发,需求是:当特定用户组的用户点击看板卡片打开拣货单时,自动将拣货单的preparer_id(关联res.users的Many2one字段)设置为当前用户。

现有实现逻辑

条码模块的看板视图展示拣货单,我通过patch扩展了StockBarcodeKanbanController的openRecord方法:

  1. 判断当前拣货单的preparer_id是否为空
  2. 检查当前用户是否属于指定的拣货员组
  3. 如果满足条件,通过RPC更新preparer_id为当前用户ID
  4. 刷新视图后执行原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数据与数据库实际数据不一致导致的:

  1. 当你从明细页面返回看板时,虽然后端已经清空了preparer_id,但前端看板的record数据可能还缓存着旧值(比如之前设置的用户ID)
  2. 移动端的Odoo视图缓存机制可能比桌面端更激进,导致record.data.preparer_id没有及时同步最新的数据库值
  3. 你当前的判断逻辑依赖本地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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 11:58:04