企业 现场服务

Odoo 企业版现场服务为什么不是“任务点完成就结束”:销售单预确认、工时挂单与材料出库统一放行讲透

基于 industry_fsm_sale 与 industry_fsm_stock,讲清 FSM 任务完成时为何要先补销售单、再挂工时、最后统一校验材料与序列号出库。

企业 项目
进阶 开发者 1 分钟阅读
0 评论 0 点赞 0 收藏 5 阅读

很多团队把 Field Service 任务理解成“工程师上门干完,点一下 Done”。但企业版真正难的是:工时怎么挂到正确销售行、材料怎么在完工瞬间放行、序列号产品怎么跟着出库、为什么销售单常常在你还没正式完工前就被确认

这条链主要在:

  • enterprise/industry_fsm_sale/models/project_task.py
  • enterprise/industry_fsm_sale/models/account_analytic_line.py
  • enterprise/industry_fsm_stock/models/project_task.py
  • enterprise/industry_fsm_stock/models/sale_order_line.py

一、为什么 FSM 不是“先做任务,最后再补销售单”

industry_fsm_sale 里,project.task.action_fsm_validate() 在任务完成时不会直接只改状态,而是先判断这张任务是否允许 billable,以及是否存在工时或材料。如果任务需要计费,系统会调用 _fsm_ensure_sale_order(),必要时自动建单,再根据项目计价模式补销售行。

这背后的业务含义很重要:

  • 现场服务的计费对象不是 task 本身,而是 SO / SOL
  • task 只是“服务发生过”的业务上下文;
  • 真正决定后续开票、交付、利润分析的锚点,仍然是销售单。

所以 Odoo 不会把 FSM 做成一个完全脱离销售模块的闭环。

二、为什么有些销售单会在加材料之前就先 confirm

industry_fsm_stock_fsm_ensure_sale_order()_fsm_create_sale_order() 做了扩展:只要现场任务要走材料流,销售单往往要提前确认。

原因不是“界面看着更正式”,而是仓库与拣货链路已经要提前成立:

  1. 工程师在任务里点材料面板;
  2. 系统希望使用当前用户默认仓库;
  3. 如果 SO 还是 draft,等到后面再 confirm,历史销售行可能会错误继承后续用户的仓库上下文;
  4. 因此企业版宁可先 confirm,再继续追加现场材料。

这是很多实施里最容易误解的一点:FSM 的 SO 早确认,不代表业务已完全结算;它只是为了让库存路线先稳定下来。

三、工时为什么不会简单地“谁填工时就挂默认产品”

account_analytic_line._timesheet_determine_sale_line() 明确体现出企业版 FSM 的复杂度。

如果项目是 employee_rate

  • 系统先看 task 是否还在 warranty;保内任务可能根本不挂销售行;
  • 再按 project.sale.line.employee.map 把不同员工映射到不同服务产品与单价;
  • 如果对应销售行尚未生成,且任务还没真正 done,工时甚至会先不落到最终 SOL 上。

也就是说,企业版不是“工时 = 默认服务产品 × 小时数”,而是允许:

  • 不同工程师不同价;
  • 任务保内不计费;
  • 先记工时,等完工时再统一补单。

四、材料为什么要等到完工时统一 _validate_stock()

industry_fsm_stock/models/project_task.py 里的 _validate_stock() 才是现场材料真正难的地方。

它做了几件事:

  1. 找出当前 task 相关的 SO 行与 stock move;
  2. 对序列号 / 批次产品,把 fsm_lot_id 补到 move line;
  3. 如果 move line 数量不够,就自动补齐缺口;
  4. 把非 timesheet / 非 milestone 服务行的 qty_delivered 直接推到已订购数量;
  5. 只对“当前任务已经完成、或同单其他任务也已完成”的拣货做统一校验;
  6. 若 push rule 继续生成后续 picking,还会递归再跑一轮。

这说明 Odoo 的现场材料交付不是“扫了就出”,而是 按任务完成状态做批量放行。这样做有两个好处:

  • 避免同一张销售单里,尚未完成的任务把别的材料提前放行;
  • 避免序列号产品在移动链条中只改了一半 move line。

五、最容易踩坑的三个误解

1. “SO confirm 了,就该锁单”

不对。FSM 场景里,企业版特意把“确认”和“锁单”拆开。action_fsm_validate() 真正成功后,才会对满足条件的 SO 执行 action_lock()。因为现场过程中还可能继续补材料。

2. “任务保内只是发票不收钱”

也不对。保内任务在源码里经常直接影响工时是否挂 SOL、是否补服务销售行,不只是财务阶段少收一笔。

3. “材料已经生成 picking,就说明可交付”

仍然不对。真正能不能自动 button_validate(),要看是不是当前 task 对应材料、是否存在未完成关联 move、是否涉及 lot / serial 补全。

六、实战建议

  • 做 FSM 实施时,先定清楚项目 pricing_type,别让员工价和任务统一价混用后再追溯历史工时。
  • 序列号物料一定要验证 fsm_lot_id 录入路径,否则完工时最容易卡在 move line 补齐。
  • 如果客户坚持“SO 未经审批不能确认”,要提前解释:FSM 的 confirm 很多时候是库存前置动作,不等同于最终商务确认。
  • 多任务共享同一销售单时,要特别测试“部分任务 done、部分未 done”的出库边界。

七、结论

Odoo 企业版 FSM 的核心不是“任务完成”这个按钮,而是把现场服务、销售计费、库存放行三条链在 done 时刻收拢到一起。你看到的是一个完成动作,源码里处理的却是销售单锚点、工时映射、序列号出库和锁单时机。

DISCUSSION

评论区

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