公司切换与权限

Odoo 记录规则为什么会跟着 allowed_company_ids 变:_compute_domain_keys 讲透

`ir.rule` 的计算域是缓存过的,而缓存键里最关键的上下文之一就是 `allowed_company_ids`。这就是为什么切换公司后,权限结果会变。

Odoo 开发 框架
进阶 开发者 1 分钟阅读
0 评论 0 点赞 0 收藏 6 阅读

如果你做过多公司项目,应该见过这种现象:

  • 同一个用户;
  • 同一段代码;
  • 切换公司以后,看到的记录突然不一样了。

这不是偶然,而是 Odoo 记录规则本来就把公司上下文放进了计算结果里。

odoo/addons/base/models/ir_rule.py 看,ir.rule 的域不是每次都重新算的,它是带缓存的。而这个缓存最关键的上下文键之一,就是 allowed_company_ids

一、_compute_domain() 是缓存过的

_compute_domain() 不是一个普通函数。它被 ormcache 包起来,并且缓存键里会用到:

  • self.env.uid
  • self.env.su
  • model_name
  • mode
  • 以及 _compute_domain_context_values() 返回的上下文值

_compute_domain_context_values() 默认只返回:

allowed_company_ids

这意味着什么?

意味着同一个用户切换公司后,哪怕模型和操作类型没变,缓存键也可能变,因此规则域会重新计算。

二、为什么只看 allowed_company_ids

这里的设计很有意思。

Odoo 并不是把所有 context 键都塞进缓存键里,而是只挑了真正会影响规则结果的关键项。

这也符合业务直觉:

  • 公司切换会改变可见记录;
  • 但很多其他 context 值并不会影响记录规则结果;
  • 所以没必要让缓存键无限膨胀。

换句话说,allowed_company_ids 是“值得缓存区分”的那一类上下文。

三、_eval_context() 里有两个很重要的公司变量

_eval_context() 会给规则域提供这些变量:

  • company_ids:当前激活公司的列表;
  • company_id:当前主公司;
  • user:带空上下文的用户对象。

这说明记录规则里的 domain 不是纯字符串,它其实是在一个受控的上下文里求值。

所以当规则里写了类似:

['|', ('company_id', '=', False), ('company_id', 'in', company_ids)]

它就会随着当前公司切换而变化。

四、_get_rules() 决定哪些规则参与计算

_get_rules() 先从数据库里把当前模型、当前 mode、当前用户组能命中的规则找出来。

接着 _compute_domain() 会把这些规则分成两类:

  • 全局规则:没有 group 的,彼此是 AND;
  • 组规则:有 group 的,彼此是 OR,然后再并回全局域。

这就是为什么“看起来只加了一条规则”,实际效果可能会非常严格:

  • 全局规则会叠加;
  • 组规则会按角色开放不同入口;
  • 公司上下文又会再影响缓存结果。

五、调试时最该先看的不是“规则文本”,而是上下文

如果你在排查“为什么换公司后权限变了”,先别急着改 rule。

先看这些:

  1. allowed_company_ids 是什么;
  2. env.company 是哪一个;
  3. 规则里用的是 company_id 还是 company_ids
  4. 这条规则是 global 还是 group-bound;
  5. 当前是不是 sudo() 状态。

很多多公司权限问题,其实不是规则写错,而是你在错误的上下文里读它。

结论

allowed_company_ids 会影响记录规则结果,不是因为 Odoo “记错了”,而是因为它明确把公司切换当作缓存和规则语义的一部分。

理解这一点之后,你会更容易判断:

  • 这是缓存键变化带来的正常差异;
  • 还是某条规则本身真的写错了。

DISCUSSION

评论区

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