先说结论
Odoo Maintenance 的工单流转,真正难的从来不是“把单从待处理拖到完成”,而是阶段一变,系统里一连串衍生状态要不要同步变正确。
从 /home/ubuntu/odoo-temp/addons/maintenance/models/maintenance.py 看,maintenance.request 的完成语义至少牵动四层东西:
stage_id.doneclose_datekanban_statemail.activity计划与反馈
所以它真正解决的问题不是:
看板上这张卡片现在在哪一列。
而是:
一张维修工单从排期到完工,如何让展示状态、统计状态和待办状态始终对齐。
第一层:为什么阶段不是纯 UI 列名
maintenance.stage 看起来很简单,核心字段之一就是 done。
这意味着阶段在 Odoo 里不是颜色标签,而是“是否已经完成”的正式语义载体。
一旦阶段有了 done 含义,它后面就能带动:
- 请求是否算未完成
- 团队待处理统计是否减少
close_date是否应当写入- 计划活动是否应当反馈/关闭
这和很多轻量看板工具不一样。后者常常允许“列只是列”,而 Odoo 明显在要求:
列位移动要能解释业务完成度。
第二层:为什么 kanban_state 在换阶段时会被重置
源码里有一段很典型的逻辑:如果 stage_id 改了,而 vals 里没有显式写 kanban_state,系统会把它重置为 normal。
这件事很容易被忽略,但其实特别合理。
因为 kanban_state 表达的是:
- 当前卡片是否 blocked
- 是否 ready for next stage
- 还是普通进行中
这些状态天然依附于“当前阶段里的处理情况”。一旦你把卡片拖进新阶段,旧阶段里的局部状态往往已经失效。
如果不自动归零,就会出现很奇怪的看板体验:
- 卡片已经进了新列
- 却还保留上一列的 blocked / ready 信号
这既误导现场人员,也会污染团队看板统计。
第三层:为什么 close_date 必须跟 done 阶段强绑定
在 create 和 write 流程里,Odoo 会做两件事:
- 如果记录落入 done 阶段,且没有
close_date,就写今天 - 如果记录离开 done 阶段,就把
close_date清掉
这说明官方不允许“表面完成”和“统计完成”分裂。
因为在维护场景里,close_date 不是装饰字段,它会影响:
- MTTR
- 完工历史
- 团队负载统计
- 后续预防性维护续生
如果用户能把卡片拖回处理中,但 close_date 还留着,就会出现统计口径前后打架。
所以 Odoo 选择把 close_date 明确绑定到 done 语义上,这是一种很值得学习的数据纪律。
第四层:为什么排期变更一定要牵动活动提醒
activity_update() 的逻辑很扎实:
- 没有
schedule_date时,删除相关维护活动 - 有
schedule_date时,尝试 reschedule 现有活动 - 如果不存在,就按当前负责人补建活动
- note 会带上设备链接,提醒内容不是空白待办
这表明 Odoo 不把维护活动视为“顺手加一个提醒”,而是把它作为维护执行链的一部分。
因为维护工单最怕的情况不是没建单,而是:
- 工单有了
- 排期改了
- 负责人换了
- 但原来的待办没更新
这样现场人员会看到错的提醒,比没有提醒更糟。
第五层:为什么 equipment_id 变化要重建活动,而不是只改字段
_need_new_activity() 现在返回的核心条件就是 equipment_id 变化。
也就是说,设备一旦换了,系统宁愿:
- 先 unlink 旧活动
- 再 schedule 新活动
而不是仅仅在旧活动上打补丁。
这说明官方认为设备变化不是小修小补,而是维护语义发生了根本变化。
因为活动 note 里会引用设备链接,负责人和排期语义也可能跟着一起变。对这种变化,重新生成一条更干净、更可信。
第六层:归档和重置为什么也是流程的一部分
archive_equipment_request() 和 reset_equipment_request() 也很值得看。
- 归档时,不只
archive=True,还会把recurring_maintenance关掉 - 重置时,不只取消归档,还会把阶段送回第一列
这说明归档在 Odoo 里不是“眼不见为净”,而是流程分叉:
- 归档代表暂时退出活动队列
- 重置代表重新进入正式处理流
尤其对维护场景来说,这很有用。因为有些工单不是删除,而是:
- 暂停
- 作废后留档
- 重新激活再走一轮
系统用 archive/reset 把这条路径保留下来了。
最容易误解的三个点
误区一:阶段只是看板展示
不是。它直接决定 done 语义和一连串衍生字段。
误区二:关闭日期可以手工随便记
也不是。它应该跟阶段完成状态保持一致。
误区三:活动提醒只是锦上添花
不是。它是排期执行链的重要组成部分。
实战上怎么用最稳
建议这样落地:
- 不要把 stage 当随意命名的列,先定义哪些阶段算 done
- 阻塞、待下一步等临时状态尽量放在
kanban_state,不要滥造阶段 - 只要改了排期或负责人,就一起验证活动是否重排正确
- 工单被打回处理中时,确认
close_date已被清空 - 暂停类工单优先用 archive/reset,而不是删单重建
最后总结
Odoo 维修工单真正成熟的地方,不是有个看板,而是它把 阶段完成语义、关闭日期、局部看板状态与活动提醒 连成了闭环。
这让 Maintenance 不只是“拖卡片”,而是一套能维持执行一致性的工单系统。
DISCUSSION
评论区