很多工厂把维护请求理解成“设备坏了,报个修,相关工位停掉”。但企业版 mrp_maintenance 做得更细:它不是简单加一个停机标记,而是把维护请求转换成资源日历上的 leave,并和工作中心排产一起求可用时段。
关键源码:
enterprise/mrp_maintenance/models/mrp_maintenance.pyenterprise/mrp_maintenance/tests/test_mrp_maintenance.py
一、为什么维护不是改状态,而是创建 leave
maintenance.stage 新增 create_leaves,maintenance.request 又新增 block_workcenter、recurring_leaves_count、leave_ids。这说明企业版的思路不是“维护单自己记着就行”,而是:
- 维护请求要不要真正阻塞工作中心,要由阶段和请求共同决定;
- 一旦需要阻塞,就要把这件事写进资源日历;
- 后续排产、工单计划和可用性判断都应看同一份资源占用事实。
这比单纯在 maintenance 模块里加个布尔字段可靠得多。
二、_get_unavailability_intervals() 为什么还要把设备维护并进工作中心不可用区间
mrp.workcenter._get_unavailability_intervals() 先取原有不可用区间,再额外查 maintenance_request 中属于 equipment 维护、且与当前时间窗重叠的记录,最终合并成新的 Intervals。
这个设计特别关键:
- 有些维护是针对设备,但设备本身挂在某个工作中心下;
- 如果只在设备维度记维护,不并入工作中心,排产仍可能把工单塞进来;
- 企业版通过二次合并,让“设备维护”和“工作中心不可用”在计划层看到的是同一个结果。
三、为什么系统不是按工作日历找空档,而是找“弹性可用槽”
_get_first_flexible_available_slot() 的注释写得很明确:维护可以安排在非工作时间,因此它不是普通工单排产那种“只看工作日历内空位”,而是忽略工作时间、只避开已有 leave / workorder 占用,在 700 天窗口内寻找第一个可放下指定时长的区间。
这背后有很强的制造现场现实感:
- 维修可能安排在夜间、周末;
- 只要不与现有占用冲突,就可以插进去;
- 但也不能无限搜索,所以源码设置了 700 天上限保证性能。
四、预防性维护为什么会一次性创建多个未来停机位
_recreate_leaves() 是整条链的核心。
当请求满足以下条件时:
maintenance_for == 'workcenter'- 已设
schedule_date block_workcenter = True- 当前阶段未 done,且阶段允许
create_leaves
系统会:
- 先删旧
leave_ids; - 检查期望时间是否已被工作单占掉;
- 若是预防性维护且启用 recurring,就按
recurring_leaves_count再往未来推多个周期; - 每次都重新调用
_get_first_flexible_available_slot()找真实可插入时段; - 将最终 leave 回写到 request,并在时间变化时给用户发 warning activity。
所以这里不是“复制几条维护单”那么简单,而是为未来维护窗口提前占坑。
五、最容易误解的地方
1. “勾了 block_workcenter 就必然按原时间停机”
不一定。如果原时段已有制造单占用,系统可能改排到别的可用槽,并给出 warning。
2. “done 阶段只是单据完成,不影响资源”
不对。阶段是否 done、是否 create_leaves,都会影响 leave 是否继续存在。维护单状态本身就是资源控制开关的一部分。
3. “预防性维护 recurring 就是把 request 复制 N 份”
也不对。源码复制的是资源阻塞时段,而不是简单克隆业务单据。重点在未来容量占用,而不是单据数量。
六、实战建议
- 制造实施时,要先区分“设备维护”和“工作中心维护”,两者都会影响排产,但入口不同。
- 预防性维护别只测一条 request,要连同未来重复 slot 一起看,才能发现排程挤压问题。
- 若工厂允许夜间维护,要确认用户理解“flexible slot”逻辑,否则会误以为系统排错时间。
- 时间调整 warning 不要忽略,它正是在提醒“理想维护窗口”和“真实产线占用”发生了冲突。
七、结论
Odoo 企业版制造维护的关键,不是报修单本身,而是把维护计划转成对工作中心容量的真实占用。只有这样,维护、排产和工单才不会各说各话。
DISCUSSION
评论区