多公司指南?

警告

本教程需要對Odoo有良好的了解。如有需要,請先參考 開始 教程。

從13.0版本開始,用戶可以同時登錄多個公司。這使用戶可以訪問多個公司的信息,同時在多公司環境中創建/編輯記錄。

如果處理不當,它可能是導致許多不一致的多公司行為的根源。例如,一個用戶同時登錄公司A和B,可以在公司A中創建銷售訂單并添加屬于公司B的產品。只有當用戶從公司B注銷時,銷售訂單才會出現訪問錯誤。

為了正確管理多公司行為,Odoo的ORM提供了多種功能:

與公司相關的字段?

當一條記錄可以從多個公司獲取時,我們必須預期根據設置值的公司不同,給定字段將分配不同的值。

如果要使同一記錄的字段支持多個值,則必須將其定義為具有屬性 company_dependent 并將其設置為 True 。

from odoo import api, fields, models

class Record(models.Model):
    _name = 'record.public'

    info = fields.Text()
    company_info = fields.Text(company_dependent=True)
    display_info = fields.Text(string='Infos', compute='_compute_display_info')

    @api.depends_context('company')
    def _compute_display_info(self):
        for record in self:
            record.display_info = record.info + record.company_info

注解

_compute_display_info 方法被修飾為 depends_context('company') (參見 depends_context ),以確保計算字段根據當前公司( self.env.company )重新計算。

當讀取一個與公司相關的字段時,當前公司將被用來檢索其值。換句話說,如果用戶在公司A和B中登錄,A是主要公司,并為公司B創建記錄,則公司相關字段的值將是公司A的值。

為了讀取從其他公司設置的與公司相關的字段的值,我們需要確保使用的公司是正確的。這可以通過使用 with_company() 來實現,它會更新當前公司。

# Accessed as main company (self.env.company)
val = record.company_dependent_field

# Accessed as desired company (company_B)
val = record.with_company(company_B).company_dependent_field
# record.with_company(company_B).env.company == company_B

警告

每當您計算/創建/…可能在不同公司中表現不同的事物時,您應確保您所做的事情是在正確的公司中完成的。始終使用 with_company 可以避免以后出現問題,成本不高。

@api.onchange('field_name')
def _onchange_field_name(self):
 self = self.with_company(self.company_id)
 ...

@api.depends('field_2')
def _compute_field_3(self):
 for record in self:
   record = record.with_company(record.company_id)
   ...

多公司一致性?

當一條記錄通過 company_id 字段被多個公司共享時,我們必須注意不能通過關系字段將其鏈接到另一個公司的記錄上。例如,我們不希望銷售訂單和其發票屬于不同的公司。

為確保多公司的一致性,您必須:

  • 將類屬性 _check_company_auto 設置為 True 。

  • 如果模型具有 company_id 字段,請使用屬性 check_company 設置為 True 來定義關系字段。

在每次 create()write() 操作時,會自動觸發檢查以確保記錄的多公司一致性。

from odoo import fields, models

class Record(models.Model):
    _name = 'record.shareable'
    _check_company_auto = True

    company_id = fields.Many2one('res.company')
    other_record_id = fields.Many2one('other.record', check_company=True)

注解

字段 company_id 不應該定義為 check_company=True 。

Model._check_company(fnames=None)[源代碼]?

檢查給定字段名稱的值的公司。

參數

fnames (list) – 要檢查的關系字段的名稱

引發

UserError – 如果任何字段的值的 company_id 不在 [False, self.company_id] (或者 self 如果是 res_company )。

對于 res_users 的關聯字段,驗證記錄的公司是否在 company_ids 字段中。

用戶A是主公司,可以訪問公司A和B,但是可能會被分配或鏈接到公司B的記錄中。

警告

check_company 功能執行嚴格檢查!這意味著如果記錄沒有 company_id (即該字段不是必需的),則無法將其鏈接到 company_id 已設置的記錄。

注解

當字段未定義域且 check_company 設置為 True 時,會添加默認域: ['|', '('company_id', '=', False), ('company_id', '=', company_id)]

默認公司?

當模型上的字段 company_id 被設置為必填時,一個好的實踐是設置一個默認公司。這樣可以方便用戶進行設置流程,甚至在公司被隱藏時也可以保證其有效性。實際上,如果用戶沒有訪問多個公司的權限(即用戶沒有 base.group_multi_company 組),公司通常會被隱藏。

from odoo import api, fields, models

class Record(models.Model):
    _name = 'record.restricted'
    _check_company_auto = True

    company_id = fields.Many2one(
        'res.company', required=True, default=lambda self: self.env.company
    )
    other_record_id = fields.Many2one('other.record', check_company=True)

視圖?

如上所述,如果用戶沒有訪問多個公司的權限,則通常會隱藏公司,參見: 默認公司 。這已經通過 base.group_multi_company 組進行了測試。

<record model="ir.ui.view" id="record_form_view">
    <field name="name">record.restricted.form</field>
    <field name="model">record.restricted</field>
    <field name="arch" type="xml">
        <form>
            <sheet>
                <group>
                    <group>
                        <field name="company_id" groups="base.group_multi_company"/>
                        <field name="other_record_id"/>
                    </group>
                </group>
            </sheet>
        </form>
    </field>
</record>

安全規則?

在處理跨公司共享或限制于單個公司的記錄時,我們必須注意用戶不能訪問屬于其他公司的記錄。

這是通過基于 company_ids 的安全規則實現的,其中包含用戶的當前公司(用戶在多公司小部件中選中的公司)。

<!-- Shareable Records -->
<record model="ir.rule" id="record_shared_company_rule">
    <field name="name">Shared Record: multi-company</field>
    <field name="model_id" ref="model_record_shared"/>
    <field name="global" eval="True"/>
    <field name="domain_force">
        ['|', ('company_id', '=', False), ('company_id', 'in', company_ids)]
    </field>
</record>
<!-- Company-restricted Records -->
<record model="ir.rule" id="record_restricted_company_rule">
    <field name="name">Restricted Record: multi-company</field>
    <field name="model_id" ref="model_record_restricted"/>
    <field name="global" eval="True"/>
    <field name="domain_force">
        [('company_id', 'in', company_ids)]
    </field>
</record>