其他深度

Odoo 维修工单为什么不只是“拖看板”:阶段完成、关闭日期与活动重排闭环讲透

很多人以为 Odoo Maintenance 的核心只是建单和分派,但从 maintenance.py 的 write、activity_update、_get_activity_note 和 archive/reset 逻辑看,工单真正难的是阶段变化后,close_date、kanban_state、待办活动与归档状态如何一起收口。看懂这个闭环,维护看板才不会表面流转、底层混乱。

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

先说结论

Odoo Maintenance 的工单流转,真正难的从来不是“把单从待处理拖到完成”,而是阶段一变,系统里一连串衍生状态要不要同步变正确

/home/ubuntu/odoo-temp/addons/maintenance/models/maintenance.py 看,maintenance.request 的完成语义至少牵动四层东西:

  • stage_id.done
  • close_date
  • kanban_state
  • mail.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 语义和一连串衍生字段。

误区二:关闭日期可以手工随便记

也不是。它应该跟阶段完成状态保持一致。

误区三:活动提醒只是锦上添花

不是。它是排期执行链的重要组成部分。

实战上怎么用最稳

建议这样落地:

  1. 不要把 stage 当随意命名的列,先定义哪些阶段算 done
  2. 阻塞、待下一步等临时状态尽量放在 kanban_state,不要滥造阶段
  3. 只要改了排期或负责人,就一起验证活动是否重排正确
  4. 工单被打回处理中时,确认 close_date 已被清空
  5. 暂停类工单优先用 archive/reset,而不是删单重建

最后总结

Odoo 维修工单真正成熟的地方,不是有个看板,而是它把 阶段完成语义、关闭日期、局部看板状态与活动提醒 连成了闭环。

这让 Maintenance 不只是“拖卡片”,而是一套能维持执行一致性的工单系统。

DISCUSSION

评论区

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