
在 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。
✅ 正确修补步骤如下:
- 确保依赖模块已加载:先 import “@stock/stock_forecasted/stock_forecasted”,触发其内部注册逻辑;
- 从 registry 获取组件构造函数:使用 registry.category(“actions”).get(‘replenish_report’) 获取已注册的 StockForecasted 类;
- 调用 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 在内的所有注册型组件行为。