先说结论
Odoo 的任务模板不是“选一条旧任务复制一下”。
从 project.task.action_create_from_template()、_get_template_field_blacklist()、project.template.create.wizard 和官方测试看,模板复制有三个明确目标:
- 保留结构,而不是照搬全部业务关系
- 复制子任务树,但避免把模板本身继续当成模板实例发出去
- 在项目级模板落地时,用角色映射把抽象责任转成真实成员
一句话说:
Odoo 模板复制保的是协作骨架,不是历史脏数据。
为什么模板复制要先做字段黑名单
_get_template_field_blacklist() 默认会把 partner_id 清空。
这一步非常有代表性。
因为模板的目标是复用流程,不是复用历史客户关系。
如果模板实例化时直接继承旧客户,最容易出现:
- 新项目任务误挂到旧客户
- 后续邮件、评分、门户访问都串线
- 团队以为只是“复制了结构”,其实复制了外部关系
官方明确把这类字段列入黑名单,说明模板复制的第一原则是:
保留流程结构,断开具体业务对象。
为什么子任务也会被一起复制
官方测试 test_create_from_template() 明确验证:
- 模板任务实例化时,子任务也会被复制
- 子任务也不再是 template
这说明 Odoo 认为模板最有价值的部分,往往不是单张卡片,而是:
- 父子层级
- 标准拆解顺序
- 固定检查清单
如果只复制父任务不复制子树,很多 SOP 模板就失去意义了。
为什么复制出的实例必须脱离 template 身份
测试还验证:从模板 action 创建出来的新任务 is_template=False。
这很重要。
否则真实执行任务会继续被当成模板:
- 报表被污染
- 搜索条件错位
- 自动化逻辑误把执行任务当标准件
所以 Odoo 很清楚:模板和实例必须在语义上切干净。
为什么项目模板还要加角色映射
project.template.create.wizard 里除了基本字段,还专门有 role_to_users_ids。
这说明项目模板不是只复制任务树,还要解决一个更实际的问题:
- 模板里只能先写角色
- 真正创建项目时,才知道当前是谁来做这些角色
这是协同办公里非常典型的需求。
比如同一套上线项目模板,A 客户项目和 B 客户项目的真实成员可能完全不同,但:
- PM
- 实施
- 顾问
- 验收接口人
这些职责位点是稳定的。
模板里放角色,落地时映射用户,远比模板里硬编码具体员工稳得多。
为什么项目模板还能顺手复制 alias 等基础设置
wizard 的白名单字段里还包括:
namedate_startdatealias_namealias_domain_id
这说明从模板创建项目,不只是生成任务,还会把协作入口一起落地。
尤其邮件 alias 很关键。
因为一个可复用项目模板,往往不止是一堆任务结构,还包含:
- 收件入口
- 截止框架
- 任务接收机制
这让模板从“复制 checklist”升级成“复制协作操作系统”。
最容易踩的误区
误区一:希望模板把所有历史字段都原样带过去
那样复制出来的大概率不是模板实例,而是历史事故复刻。
误区二:模板里直接写死真实员工
角色稳定,人员不稳定。把人硬编码进模板,维护成本很高。
误区三:把模板任务混进普通任务视图做统计
源码和视图层都在努力把 template / instance 分开看,别反着来。
排错顺序
如果用户说“为什么从模板创建后字段不对”,建议查:
- 这个字段是不是模板黑名单字段
- 模板项目本身是否带了 project partner,导致实例用项目 partner 补回
- 子任务是不是预期也应一起复制
- 当前创建的是 task template 还是 project template
- 角色映射是否在创建项目时正确填入
一句话记忆
Odoo 模板复制的目标不是复制过去,而是把一套可执行协作结构,干净地落到新的真实项目里。
DISCUSSION
评论区