Hướng dẫn về đa công ty

Cảnh báo

This tutorial requires good knowledge of Odoo. Please refer to the Server framework 101 tutorial first if needed.

Từ phiên bản 13.0, một người dùng có thể đăng nhập vào nhiều công ty cùng một lúc. Điều này cho phép người dùng truy cập thông tin từ nhiều công ty, đồng thời tạo/sửa đổi các bản ghi trong môi trường đa công ty.

Nếu không được quản lý đúng cách, nó có thể là nguồn gốc của nhiều hành vi đa công ty không nhất quán. Ví dụ, một người dùng đăng nhập vào cả hai công ty A và B có thể tạo đơn hàng bán hàng trong công ty A và thêm sản phẩm thuộc về công ty B vào đó. Chỉ khi người dùng đăng xuất khỏi công ty B thì lỗi truy cập mới xảy ra với đơn hàng bán hàng.

Để quản lý đúng cách các hành vi đa công ty, ORM của SoOn cung cấp nhiều tính năng:

Các trường phụ thuộc vào công ty

Khi một bản ghi có sẵn từ nhiều công ty, chúng ta phải kỳ vọng rằng các giá trị khác nhau sẽ được gán cho một trường nhất định tùy thuộc vào công ty từ đó giá trị được thiết lập.

Để trường của cùng một bản ghi hỗ trợ nhiều giá trị, nó phải được định nghĩa với thuộc tính company_dependent đặt thành 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

Ghi chú

Phương thức _compute_display_info được trang trí với depends_context('company') (xem depends_context) để đảm bảo rằng trường đã tính toán được tính toán lại tùy thuộc vào công ty hiện tại (self.env.company).

Khi một trường phụ thuộc vào công ty được đọc, công ty hiện tại được sử dụng để truy xuất giá trị của nó. Nói cách khác, nếu một người dùng đăng nhập vào các công ty A và B với A là công ty chính và tạo một bản ghi cho công ty B, giá trị của các trường phụ thuộc vào công ty sẽ là của công ty A.

Để đọc các giá trị của các trường phụ thuộc vào công ty được thiết lập bởi một công ty khác ngoài công ty hiện tại, chúng ta cần đảm bảo công ty mà chúng ta đang sử dụng là đúng. Điều này có thể được thực hiện với with_company(), điều này cập nhật công ty hiện tại.

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

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

Cảnh báo

Bất cứ khi nào bạn đang tính toán/tạo/... những thứ có thể hoạt động khác nhau ở các công ty khác nhau, bạn nên đảm bảo rằng những gì bạn đang làm được thực hiện ở công ty đúng. Không tốn nhiều chi phí để luôn sử dụng with_company nhằm tránh các vấn đề sau này.

@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)
   ...

Tính nhất quán đa công ty

Khi một bản ghi được chia sẻ giữa nhiều công ty thông qua một trường company_id, chúng ta phải chú ý rằng nó không thể được liên kết với bản ghi của một công ty khác thông qua một trường quan hệ. Ví dụ, chúng ta không muốn có một đơn hàng bán hàng và hóa đơn của nó thuộc về các công ty khác nhau.

Để đảm bảo tính nhất quán đa công ty này, bạn phải:

  • Đặt thuộc tính lớp _check_company_auto thành True.

  • Định nghĩa các trường quan hệ với thuộc tính check_company đặt thành True nếu mô-đun của chúng có trường company_id.

Trên mỗi create()write(), các kiểm tra tự động sẽ được kích hoạt để đảm bảo tính nhất quán đa công ty của bản ghi.

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)

Ghi chú

Trường company_id không được định nghĩa với check_company=True.

Cảnh báo

Tính năng check_company thực hiện kiểm tra nghiêm ngặt! Điều này có nghĩa là nếu một bản ghi không có company_id (tức là trường không bắt buộc), nó không thể được liên kết với một bản ghi có company_id được thiết lập.

Ghi chú

Khi không có miền nào được xác định trên trường và check_company được đặt thành True, một miền mặc định được thêm vào: ['|', '('company_id', '=', False), ('company_id', '=', company_id)]

Công ty mặc định

Khi trường company_id được yêu cầu trên một mô hình, một cách thực hành tốt là thiết lập một công ty mặc định. Điều này giúp đơn giản hóa quy trình thiết lập cho người dùng hoặc thậm chí đảm bảo tính hợp lệ của nó khi công ty bị ẩn khỏi chế độ xem. Thực tế, công ty thường bị ẩn nếu người dùng không có quyền truy cập vào nhiều công ty (tức là, khi người dùng không có nhóm 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)

Giao diện

Như đã nêu ở trên, công ty thường bị ẩn khỏi chế độ xem nếu người dùng không có quyền truy cập vào nhiều công ty. Điều này được đánh giá bằng nhóm 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>

Quy tắc bảo mật

Khi làm việc với các bản ghi được chia sẻ giữa các công ty hoặc hạn chế cho một công ty duy nhất, chúng ta phải đảm bảo rằng người dùng không có quyền truy cập vào các bản ghi thuộc về các công ty khác.

Điều này được thực hiện với các quy tắc bảo mật dựa trên company_ids, chứa các công ty hiện tại của người dùng (các công ty mà người dùng đã chọn trong widget đa công ty).

<!-- 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>