先说结论
Odoo 的 Stock Rules Report,最不该被理解成“把库存路线画出来给你看看”。
它真正的价值是:
把某个产品在某个仓库视角下,沿着库位和规则递归命中的补货链可视化。
所以它最适合回答的问题不是:
- 我们系统里配置了哪些 route?
而是:
- 对这件产品、这个仓库、这个目标库位来说,系统到底会命中哪条规则链?
- 为什么链条在某一步断了?
- 为什么这里看起来应该能补,系统却补不到?
这就是“路线图”和“诊断工具”的根本区别。
为什么它不是普通 route 图
如果只是画 route 图,系统完全可以:
- 把 route、rule、location 读出来;
- 按配置关系连个线。
但 Odoo 的这份报告不是从“配置台账”出发,而是从:
- 某个具体 product;
- 某个 warehouse 组合;
- 某个 location 递归追规则。
也就是说,它不是问“系统里有什么路”,而是在问:
这个具体场景下,系统会走哪条路。
这就天然更偏排错。
入口为什么叫 action_open_routes_diagram()
在 product.py 里,入口方法是 action_open_routes_diagram()。
这个名字很容易让人误会成纯展示。
但你看内部逻辑会发现:
- 如果用户没有多仓权限且产品唯一,Odoo 甚至会直接触发 report action;
- 否则才先弹出
stock.rules.report向导,让你选仓库后打印。
这说明“diagram”只是表现形式。 真正业务目的是:
- 在给定产品和仓库上下文下,生成一份可用来判断规则命中的报告。
stock.rules.report 向导本身其实很薄
addons/stock/wizard/stock_rules_report.py 里的 transient model 很轻:
default_get()根据上下文补产品和默认仓库;_prepare_report_data()只整理product_id、warehouse_ids;print_report()直接调用 report action。
这层设计很有意思:
- 向导不负责业务推导;
- 向导只负责收集你想诊断的上下文。
这也意味着,真正有价值的逻辑在报表背后,不在弹窗表单本身。
核心抓手:_get_rules_from_location()
最值得盯住的方法,是 product.py 里的 _get_rules_from_location()。
这个方法的工作方式非常关键:
- 从当前 location 的 warehouse 视角出发;
- 调用
stock.rule._get_rule(...)找当前命中的 rule; - 如果没找到,就返回现有 seen_rules;
- 如果找到的 rule 已经见过,直接抛错,防止 endless loop;
- 如果 rule 是
make_to_stock,或者 action 不是pull/pull_push,递归停止; - 否则继续往
rule.location_src_id递归找上游规则。
这段逻辑几乎把这份报告的灵魂讲完了。
因为它说明:
报告不是平铺所有规则,而是递归还原“这个需求会被谁往上游继续拉”。
为什么递归方向这么重要
很多人理解库存路线时,会下意识从“供给仓往需求仓”顺着看。
但补货诊断往往更适合反着看:
- 这个目标库位要货;
- 系统打算从哪里补;
- 那个来源地如果自己没货,又会继续向哪里拉;
- 直到链条结束,或者断掉。
_get_rules_from_location() 选择的正是这种逆向还原思路。
这也是为什么它特别适合查:
- 缺少上游规则;
- route 选错仓;
- pull chain 在中间断裂;
- 配置出现循环依赖。
seen_rules 和 endless loop 防护说明了什么
源码里一旦发现某条 rule 已经出现在 seen_rules 里,就直接抛:
Invalid rule's configuration, ... causes an endless loop
这个保护特别值得实施顾问重视。
因为它说明 Odoo 官方非常清楚:
- route / rule 的问题不只是“找不到路”;
- 还可能是“路绕成了圈”。
所以这份报告不是装饰性图表,而是有明确防错语义的配置诊断工具。
为什么 make_to_stock 会让递归停下
当 rule 的 procure_method 是 make_to_stock,或者 action 不属于 pull/pull_push 时,方法就不再继续往上追。
这背后的业务逻辑是:
- 一旦来到 make_to_stock,系统认为需求到这里就交给本地库存语义解决;
- 它不再把这个节点继续解释成一条上游拉动链。
所以报告展现的不是“所有可能的库存动作”,而是:
- 这条补货需求会沿着 pull 逻辑追到哪里为止。
这也是它和完整库存全景图区别最大的地方。
这份报告最适合查什么问题
最典型的,是这三类:
1. 某个仓 / 某个库位为什么补不到货
你想知道不是“有没有 route”,而是“当前产品在这里到底命中了哪条 rule”。
2. 为什么系统停在中间某个位置,不再往上游补
往往是:
- rule action 不再属于 pull 系;
- 或者命中了 make_to_stock;
- 或者根本没有匹配到 rule。
3. 为什么改完 route 后反而报循环或异常
这时 seen_rules 防护就很容易帮你识别配置闭环。
为什么它不适合拿来当执行结果证明
Stock Rules Report 说到底还是规则命中解释。
它并不等于:
- procurement 一定会成功;
- 采购单 / 调拨单一定会被创建;
- lead time、供应商、库存可用量一定都满足。
因为真正执行时还要受这些影响:
- 供应商配置;
- 补货量;
- 调度器是否跑到;
- 多公司、多仓、库存可用量;
- 各类业务规则是否完整。
所以你应该把这份报告当成:
规则链解释器
而不是:
执行结果保证书。
实施排错的推荐顺序
如果现场说“这件货明明有路线,但就是补不过来”,建议这么查:
- 先打开 Stock Rules Report,看目标仓下的规则链有没有命中;
- 如果链条断了,回看
_get_rules_from_location()对应节点的 location 和 route; - 如果链条成环,优先拆循环,而不是继续补别的规则;
- 只有规则链解释清楚后,再去看 procurement、供应商、在途和可用量问题。
也就是说:
- 先查“有没有一条说得通的路”;
- 再查“这条路能不能真正走通”。
一句话总结
Odoo 的 stock.rules.report 不是一张好看的流程图。
它真正的价值在于:
- 围绕具体产品和仓库上下文,
- 递归还原规则链,
- 暴露链条断点、错误终点和循环依赖,
- 帮你判断“为什么系统没有按你以为的方式补货”。
最准确的理解是:
它是 route 配置的诊断镜,不是 route 配置的宣传册。
DISCUSSION
评论区