协同办公

Odoo Helpdesk 工单转任务时,到底哪些会继承、哪些不会:project、sale line 与 timesheet 边界讲透

很多人以为 Odoo 把 helpdesk ticket 转成 project task 时,会把工单上的上下文、工时、可计费信息整包搬过去。企业版源码给出的答案更克制:向导会继承项目、阶段、客户、描述,销售订单行也可跟过去,但 ticket 工时不会自动改挂到 task,且同一条 timesheet 不能同时连 ticket 和 task。

企业 协同办公
进阶 开发者 2 分钟阅读
0 评论 0 点赞 0 收藏 7 阅读

先说结论

Odoo 企业版里,把一张 helpdesk.ticket 转成 project.task,并不是“原样平移”。

project_helpdeskhelpdesk_timesheethelpdesk_sale_timesheet 三层源码叠起来看,官方其实在守三条边界:

  1. 任务语义要继承:名称、描述、客户、目标项目、目标阶段会带过去;
  2. 计费语义可以继承:如果启用了 helpdesk sale timesheet,sale_line_id 也会跟着转到 task;
  3. 工时归属不会自动改挂:已有 timesheet_ids 仍留在 ticket 侧,不会因为“转任务”自动改成 task 工时。

所以更准确的理解是:

Odoo 的工单转任务,本质是新建一个 task 作为后续执行载体,同时保留 ticket 作为历史来源;它不会替你偷偷重写既有工时账本。

这恰恰是协同办公里很重要的一种设计克制:

  • 执行对象可以切换;
  • 计费线索可以延续;
  • 但已记录的时间,不会被系统默默改写归属。

一、真正的“转任务”不是改类型,而是创建新 task 并归档 ticket

enterprise/project_helpdesk/wizard/helpdesk_ticket_convert_wizard.py 里,action_convert() 做的不是把 ticket 直接变形,而是:

  • 读取上下文里的 to_convert
  • _get_task_values(ticket) 组装任务值;
  • 批量 create() 出新的 project.task
  • 然后把原 ticket 设为 active = False
  • 最后双方各发一条消息,保留来源链路。

这说明官方建模思路很明确:

  • ticket 仍然是 ticket
  • task 是新建出来的后续执行对象
  • 两者通过消息追溯保持来源关系,而不是靠“同一条记录换个模型壳”。

这点很关键,因为只要理解成“新建 + 归档 + 留痕”,后面很多行为就说得通了:

  • 为什么旧工单还能作为历史依据;
  • 为什么不会自动把所有关联对象强行搬家;
  • 为什么消息链比字段覆盖更重要。

二、基础向导真正继承了哪些字段

_get_task_values() 在基础版 project_helpdesk 中给 task 填的核心字段非常克制:

  • name
  • description
  • project_id
  • stage_id
  • partner_id

也就是说,默认继承的是:

1. 执行标题

工单标题直接变成任务标题,方便协作团队继续沿着同一问题推进。

2. 问题描述

ticket 的 description 会进入 task,避免服务台与项目团队二次抄写。

3. 承接项目与阶段

这不是“自动猜测一个任务该去哪”,而是显式由向导决定:

  • 转到哪个 project_id
  • 落到哪个 stage_id

4. 客户上下文

partner_id 一起过去,说明任务并不是脱离客户语境的纯内部卡片。

因此,工单转任务继承的是 执行上下文,而不是一切关联数据。


三、为什么 helpdesk_timesheet 会优先给你默认“原 team 对应项目”

如果装了 helpdesk_timesheet,同名向导会覆写 _default_project_id()

逻辑非常简单但很有意味:

  • 先取待转换 tickets 的 project_id
  • 如果这些 ticket 都来自同一个项目,就把那个项目设成默认值;
  • 如果有多个项目,就按 sequence 取第一个;
  • 测试 test_wizard_default_project 也明确验证了:默认项目应当是 helpdesk team 绑定的 project。

这意味着官方并不把“转任务”理解成一次完全脱离 helpdesk 现场的跳转。

相反,它默认假设:

如果这个 helpdesk team 本来就把工单工时记到某个项目里,那么转任务时,最自然的承接项目仍是那个项目。

这是一种很典型的企业协同设计:

  • 服务台先接单;
  • 工时先沉到 team 绑定项目;
  • 真要升级成项目执行项时,默认也还是回到这条项目语义主线。

四、sale line 为什么能继承,但 timesheet 为什么不能自动继承

这里最值得写清。

sale line 的继承:是“计费语义延续”

helpdesk_sale_timesheet/wizard/helpdesk_ticket_convert_wizard.py,企业版只多做了一件事:

  • _get_task_values(ticket) 上追加 sale_line_id

对应测试 test_convert_ticket_with_sol_to_task 也明确断言:

  • 转出来的 task,应该和 ticket 拥有同一个 sale_line_id

这说明 Odoo 认可一件事:

  • 这张工单背后的可计费合同/服务订单项,往往也是后续任务的计费依据。

所以 sale_line_id 可以跟过去。

timesheet 不自动继承:是“时间账本不重写”

但你通读整个 ticket 转 task 向导会发现:

  • 没有任何地方在迁移 timesheet_ids
  • 没有任何地方把 helpdesk_ticket_id 批量改成 task_id
  • 也没有任何地方做“历史工时改挂任务”的后处理。

这不是遗漏,而是和 account.analytic.line 的约束设计严格一致。

helpdesk_timesheet/models/account_analytic_line.py 明确规定:

  • 一条 timesheet 不能同时连 task_idhelpdesk_ticket_id
  • _check_no_link_task_and_ticket() 会直接报错;
  • 当你给 timesheet 设 helpdesk_ticket_id 时,task_id 会被清掉;
  • 反过来有 task_id 时,helpdesk_ticket_id 也会被清掉。

所以系统态度非常明确:

一条工时要么属于 ticket,要么属于 task,不能两边都算。

既然如此,转任务时不自动迁移历史 timesheet,反而是更安全的选择。

因为一旦自动迁移,就等于系统替企业改写了:

  • 历史服务支持工时的归属对象;
  • 可能已经参与统计或审核的项目归类;
  • 甚至潜在的客户计费依据。

五、这意味着“转任务”更像前向切换,不像历史回填

很多实施方的直觉是:

  • 既然工单升级成任务,旧工时也应该自动算到任务里。

但源码展示的官方心智更像:

  • 从现在开始,这件事适合在 task 上继续推进;
  • 至于之前已经记在 ticket 上的工时,仍代表支持阶段的历史事实。

这就是“前向切换”而不是“历史回填”。

协同上它非常合理:

  • 一线支持先响应客户;
  • 确认需要项目团队介入后,再生成 task;
  • 后续新工时记在 task 还是继续记在 ticket,应由流程显式决定;
  • 但旧工时不该被系统悄悄重写。

六、ticket 工时本身为什么已经和 project 强绑定

再往下看 helpdesk_timesheet,你会发现 ticket 工时并不是“松散附着”。

account.analytic.line 带上 helpdesk_ticket_id 时:

  • create/write 会自动补 project_id
  • 还会补 account_id(来自 ticket 的 analytic account / project account);
  • 默认 company_id 也会尽量对齐 ticket 对应项目公司;
  • partner 也会跟 ticket 客户走。

换句话说,ticket 工时一旦落账,背后已经站着一整套:

  • 项目
  • 分析账户
  • 公司
  • 客户

所以它不是 UI 上一条“顺手打的工时”,而是已经进入成本/计费语义的业务记录。

这就更能解释:

为什么转任务不会自动重挂历史工时。

因为那样改的不是一个显示字段,而是可能连项目归集、分析维度、计费逻辑一起改。


七、team 变化时,Odoo 只自动改“未验证草稿工时”

还有一个细节,特别能看出官方边界感。

helpdesk_timesheet.models.helpdesk_ticket.write() 和对应测试里:

  • 如果 ticket 切到新的 helpdesk team,且新 team 仍支持 timesheet;
  • 未验证 的工时会改到新项目;
  • 已验证 的工时则保留原项目不动。

这和“转任务不自动迁移工时”其实是一致的设计哲学:

  • 草稿、未确认的数据可以顺着流程调整;
  • 已验证、已落定的数据不能随便改写。

因此,官方只在非常明确、风险较低的范围内做自动重挂:

  • 换 team 时,改未验证工时项目;
  • 转 task 时,不碰既有工时归属。

八、计费 ticket 转 task 后,后续 billable 逻辑为什么还能接得上

装了 helpdesk_sale_timesheet 后,ticket 上的 sale_line_id 本来就承担着:

  • 默认可计费订单项;
  • 计算剩余工时;
  • 决定 ticket 工时默认 so_line
  • 把 portal / invoice 视图接回销售单。

而转换向导把 sale_line_id 直接带到 task,意味着:

  • 这项工作从“支持工单”升级为“项目任务”后,
  • 后续任务工时仍可沿着同一条销售订单项继续计费。

也就是说,Odoo 在转换时保留的是:

  • 未来工时该如何计费 的线索;

而不是:

  • 过去已经记过的工时要改算到哪里

这个分层非常合理。


九、对实施与二开的真正启发

1. 不要把“转任务”理解成数据搬家按钮

它首先是流程切换按钮。

2. 如果你要迁移历史工时,必须当成显式业务动作设计

因为你在改写的是分析与计费归属,不是界面展示。

3. sale_line_id 能继承,不代表 timesheet_ids 也应该继承

一个是未来计费锚点,一个是历史工时账本,语义不同。

4. 需要可审计性时,官方默认做法其实更稳

ticket 归档、task 新建、消息留痕,比“原记录改模型 + 关联全搬”更容易审计。

5. 若要做自动迁移,至少先区分 validated 与 draft 工时

源码已经用 team 变更场景说明:

  • draft 可以调;
  • validated 不能乱动。

一句话记忆法

Odoo 企业版把 helpdesk ticket 转成 task 时,继承的是执行上下文和未来计费锚点,不会自动改写既有 timesheet 的历史归属。

参考源码

  • enterprise/project_helpdesk/wizard/helpdesk_ticket_convert_wizard.py
  • enterprise/project_helpdesk/tests/test_tasks_tickets_conversion.py
  • enterprise/helpdesk_timesheet/wizard/helpdesk_ticket_convert_wizard.py
  • enterprise/helpdesk_timesheet/models/account_analytic_line.py
  • enterprise/helpdesk_timesheet/models/helpdesk_ticket.py
  • enterprise/helpdesk_timesheet/tests/test_ticket_conversion.py
  • enterprise/helpdesk_sale_timesheet/wizard/helpdesk_ticket_convert_wizard.py
  • enterprise/helpdesk_sale_timesheet/tests/test_tasks_tickets_conversion_sol.py
  • enterprise/helpdesk_sale_timesheet/models/helpdesk_ticket.py

DISCUSSION

评论区

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