工单重排

Odoo 工单为什么明明排了时间还提示冲突:Replan、时间重叠检测与甘特排程边界讲透

很多人以为工单有开始和结束时间就算排产完成,但 Odoo 还会继续检查前序工单、同工位时间重叠和重排触发条件。本文结合 mrp.workorder 源码讲清 Replan 背后的规则。

制造
进阶 开发者 1 分钟阅读
0 评论 0 点赞 0 收藏 5 阅读

先说结论

在 Odoo 里,工单“有了开始和结束时间”并不等于“排产没问题”。

系统还会继续问三件事:

  1. 它是不是排在前序工单之前了
  2. 它是不是和同一工位上的其他工单时间重叠了
  3. 当前排程是否需要通过 Replan 重新落到资源日历上

所以很多用户看到甘特图里工单已经有时间,却仍然出现黄色/红色提示,本质不是界面抽风,而是 Odoo 在区分:

  • 有时间
  • 时间合理
  • 时间可执行

一句话说透:

Odoo 的工单排程不只是在填日期,而是在验证“前后顺序”和“同资源不重叠”这两个制造约束。

_compute_json_popover() 为什么信息量这么大

addons/mrp/models/mrp_workorder.py 里,工单看板和甘特上的提示信息主要来自 _compute_json_popover()

它不是简单做个 tooltip,而是在汇总几个不同来源的风险:

  • 前序工单的 date_start / date_finished
  • 自己当前是 blocked 还是 ready
  • 当前工单是否已经晚于现在
  • _get_conflicted_workorder_ids() 查出来的同工位重叠冲突

这意味着 Odoo 的 popover 不是“显示附加信息”,而是在做一层排程质量诊断。

前序工单为什么会出现“Scheduled before the previous work order”

很多人会误以为:

  • 只要工单依赖关系已经建好
  • 系统自然会保证时间先后绝对正确

但源码并没有这么天真。

_compute_json_popover() 里,Odoo 会比较:

  • 当前工单 date_start
  • 前序工单最早开始、最晚结束时间

如果发现当前工单被排到了前序工单之前,就直接给出危险提示。

这说明依赖关系本身只是结构约束,时间表仍然可能被人工拖拽、二开写入或重排后变得不合理

所以 Odoo 还要再做一次时间上的现实校验。

同工位冲突为什么不是 Python 循环查,而是直接上 SQL OVERLAPS

_get_conflicted_workorder_ids() 很值得看。

它直接执行 SQL,对满足以下条件的工单做重叠判断:

  • 都在 blocked / ready
  • 不是同一条工单
  • 属于同一个 workcenter_id
  • 两个时间区间 OVERLAPS

这有两个很重要的含义:

1)冲突定义非常明确

Odoo 关心的不是“看起来忙不忙”,而是同一工位上两段时间区间是否真实重叠。

2)这个检查是资源层约束,不是工艺层约束

即使你的前后工序逻辑没问题,只要同工位时间撞上,系统仍然认为排程有冲突。

这就是为什么有些现场会说:

  • 工艺顺序没错
  • 但甘特图还是报警

因为报的不是工艺错误,而是资源占用错误。

Replan 到底重排了什么

action_replan() 的实现很直接:

  • 它不是只重排当前工单
  • 而是对关联制造单调用 production._plan_workorders(replan=True)

这点非常关键。

意味着 Replan 不是一个局部“把我这条工单挪一挪”的按钮,而是:

以制造单为单位,重新把 ready / blocked 的工单放回整体排程逻辑里。

所以现场点一次 Replan,看到多道工序时间一起变化,不是副作用,而是设计本意。

工单的 date_start / date_finished 实际上关联到 leave_id 上的资源日历占用。

源码里还特别解释:

  • 如果甘特拖拽同时改开始/结束
  • ORM 对 related 字段可能分多次 write
  • 会导致日期约束误触发

所以 Odoo 才写了 _compute_dates() / _set_dates() 这一套,确保时间更新能成对落地。

这提醒我们:

工单时间不是普通表单字段,它本质上是资源日历上的占位记录。

也正因为如此,排程问题往往要同时看:

  • 工单本身
  • leave_id
  • 工位日历
  • 是否重排成功

新手最容易误解的点

1)有开始和结束时间,不代表没有冲突

时间存在,只说明“排过”;不说明“排对了”。

2)依赖关系存在,不代表时间先后一定合理

人工拖拽、批量修改、定制写入都可能把时间搞反。

3)Replan 不是只动当前一条工单

它会把同制造单下相关 ready / blocked 工单一起纳入重排。

4)工单时间不是纯展示字段

它背后对应资源日历 leave,占的是工位资源能力。

实施和开发注意点

一,培训时别把甘特图讲成“排上时间就好了”

必须让计划员理解两层约束:

  • 工艺先后约束
  • 同工位资源占用约束

只理解第一层,看到红色警告就会一头雾水。

二,二开别直接粗暴写 date_start / date_finished

如果不了解 leave_id 和重排逻辑,只改表面字段,很容易制造出:

  • 时间看起来改了
  • 资源占位没同步
  • popover 一直报警

三,排错建议顺序

  1. 看当前工单是否 blocked / ready
  2. blocked_by_workorder_ids 的开始和结束时间
  3. _get_conflicted_workorder_ids() 这一类冲突判断思路,确认是否同工位重叠
  4. 再判断是否需要通过 Replan 让整张 MO 重新排程

最后总结

Odoo 的工单排程不是“写入两个日期字段”这么简单。

它至少同时在校验三层东西:

  • 前序工单是否先完成
  • 同工位资源是否时间重叠
  • 当前时间是否真的已落到资源日历上

所以工单有时间却仍然报冲突,并不奇怪。

一句话记住:

在 Odoo 里,排产成功不是“有时间”,而是“顺序对、资源不撞、日历落得住”。

DISCUSSION

评论区

想参与讨论?先 登录 再发表评论。
还没有评论,你可以成为第一个留言的人。