如何正确修补 Odoo 16 中的 StockForecasted 组件

8次阅读

如何正确修补 Odoo 16 中的 StockForecasted 组件

在 odoo 16 中,`stockforecasted` 并未作为默认导出类暴露在模块路径中,而是注册到 `actions` 注册表中(键名为 `’replenish_report’`),直接 import 会导致 `undefined` 错误;正确方式是通过 `registry.category(“actions”).get(‘replenish_report’)` 获取该组件实例再进行 patch。

Odoo 16 的前端架构采用模块化注册机制,许多核心组件(如库存预测报表 StockForecasted)并非以标准 ES 模块方式导出,而是通过 @web/core/registry 注册到特定类别中。StockForecasted 类实际被注册为 actions 类别下的 ‘replenish_report’ 条目——这正是直接 import { StockForecasted } from “@stock/stock_forecasted/stock_forecasted” 失败的根本原因:该路径下无命名导出,控制台会抛出 TypeError: StockForecasted is undefined。

✅ 正确修补步骤如下:

  1. 确保依赖模块已加载:先 import “@stock/stock_forecasted/stock_forecasted”,触发其内部注册逻辑;
  2. 从 registry 获取组件构造函数:使用 registry.category(“actions”).get(‘replenish_report’) 获取已注册的 StockForecasted 类;
  3. 调用 patch() 进行原型增强:对 .prototype 执行 patch,并在重写方法中显式调用 await this._super(…arguments) 以保留原始逻辑。

以下是可直接使用的完整补丁代码示例:

/** @odoo-module **/  import { patch } from '@web/core/utils/patch'; import { registry } from '@web/core/registry'; import "@stock/stock_forecasted/stock_forecasted"; // 触发注册  const actionRegistry = registry.category("actions"); const StockForecasted = actionRegistry.get('replenish_report');  if (!StockForecasted) {     console.error("[Patch Error] 'replenish_report' component not found in actions registry."); } else {     patch(StockForecasted.prototype, 'test_my_stock.StockForecasted', {         async _getReportValues(...args) {             console.log('_getReportValuesInherit: patch applied successfully');             // ✅ 必须调用父类原方法,否则功能中断             await this._super(...args);              // ? 在此处插入自定义逻辑,例如动态推导 resModel:             if (!this.resModel) {                 if (this.props.action?.res_model) {                     const [modelRecord] = await this.orm.read('ir.model', [Number(this.props.action.res_model)], ['model']);                     this.resModel = modelRecord?.model || null;                 } else if (this.props.action?._originalAction) {                     try {                         const originalContext = jsON.parse(this.props.action._originalAction)?.context;                         this.resModel = originalContext?.active_model || null;                     } catch (e) {                         console.warn('Failed to parse _originalAction context', e);                     }                 }             }         },     }); }

⚠️ 注意事项:

  • 切勿省略 await this._super(…args):Odoo 的 _super 是异步代理,跳过将导致 this.context、this.orm 等关键属性未初始化,引发后续运行时错误;
  • 添加存在性校验:actionRegistry.get() 可能返回 undefined(如模块未加载或注册名变更),建议加入 if (!StockForecasted) 防御性判断;
  • 避免重复 patch:确保该 JS 文件仅被加载一次(推荐放在自定义模块的 Static/src/js/ 下,并通过 assets 清单正确引入);
  • 兼容性提示:Odoo 17+ 已重构部分 forecasted 逻辑,此方案专用于 Odoo 16,请勿直接迁移至新版。

通过 registry 机制获取并 patch 组件,是 Odoo 前端扩展的标准实践。掌握这一模式,可安全、可靠地定制包括 StockForecasted 在内的所有注册型组件行为。

text=ZqhQzanResources