先说结论
Odoo 里的多公司项目,不是给 project.project.company_id 改个值就结束。
如果你去看 /home/ubuntu/odoo-temp/addons/project/tests/test_multicompany.py 和 addons/project/models/project_project.py,会发现官方维护的是一组联动约束:
- 项目公司
company_id - 项目分析账户
account_id - 客户
partner_id - 任务
project.task.company_id - 以及用户当前允许访问的公司上下文
所以多公司下最常见的几个“怪现象”其实都很合理:
- 项目不能改公司
- 任务跟着项目一起换公司
- 某个任务改公司后直接脱离项目,变成 private task
- 分析账户一旦已有分录,项目公司就不能随便挪
本质上,Odoo 在保护的不是表面字段,而是:经营归属、分析口径和权限边界的一致性。
第一层:项目公司不是装饰字段,而是经营边界
在很多实施讨论里,项目的公司字段常被误解成“主要用来筛选视图”。
实际上不是。
从测试可以看出,项目公司至少影响三类事情:
- 用户是否有权创建 / 修改该项目
- 分析账户的公司是否要同步
- 项目下任务的公司归属是否要重算
这说明 company_id 是经营边界,不是皮肤设置。
所以当用户说:
这个项目其实应该放到 B 公司,直接改一下吧
你真正需要问的是:
- 它已经挂了分析账户吗?
- 这个分析账户有分录吗?
- 这个账户是否被多个项目共用?
- 下面任务是否已经形成了别的公司归属?
第二层:为什么分析账户会把项目公司“钉住”
project_project.py 的 _compute_company_id 和 _inverse_company_id 很值得反复看。
官方明确表达了一个原则:
- 如果分析账户有公司,项目通常要跟着这个公司走
- 如果你想把项目公司改掉,但分析账户已有分析分录,或者被多个项目共用,系统会阻止
原因其实非常朴素:
1. 分析账户代表的是经营归属
项目不是孤立对象,它背后往往连接:
- 工时
- 成本
- 收入
- 利润分析
一旦这些东西已经发生,再硬改公司,就等于改经营口径。
2. 一个账户挂多个项目时,不能允许单边漂移
如果同一个 analytic account 绑了多个项目,你把其中一个项目挪到别的公司,就会破坏“一套分析账对应一个一致归属”的前提。
所以系统报错,不是死板,而是在防止经营数据变脏。
第三层:为什么任务会跟着项目改公司
多公司测试里有个很容易被忽视的重点:
- 给任务设置项目时,任务公司会被自动对齐到项目公司
- 移动任务到另一个项目时,任务公司也会切换
- 父任务换项目时,子任务公司也会跟着联动
这说明在 Odoo 看来:
项目任务默认不是独立经营实体,而是项目边界下的执行记录。
因此大多数情况下,任务公司应该继承项目,而不是各玩各的。
这也是为什么“任务换项目”从来不只是 UI 上换个 Many2one,它会带着公司语义一起重算。
第四层:为什么任务一改单独公司,可能直接掉成 private task
这是很多人第一次看到会震惊的行为。
测试里明确验证了:
- 如果项目已有公司
- 你把任务手工改成另一个公司
- 这个任务可能会脱离项目,变成
project_id = False的 private task
为什么?
因为系统必须在两个事实之间选一个:
- 任务属于项目
- 任务属于另一个公司
当这两个事实冲突时,Odoo 选择保留公司一致性,而不是保留“挂在项目下面”的表象。
这其实很合理。
否则你会得到一种更糟糕的数据:
- 名义上挂在 A 公司项目下
- 实际上任务属于 B 公司
- 权限、统计、分析、过滤全部混乱
所以它宁可把任务打回 private,也不允许这种混挂长期存在。
第五层:partner 也是约束链的一部分
还有一个很常被忽略的约束:
- 如果项目或任务绑定了有公司归属的 partner
- 那么 company 不能随便和 partner.company_id 冲突
这背后的思路很一致:
- 客户归属要对
- 项目归属要对
- 分析账户归属要对
- 任务归属也要对
只有这样,客户维度、公司维度和利润维度才不会打架。
第六层:多公司排错时,最有效的顺序是什么
如果你遇到:
- 改项目公司报错
- 项目创建后 company 不如预期
- 任务移动后公司变了
- 任务突然不在项目里了
建议按这个顺序查:
1. 先看用户允许的公司上下文
很多“不能操作”并不是模型限制,而是当前用户根本不在 allowed_company_ids 里。
2. 再看项目的分析账户
确认:
- 是否已有
account_id - 账户公司是谁
- 是否已有 analytic lines
- 是否被多个项目共用
3. 再看 partner 是否带公司
客户如果本身带公司限制,会把项目和任务的可改动空间进一步收紧。
4. 最后看任务是不是因为公司冲突被打成 private
这一步尤其容易在“手工改任务公司”或“跨项目移动子任务”时出现。
实施建议:不要把“调公司”当日常修数据手段
很多团队上线后,会把 company 当成一个可随时修正的普通字段。我的建议是别这么干。
更稳的做法是:
- 新建项目前先确认所属公司
- 分析账户策略先定清楚
- 尽量避免多个公司之间“先做后改归属”
- 真要迁移,先评估 analytic lines 和项目共享关系
否则你修的不是一个字段,而是在撬一整条经营链路。
最后一句
多公司项目的复杂点,不在权限本身,而在 Odoo 很清楚地知道:
项目不是孤立卡片,而是分析、客户、任务和经营归属的交汇点。
所以当系统不让你随便改公司时,通常不是在为难你,而是在阻止后面更难收拾的数据错位。
DISCUSSION
评论区