hr_multi_company_employee/models/hr_employee.py

107 lines
4.5 KiB
Python

from odoo import models, fields, api, _
class HrEmployee(models.Model):
_inherit = 'hr.employee'
company_ids = fields.Many2many(
'res.company',
string='Branches',
domain="[('parent_id', '!=', False)]",
help="Branch companies this employee is associated with."
)
# Overriding company_id to be computed from company_ids
# This maintains compatibility with standard Odoo logic that expects a single company_id
company_id = fields.Many2one(
'res.company',
string='Company',
compute='_compute_company_id',
store=True,
readonly=False,
required=True,
help="The primary company of the employee. Automatically set to the first branch in Branches."
)
attendance_manager_id = fields.Many2one(
'res.users',
domain="[('share', '=', False), ('company_ids', 'in', company_ids)]"
)
@api.depends('company_ids')
def _compute_company_id(self):
for employee in self:
if employee.company_ids:
employee.company_id = employee.company_ids[0]
elif employee.company_id:
# Sync company_ids from company_id for existing records
employee.company_ids = [(6, 0, [employee.company_id.id])]
else:
employee.company_id = self.env.company
employee.company_ids = [(6, 0, [self.env.company.id])]
@api.model
def _search(self, domain, offset=0, limit=None, order=None, **kwargs):
""" Override search to include company_ids and fallback to company_id if empty """
def replace_company_leaf(dom):
if not dom:
return dom
new_dom = []
for leaf in dom:
if isinstance(leaf, (list, tuple)):
if leaf[0] == 'company_id':
# Match if Branch is in search OR (Branch is empty AND Company is in search)
new_dom.append('|')
new_dom.append(('company_ids', leaf[1], leaf[2]))
new_dom.append('&')
new_dom.append(('company_ids', '=', False))
new_dom.append(('company_id', leaf[1], leaf[2]))
else:
new_dom.append(leaf)
elif isinstance(leaf, list):
new_dom.append(replace_company_leaf(leaf))
else:
new_dom.append(leaf)
return new_dom
if domain:
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:
new_domain = "['|', '|', '|', ('partner_share', '=', False), ('company_id', 'parent_of', company_ids), ('company_id', '=', False), ('employee_ids.company_ids', 'in', company_ids)]"
if rule.domain_force != new_domain:
rule.sudo().write({'domain_force': new_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:
new_domain_company = "['|', ('id', 'in', company_ids), ('id', 'parent_of', company_ids)]"
if rule_company.domain_force != new_domain_company:
rule_company.sudo().write({'domain_force': new_domain_company})
class HrEmployeePublic(models.Model):
_inherit = 'hr.employee.public'
company_ids = fields.Many2many(
'res.company',
related='employee_id.company_ids',
readonly=True,
string='Branches'
)