这篇不讲整条补货链,只讲“提醒”和“留痕”
库存延期一旦发生,很多人会下意识把所有日期变化看成一回事。
但在 stock.move 里,至少有两种完全不同的反馈面:
delay_alert_date:给操作人看的提醒信号_propagate_date_log_note():给业务文档留下解释痕迹的日志信号
如果把这两者混在一起,就很容易出现两种误判:
- 明明界面上亮了延期提醒,却没看到 chatter 连续刷消息,于是怀疑日志没触发
- 明明文档上写了 deadline 变化说明,却以为一定意味着 move 上的 alert 字段也会同步亮起
这篇只解释这两个信号为什么分工不同。
delay_alert_date 只回答一个问题:前序 move 已经晚过我了吗
_compute_delay_alert_date() 的逻辑相当克制。
它会:
- 跳过
done和cancel的 move - 从
move_orig_ids里挑仍在进行、且带日期的前序 move - 取这些前序 move 里最晚的
date - 如果那个最晚日期还晚于当前 move 自己的
date,就把它写进delay_alert_date
换句话说,这个字段不是在做“全供应链风险评估”,它只是回答:
按当前依赖关系看,你前一步最晚完成时间已经压过你自己的计划时间了吗?
如果答案是是,就亮提醒;不是,就不亮。
为什么它不是 chatter 机制
delay_alert_date 的职责非常偏操作层:
- 给当前 move 一个可见的延误信号
- 帮用户判断这一步是否已经被上游拖慢
它本身不负责解释给业务文档看,也不负责留下审计轨迹。
所以你在 move 上看到提醒,并不自动等于:
- PO、SO、MO 一定被连续写日志
这是设计分层,不是遗漏功能。
_propagate_date_log_note() 又在解决另一件事
到了 _propagate_date_log_note(),关注点已经不是“当前 move 是否晚了”,而是:
- 与这个 move 相关联的业务文档
- 是否需要被告知 deadline 因上游延误而变化
源码会先找:
- 上游文档
doc_orig - 当前 move 影响到的文档
documents
然后构造一条明确的人类可读说明:
- deadline 已因某个来源文档的延误而被自动更新
也就是说,这个方法做的是:
- 业务解释
- 审计留痕
- 文档级可追溯说明
它不是告警字段的重复实现。
为什么日志不会每次都疯狂追加
很多系统一旦碰到延期传播,就会在 chatter 里越写越多,最后没人愿意看。
Odoo 在这里做了一个很实用的抑制:
- 先看目标文档最近一条消息
- 如果最近一条的 subject 和这次要写的一样
- 就直接跳过
这意味着它追求的是:
- 让业务方知道 deadline 的确因为上游变化被更新过
- 但不要在同一类变化上无休止刷屏
所以“为什么有延期却没再多一条日志”,很多时候不是没传播,而是 系统判断最近已经写过同主题说明,没必要再重复。
这两个信号为什么故意分开
如果把 alert 和 chatter 留痕做成完全绑定,会出现两个问题:
1)操作提醒被文档噪音污染
用户只想知道当前 move 是否受阻,却被迫阅读大量重复说明。
2)文档审计被界面刷新频率绑架
业务解释需要稳定、可追溯,但不该随着每次字段重算无限膨胀。
所以把它们拆开其实很合理:
delay_alert_date用来感知当前依赖延误_propagate_date_log_note()用来在合适时机说明 deadline 更新原因
排查时别再把两者混成同一开关
如果你在项目里遇到“延期提醒”和“日志说明”对不上,建议按这个顺序查:
- 当前 move 是否仍处于非 done、非 cancel 状态
move_orig_ids里是否存在日期更晚的前序 move- 当前 move 是否因此算出了
delay_alert_date - 当前 move 关联到的文档集合是否为空
- 最近一条 chatter subject 是否与这次准备写入的一样
这样你就能区分:
- 是 alert 根本没触发
- 还是 alert 触发了,但日志被抑制了
- 或者文档链本身就没找到
总结
库存延期相关的两个信号,本来就不是一回事:
delay_alert_date是操作层提醒_propagate_date_log_note()是文档层留痕- 后者还会主动压制重复主题日志
如果只记一句,就记这句:
Odoo 库存延期里,“看到提醒”不等于“应该再刷一条 chatter”,因为提醒字段和日志留痕从设计上就是两套分工。
DISCUSSION
评论区