# -*- coding: utf-8 -*- from odoo import api, fields, models, _ from pypinyin import pinyin, lazy_pinyin from odoo.osv import expression from odoo.exceptions import UserError, ValidationError class YuthonUserRole(models.Model): _name = 'soong.user.role' _order = 'number asc' name = fields.Char(string="角色名称") number = fields.Char(string="序号") is_main = fields.Boolean(string="主角色") department_id = fields.Many2one('hr.department', string="所属部门") create_time = fields.Date(string="生效日期", default=fields.Datetime.today()) end_time = fields.Date(string="终止日期") parent_id = fields.Many2one('soong.user.role', string='上级角色') user_role_group_ids = fields.Many2many('soong.user.role.group', string='角色分组', index=True) personnel_ids = fields.Many2many('hr.employee', string='在岗人员', store=True, index=True) number_people = fields.Integer(string="在岗人数", compute='_compute_employee_ids') personnel = fields.Text(string="在岗人员") employee_ids = fields.One2many('hr.employee', 'user_role_id') company_id = fields.Many2one('res.company', string="公司", default=lambda self: self.env.company) pinyin_name = fields.Char(string="拼音名称", compute='_compute_pinyin', index=True) is_company = fields.Boolean(string="本公司", default=True, compute='_compute_is_company', search='_search_part_of_company') @api.depends_context('uid', 'company') @api.depends('company_id') def _compute_is_company(self): active_company_ids = self.env.companies for employee in self: employee.is_company = employee.company_id in active_company_ids def _search_part_of_company(self, operator, value): if operator not in ('=', '!=') or not isinstance(value, bool): raise UserError(('Operation not supported')) company_ids = self.env.companies.ids # 获取公司ID列表 # 处理反向操作符 if not value: operator = '!=' if operator == '=' else '=' # 使用company_id in company_ids的结构 if operator == '=': return [('company_id', 'in', company_ids)] else: # operator == '!=' return [('company_id', 'not in', company_ids)] @api.onchange('is_main') def _onchange_is_main(self): for employee in self.personnel_ids: employee_id = self.env['hr.employee'].search([('id', '=', employee.id.origin)]) if self.is_main: # 1. 是主角色:替换主角色,清空辅助角色中的当前记录 employee_id.user_role_id = self.id.origin if self.id.origin in employee_id.user_role_ids.ids: employee_id.user_role_ids = [(3, self.id.origin)] else: # 2. 不是主角色:检查辅助角色,没有则添加 if self.id.origin not in employee_id.user_role_ids.ids: employee_id.user_role_ids = [(4, self.id.origin)] # @api.depends('department_id') def _compute_display_name(self): for record in self: display_parts = [] if record.name: display_parts.append(record.name) if record.department_id: display_parts.append(f"({record.department_id.name})") record.display_name = " ".join(display_parts) @api.depends('name') def _compute_pinyin(self): for employee in self: employee.pinyin_name = ''.join(lazy_pinyin(employee.name)) @api.model def _name_search(self, name, domain=None, operator='ilike', limit=None, order=None): domain = domain or [] if name: has_chinese = any('\u4e00' <= char <= '\u9fff' for char in name) if has_chinese: # 包含中文:使用模糊匹配 search_domain = [('name', operator, name)] else: # 纯字母/数字:使用精确匹配 search_domain = ['|', ('pinyin_name', operator, name), ('name', '=', name)] domain = expression.AND([search_domain, domain]) return self._search(domain, limit=limit, order=order) @api.depends('personnel_ids') def _compute_employee_ids(self): for rec in self: rec.number_people = 0 if rec.personnel_ids: rec.number_people = len(rec.personnel_ids) @api.onchange('personnel_ids') def _onchange_personnel_ids(self): for record in self: for personnel_id in record.personnel_ids: employee = self.env['hr.employee'].search([('id', '=', personnel_id.id.origin)], limit=1) if employee: if self.id.origin != employee.user_role_id.id: new_user_role_ids = employee.user_role_ids.ids + [self.id.origin] employee.write({'user_role_ids': [(6, 0, new_user_role_ids)],}) class YuthonUserRoleGroup(models.Model): _name = 'soong.user.role.group' _order = 'number asc' name = fields.Char(string="角色名称") number = fields.Char(string="序号", store=True) user_note = fields.Text(string="角色说明") user_role_ids = fields.Many2many('soong.user.role', string='包含角色', index=True) company_id = fields.Many2one('res.company', string='公司', default=lambda self: self.env.company) start_date = fields.Date(string="生效日期", default=fields.Datetime.today()) end_date = fields.Date(string="终止日期") create_date = fields.Date(string="创建日期", default=fields.Datetime.today()) is_company = fields.Boolean(string="本公司", default=True, compute='_compute_is_company', search='_search_part_of_company') @api.depends_context('uid', 'company') @api.depends('company_id') def _compute_is_company(self): active_company_ids = self.env.companies for record in self: record.is_company = record.company_id in active_company_ids def _search_part_of_company(self, operator, value): if operator not in ('=', '!=') or not isinstance(value, bool): raise UserError(('Operation not supported')) company_ids = self.env.companies.ids if not value: operator = '!=' if operator == '=' else '=' if operator == '=': return [('company_id', 'in', company_ids)] else: return [('company_id', 'not in', company_ids)] def button_role_group_wizard(self): return { 'name': '包含角色弹窗', 'type': 'ir.actions.act_window', 'view_mode': 'form', 'res_model': 'role.group.wizard', 'target': 'new', 'context': { 'default_role_group_id': self.id, 'default_user_role_ids': [(6, 0, self.user_role_ids.ids)] } } class YuthonRoleTree(models.Model): _name = 'soong.role.tree' _order = 'number asc' name = fields.Char(string="角色名称") department_id = fields.Many2one('hr.department', string="所属部门") company_id = fields.Many2one('res.company', string="公司", index=True, default=lambda self: self.env.company)