Files
gzth/soong_workflow/models/soong_user_role.py
T
2026-04-29 19:20:07 +08:00

194 lines
8.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- 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 personnel_id in self.personnel_ids:
employee = self.env['hr.employee'].browse(personnel_id.id)
if employee:
if self.id not in employee.user_role_ids.ids:
new_user_role_ids = list(set(employee.user_role_ids.ids + [self.id]))
employee.with_context(_syncing_role_personnel=True).write({
'user_role_ids': [(6, 0, new_user_role_ids)],
})
def write(self, vals):
"""覆盖 write,personnel_ids 变更时双向同步到员工的主/辅助角色字段"""
# 记录变更前的 personnel_ids
old_personnel_map = {rec.id: set(rec.personnel_ids.ids) for rec in self}
result = super().write(vals)
if 'personnel_ids' not in vals:
return result
for rec in self:
new_ids = set(rec.personnel_ids.ids)
old_ids = old_personnel_map.get(rec.id, set())
added_ids = new_ids - old_ids # 新增的员工
removed_ids = old_ids - new_ids # 移除的员工
if rec.is_main:
# 主角色:新增员工 → 设为主角色;移除员工 → 清空主角色(若仍是该角色)
for emp in self.env['hr.employee'].browse(list(added_ids)):
emp.write({'user_role_id': rec.id})
for emp in self.env['hr.employee'].browse(list(removed_ids)):
if emp.user_role_id.id == rec.id:
emp.write({'user_role_id': False})
else:
# 辅助角色:新增员工 → 添加到辅助角色;移除员工 → 从辅助角色移除
for emp in self.env['hr.employee'].browse(list(added_ids)):
if rec.id not in emp.user_role_ids.ids:
emp.write({'user_role_ids': [(4, rec.id)]})
for emp in self.env['hr.employee'].browse(list(removed_ids)):
if rec.id in emp.user_role_ids.ids:
emp.write({'user_role_ids': [(3, rec.id)]})
return result
class YuthonUserRoleGroup(models.Model):
_name = 'soong.user.role.group'
_order = 'number asc'
_rec_name = 'name'
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)