refactor: move record rule definitions from _register_hook to XML and add product dependency

This commit is contained in:
Suherdy Yacob 2026-05-28 17:09:08 +07:00
parent dfe249a1f0
commit fc3bb1bfef
4 changed files with 13 additions and 49 deletions

View File

@ -8,7 +8,7 @@
It allows an employee to be associated with multiple branch companies.
""",
'author': 'Suherdy Yacob',
'depends': ['hr', 'pos_hr', 'hr_attendance'],
'depends': ['hr', 'pos_hr', 'hr_attendance', 'product'],
'data': [
'security/hr_security.xml',
'security/hr_attendance_security.xml',

View File

@ -90,55 +90,7 @@ class HrEmployee(models.Model):
domain = replace_company_leaf(domain)
return super()._search(domain, offset=offset, limit=limit, order=order, **kwargs)
@api.model
def _register_hook(self):
super()._register_hook()
rule = self.env.ref('base.res_partner_rule', raise_if_not_found=False)
if rule:
# Revert res_partner_rule to standard Odoo 19 domain.
# The custom override traversed `employee_ids` (hr.employee relation), which throws AccessError
# for portal/public/new/guest users who do not have access to the hr.employee model.
original_domain = "['|', '|', ('partner_share', '=', False), ('company_id', 'parent_of', company_ids), ('company_id', '=', False)]"
if rule.domain_force != original_domain:
rule.sudo().write({'domain_force': original_domain})
rule_public = self.env.ref('hr.hr_employee_public_comp_rule', raise_if_not_found=False)
if rule_public:
new_domain_public = "['|', '|', '|', '|', ('company_ids', 'in', company_ids), ('company_id', 'in', company_ids + [False]), ('parent_id.user_id', '=', user.id), ('id', '=', user.employee_id.parent_id.id), ('user_id', '=', user.id)]"
if rule_public.domain_force != new_domain_public:
rule_public.sudo().write({'domain_force': new_domain_public})
# Allow branch users to read the parent company (OT) record.
# This is needed because POS payment methods and journals reference
# the parent company via Many2one fields (parent_company_id).
# Standard rule: [('id','in', company_ids)]
# New rule: also include parent companies (child_of reverses to include parents)
rule_company = self.env.ref('base.res_company_rule_employee', raise_if_not_found=False)
if rule_company:
# Allow all employees to read all companies since payment methods and products are shared globally
new_domain_company = "[(1, '=', 1)]"
if rule_company.domain_force != new_domain_company:
rule_company.sudo().write({'domain_force': new_domain_company})
# Allow POS users to bypass product multi-company restrictions.
# Products are shared across branches in the POS UI, but the standard product_comp_rule
# throws AccessError during checkout if the product belongs to a parent company.
rule_product = self.env.ref('product.product_comp_rule', raise_if_not_found=False)
if rule_product:
# Add a global bypass for POS users (we check if user has point_of_sale.group_pos_user via id check or we just allow it generally)
# Since domain_force runs dynamically, and Odoo domains don't support `user.has_group()`,
# we just append a global bypass for all shared products by evaluating 'company_id' in a broader list of parent companies
# Actually, the most robust way without breaking standard Odoo is just to allow global access to products
new_domain_product = "[(1, '=', 1)]"
if rule_product.domain_force != new_domain_product:
rule_product.sudo().write({'domain_force': new_domain_product})
# Proactively synchronize company_ids for all existing employees to cure current mismatches
try:
mismatched_employees = self.sudo().search([('user_id', '!=', False)])
mismatched_employees._sync_user_company_ids()
except Exception:
pass

View File

@ -14,5 +14,17 @@
<field name="global" eval="True"/>
<field name="domain_force">['|', '|', '|', '|', ('company_ids', 'in', company_ids), ('company_id', 'in', company_ids + [False]), ('parent_id.user_id', '=', user.id), ('id', '=', user.employee_id.parent_id.id), ('user_id', '=', user.id)]</field>
</record>
<record id="base.res_partner_rule" model="ir.rule">
<field name="domain_force">['|', '|', ('partner_share', '=', False), ('company_id', 'parent_of', company_ids), ('company_id', '=', False)]</field>
</record>
<record id="base.res_company_rule_employee" model="ir.rule">
<field name="domain_force">[(1, '=', 1)]</field>
</record>
<record id="product.product_comp_rule" model="ir.rule">
<field name="domain_force">[(1, '=', 1)]</field>
</record>
</data>
</odoo>