介绍
在Odoo数据模型中,公司依赖字段是一个较少被提及的特性。它是一个小属性,但一旦开始使用多公司配置,就会产生很大的不同。
在大多数Odoo设置中,记录上的字段持有一个所有用户都能看到的单一值。但是,当两家公司共享相同的产品目录,而每家公司需要自己的内部参考代码时,会发生什么?或者当不同公司在同一产品上需要不同的默认账户时呢?
这正是company_dependent属性解决的问题。无论您是在进行Odoo开发、Odoo自定义,还是仅仅在探索Odoo框架,理解这种字段类型将使您在多公司项目中获得真正的优势。
Odoo中的公司依赖字段是什么
一个 公司依赖字段 是一个在同一记录中为每个公司存储单独值的字段。当属于公司 A 的用户读取该字段时,他们看到的是他们公司的值。当来自公司 B 的用户读取相同记录时,他们看到的是不同的值。
从外部来看,它看起来和行为都像一个普通字段。用户在 Odoo 界面中以相同的方式与其交互。魔法发生在 Odoo ORM 的后台。
它在界面中的显示
在 Odoo UI 中,公司依赖字段看起来与常规字段完全相同。没有可见的指示告诉用户他们看到的值是特定于公司的。这是故意的:这种行为对最终用户是透明的。
从开发者的角度来看,这是 Odoo 字段类型之一,可以应用于许多基本类型:Char、Boolean、Integer、Float、Many2one 等。company_dependent=True 属性是激活 Odoo ORM 中这种行为的关键。
在 Odoo Studio 中,一些公司依赖字段已经在标准模型上暴露(例如与账户相关的产品字段)。也可以创建自定义公司依赖字段,不过在某些 Odoo 版本中,Studio 对此特定属性的支持有限。
字段是如何工作的
在后台,公司依赖字段的工作方式与常规字段非常不同。理解这一机制有助于在构建或调试 Odoo 自定义时避免意外。
存储在 ir.property 中
在 Odoo 16 及更早版本中,公司依赖字段值并不存储在模型自己的数据库表中。相反,它们存储在一个名为 ir.property 的单独系统表中。
ir.property 中的每个条目链接:
- 一个特定记录(例如,ID 为 42 的产品)
- 一个特定字段(例如,
property_account_income_id) - 特定公司
- 该组合的实际值
这就是为什么这些值对用户看起来是透明的原因:ORM根据当前公司上下文自动检索和写入ir.property。
Odoo 17+中的变化
从Odoo 17开始,存储机制进行了重构。公司相关字段现在直接存储在模型的表中,使用jsonb列,公司值作为JSON字典存储。这显著提高了性能并简化了查询。
接口和面向开发者的API保持不变,但对公司相关字段的查询在规模上现在要快得多。
默认值
公司相关字段支持公司特定的默认值。当某个公司没有明确设置值时,该字段将回退到字段本身定义的默认值。此默认值也可以通过ir.property模型(Odoo 16及更早版本)或直接在模型上(Odoo 17+)为每个公司设置。
与ORM的交互
在odoo orm上下文中,访问公司相关字段始终遵循环境中的当前公司(self.env.company)。这意味着:
- 读取字段返回活动公司的值
- 写入字段仅更新活动公司的值
- 切换公司上下文(
record.with_company(company))可以让您读取或写入特定公司的值
商业用例
公司依赖字段不仅仅是一个技术上的好奇心。它解决了多公司Odoo设置中的真实日常问题。以下是五个常见场景,展示了它真正的价值。
1. 会计:按公司划分的收入和支出账户
这是Odoo开箱即用中最常见的例子。产品上的property_account_income_id和property_account_expense_id字段是公司依赖的。
在实践中:公司A与公司B销售相同的产品,但每家公司有不同的会计科目表。每家公司只需配置自己的会计条目,而不是重复产品记录。产品是共享的;会计逻辑则不是。
2. 销售和客户关系管理:按公司划分的价格表
在一个运营多个销售实体的集团中,每家公司可能会使用不同的定价策略。通过公司依赖的价格表字段,共享的客户记录可以根据处理销售的公司携带不同的默认价格表。
这使得CRM数据集中管理,同时允许每家公司应用自己的商业规则。
3. 库存:按公司划分的库存估值方法
一些集团在多个法律实体之间运营仓库,面临不同的地方规定。一个产品在一个国家可能需要FIFO成本,而在另一个国家则需要平均成本。使用产品或类别上的公司依赖字段可以避免重复整个产品目录。
4. 制造:按公司划分的默认供应商
当共享产品根据公司从不同供应商处购买时,指向res.partner的公司依赖many2one字段可以保存每个实体的首选供应商。每家公司都可以看到自己的首选供应商,而不会发生冲突。
5. 自定义字段用于监管数据
在多个国家运营的集团通常需要在共享记录上存储特定于国家的合规参考。例如,一个产品可能需要根据不同的司法管辖区使用不同的HS编码或税务分类。公司依赖的 Char 字段是一种干净、低开销的处理方式,无需创建模型变体。
创建或自定义字段
在Odoo中创建公司依赖字段主要有两种方法:使用Odoo Studio或直接编写Python代码。
使用Odoo Studio
Odoo Studio允许您在没有任何代码的情况下创建字段。然而,Studio并未在所有版本中提供专门的 company_dependent 切换选项。在Odoo 16和17中,在标准模型上创建新字段时,某些字段类型提供了该选项。
如果您需要对该属性进行全面控制,技术开发是更可靠的方法。Studio是处理简单案例的良好起点,但在高级Odoo自定义场景中存在限制。
技术方法:Python字段
在自定义Odoo模块中,声明一个公司依赖字段是简单的。这是Odoo Python字段开发中使用的标准模式:
from odoo import fields, models
class ProductTemplate(models.Model):
_inherit = 'product.template'
x_internal_ref = fields.Char(
string='内部参考(按公司)',
company_dependent=True,
)
x_preferred_carrier_id = fields.Many2one(
comodel_name='res.partner',
string='首选承运人',
company_dependent=True,
)
在任何字段声明中添加 company_dependent=True 就足够了。ORM会自动处理其余部分。
按公司设置默认值
在Odoo 16及更早版本中,您可以通过 ir.property 模型设置公司级别的默认值。当您希望为公司中的所有记录设置一个合理的默认值,而无需逐条记录设置时,这非常有用:
self.env['ir.property']._set_default(
'x_internal_ref',
'product.template',
'DEFAULT-VALUE',
company_id=self.env.company.id,
)
在 Odoo 17+ 中,默认值直接存储在模型记录上,并且可以通过字段定义访问。
Odoo Studio 字段及其限制
在使用 Odoo Studio 字段时,请记住,自定义字段需要 x_ 前缀。公司依赖的行为可能在 Studio UI 中不可见,但如果开发者模式处于激活状态,仍然可以通过设置下的技术菜单进行配置。
最佳实践
一旦了解了模式,与公司依赖字段的工作就变得简单。以下是一些可以节省时间并避免麻烦的实践。
1. 仅在值确实因公司而异时使用
公司依赖字段增加了复杂性。如果所有公司的值相同,请使用常规字段。将 company_dependent=True 保留给那些不同公司确实需要在共享记录上有不同值的字段。
2. 始终在多公司环境中测试
在构建或测试涉及公司依赖字段的功能时,始终至少激活两家公司进行测试。在单公司设置中容易遗漏的问题会立即在生产环境中显现。
3. 使用 with_company() 进行跨公司操作
如果您的代码需要读取或写入当前公司以外的公司的公司依赖字段值,请使用 record.with_company(target_company)。避免在不恢复环境公司的情况下手动切换环境公司。
4. 导出和导入时要小心
当导出包含公司依赖字段的记录时,导出的值反映的是执行导出的用户所在公司的信息。在不同公司上下文中导入相同文件时,将为该公司设置值。这通常是正确的行为,但在迁移和数据导入工作流程中要明确说明。
5. 记录哪些字段是公司依赖的
最终用户很少知道哪些字段是公司依赖的。在您的内部 Odoo 文档或入职材料中添加简短的说明会大有帮助。这可以防止用户在切换公司时看到同一记录上不同的值而感到困惑。
6. 对于结构化数据,优先使用 Many2one 而非 Char
当每个公司的值是对另一个记录(账户、价格表、合作伙伴)的引用时,使用一个 Many2one 公司依赖字段,而不是将名称存储为文本。这可以保持数据模型的整洁,并使报告更加可靠。
常见陷阱
即使是经验丰富的 Odoo 开发人员也会遇到公司依赖字段的问题。知道需要注意什么可以防止浪费调试时间。
陷阱 1:在自动化操作中忘记公司上下文
计划操作和服务器操作通常在一个上下文中运行,其中公司是数据库中的第一个公司,而不一定是您所期望的公司。如果您的自动化操作读取或写入公司依赖字段,请明确验证公司上下文。使用 with_company() 来确保安全。
陷阱 2:假设字段像计算字段一样工作
公司依赖字段不是计算字段。它们没有 compute 方法。每个公司的变体来自存储,而不是计算。尝试将 compute= 与 company_dependent=True 一起添加将不会按预期工作,并可能导致 Odoo 框架中的错误。
陷阱 3:跨公司搜索
标准 ORM 在公司依赖字段上的搜索仅返回与当前公司上下文匹配的结果。如果您需要跨所有公司进行搜索,您需要直接查询 ir.property(Odoo 16 及更早版本)或小心处理 jsonb 列(Odoo 17+)。这是报告和数据提取工作中常见的混淆来源。
陷阱 4:未为所有公司设置默认值
当您在实时系统中引入一个依赖于公司的字段时,现有记录将对任何未明确设置值的公司返回 False 或 None。如果您的业务逻辑期望有一个默认值,请使用数据迁移脚本主动为所有相关公司设置它。
陷阱 5:将其与访问权限混淆
依赖于公司的字段控制显示的值,而不是用户是否可以看到该字段。如果您需要完全隐藏某些公司或用户的字段,这应该由记录规则或字段级访问权限来处理,而不是 company_dependent。
结论
依赖于公司的字段 是 Odoo 中的一项功能,直到您需要它时才会感到它的存在,然后它变得不可或缺。它是任何需要在不同公司之间携带不同值的记录的正确工具:会计配置、定价规则、法规参考或任何因法律实体而异的业务特定属性。
理解它在 ORM 层面的工作原理、哪个版本的 Odoo 更改了存储模型以及需要避免的陷阱,将为您在多公司项目上节省大量时间。无论您是在标准 Odoo 开发者指南中遇到它,还是在调试实时系统时发现它,了解这种字段类型都是 Odoo 真正专业知识的标志。
如果您正在基于 Odoo 框架构建并需要干净地处理每个公司的数据,company_dependent=True 是您一直在寻找的答案。
需要帮助进行Odoo实施吗?
在 Dasolo,我们帮助公司在所有规模和配置中实施、定制和优化 Odoo,包括复杂的多公司设置。无论您需要量身定制的数据模型、自定义字段策略,还是全面的 Odoo 部署,我们的团队都具备技术和功能深度,以确保正确实施。
如果您对依赖于公司的字段或 Odoo 实施的任何其他方面有疑问,我们很乐意提供帮助。 与我们联系 让我们谈谈您正在构建的内容。