# -*- coding: utf-8 -*- from odoo import api, fields, models from pypinyin import pinyin,lazy_pinyin from odoo.osv import expression from odoo.exceptions import ValidationError, UserError # 作为顶级根节点、在下属部门显示名中不带出的上级部门(只显示本部门,不拼上级) # 精确匹配:与部门名完全相同才算根级 ROOT_DEPARTMENTS = {'集团本部', '客户服务中心'} # 前缀匹配:以这些字样开头的部门都算根级(覆盖 天河粮储/天河物管/天河投资 等公司) ROOT_DEPARTMENT_PREFIXES = ('天河',) def _is_root_department(department): """判断上级部门是否属于根级(根级不拼进下级显示名)。""" name = department.name or '' return name in ROOT_DEPARTMENTS or name.startswith(ROOT_DEPARTMENT_PREFIXES) class YuthonHrDepartment(models.Model): _inherit = "hr.department" # 部门显示名只带一级上级("上级 / 本部门"),最多一层;无上级则只显示本部门 _rec_name = 'hierarchical_name' _order = 'department_code asc' name = fields.Char(string="部门名称", tracking=True, required=True) department_phone = fields.Char(string="部门电话") department_fax = fields.Char(string="部门传真") department_location = fields.Char(string="部门地址") department_function = fields.Char(string="部门职能") is_institution = fields.Boolean(string="是否机构") is_global_department = fields.Boolean(string="是否全局部门") create_date = fields.Date(string="创建时间", default=fields.Date.today()) start_date = fields.Date(string="生效日期", default=fields.Date.today()) expiration_date = fields.Date(string="失效日期", default=fields.Date.today()) end_date = fields.Date(string="结束时间") department_code = fields.Char(string="部门序号") company_id = fields.Many2one('res.company', string="公司", index=True, default=lambda self: self.env.company, store=True) pinyin_name = fields.Char(string="拼音名称", compute='_compute_pinyin', index=True, store=True) is_company = fields.Boolean(string="本公司", default=True, compute='_compute_is_company', search='_search_part_of_company') hierarchical_name = fields.Char(string="层级名称", compute='_compute_hierarchical_name', store=True, index=True) @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 if not value: operator = '!=' if operator == '=' else '=' if operator == '=': return [('company_id', 'in', company_ids)] else: return [('company_id', 'not in', company_ids)] @api.constrains('create_date', 'end_date') def _check_start_end_time(self): for record in self: if record.create_date and record.end_date and record.create_date > record.end_date: raise models.ValidationError("开始时间不能大于结束时间!") def do_department_to_res_groups(self): """ 批量生成新的权限组 :return: """ for record in self: res_groups_objs = self.sudo().env["res.groups"].search([("department_ids", "in", record.ids)]) user_ids = self.sudo().env["hr.employee"].search([("department_id", "=", record.id)]).user_id.ids if not res_groups_objs: # 查询当前部门下的员工的数量 self.sudo().env["res.groups"].create({ "name": record.name, "department_ids": [(4, id) for id in record.ids] , "users": [(4, id) for id in user_ids] }) else: for res_groups_obj in res_groups_objs: res_groups_obj.sudo().write({ "users": [(4, id) for id in user_ids] }) @api.onchange('department_code', 'parent_id') def _onchange_department_code(self): for code in self: if code.parent_id.department_code: code.department_code = code.parent_id.department_code + (code.department_code.split('.')[-1] if code.department_code else '') else: code.department_code = code.department_code @api.depends('name') def _compute_pinyin(self): for employee in self: if employee.name: employee.pinyin_name = ''.join(lazy_pinyin(employee.name)) @api.depends('name', 'parent_id.name') def _compute_hierarchical_name(self): for department in self: parent = department.parent_id # 上级为空 或 上级属于根级部门(集团本部/天河系公司等)→ 只显示本部门 if parent and not _is_root_department(parent): department.hierarchical_name = '%s(%s)' % (department.name, parent.name) else: department.hierarchical_name = department.name def action_recompute_hierarchical_name(self): """手动重算所有部门的层级显示名(改了 ROOT_DEPARTMENTS 规则后,store 字段旧值不会自动重算,用此动作触发)。 可在 设置→技术→动作→服务器动作 找到「重算部门层级显示名」并运行, 或直接在该模型的列表/表单「动作」菜单中点击。 """ all_depts = self.sudo().search([]) all_depts._compute_hierarchical_name() self.env.cr.commit() return { 'type': 'ir.actions.client', 'tag': 'display_notification', 'params': { 'title': '部门层级名重算完成', 'message': '已重算 %d 个部门' % len(all_depts), 'type': 'success', 'sticky': False, } } @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.constrains('department_code') def _check_department_code_uniqueness(self): for record in self: if record.department_code: existing_records = self.search([ ('department_code', '=', record.department_code), ('id', '!=', record.id) ]) if existing_records: raise ValidationError("部门序号必须唯一!") @api.onchange('department_code') def _onchange_department_code(self): for record in self: if record.department_code: employee_ids = self.env['hr.employee'].search([('department_id', '=', record.id.origin), ('company_id', '=', record.company_id.id)]) for employee in employee_ids: if employee.number and len(employee.number) >= 2: old_suffix = employee.number[-2:] employee.number = record.department_code + old_suffix def open_record(self): return { "type": "ir.actions.act_window", "res_model": 'hr.department', "res_id": self.id, "name":"部门详情", "view_mode": "form", } def put_department_change(self): form_id = self.env.ref('yuthon_hr_employee_approval.view_yuthon_department_change_form').id department_list = [] for record in self: department_list.append([0, 0, {'department_id': record.id,}]) return { "type": "ir.actions.act_window", "name": "部门变成审批", "res_model": "yuthon.department.change", "views": [[form_id, "form"]], "context": { 'default_approval_ids': department_list, } } def all_put_department_change(self): department_list = [] department_ids = self.env["hr.department"].browse( self._context.get('active_ids', self._context.get('active_id'))) for record in department_ids: department_list.append([0, 0, {'department_id': record.id,}]) form_id = self.env.ref('yuthon_hr_employee_approval.view_yuthon_department_change_form').id return { "type": "ir.actions.act_window", "name": "部门变成审批", "res_model": "yuthon.department.change", "views": [[form_id, "form"]], "context": { 'default_approval_ids': department_list, } }