Merge pull request !12553 from 李鹏宇/dev
This commit is contained in:
李鹏宇
2026-08-04 09:23:31 +00:00
committed by Gitee
4 changed files with 131 additions and 6 deletions
@@ -69,6 +69,18 @@ class SoongWorkflowRecord(models.Model):
soong_state = fields.Selection([('to_do', '待办'), ('done', '已办'),('to_active', '待归档'), ('active', '已归档')], string="流程状态", default="to_do")
member_of_department = fields.Boolean("是否是本部门数据", compute='_compute_part_of_department',
search='_search_part_of_department')
special_member_visible = fields.Boolean(
"特殊权限可见(人事/考勤)",
compute='_compute_special_member_visible',
search='_search_special_member_visible',
help="当前用户属于『本部-角色-人事专员』或『考勤-用户』用户组时,可查看对应的(仅本公司的)人事/考勤流程",
)
dept_query_visible = fields.Boolean(
"部门查询可见(排除考勤/人事)",
compute='_compute_dept_query_visible',
search='_search_dept_query_visible',
help="本部门可见,但排除审批分组为考勤/人事的流程(二者仅对特殊权限组可见)",
)
# 人力资源流程的发生日期
workflow_happen_date = fields.Date(string="发生日期")
@@ -613,6 +625,78 @@ class SoongWorkflowRecord(models.Model):
domain = ['!'] + domain
return domain
# ------------------------------------------------------------------
# 特殊权限可见:人事专员 / 考勤-用户 用户组可查看对应(仅本公司)流程
# ------------------------------------------------------------------
@api.depends_context('uid', 'company')
@api.depends('approvals_group_id', 'company_id')
def _compute_special_member_visible(self):
user = self.env.user
hr_group = self.env['res.groups'].sudo().search([('name', '=', '本部-角色-人事专员')], limit=1)
kq_group = self.env['res.groups'].sudo().search([('name', '=', '考勤-用户')], limit=1)
is_hr_user = bool(hr_group and user in hr_group.users)
is_kq_user = bool(kq_group and user in kq_group.users)
active_company_ids = self.env.companies.ids
for record in self:
visible = False
if record.approvals_group_id and record.company_id.id in active_company_ids:
group_name = record.approvals_group_id.name
if group_name == '人事' and is_hr_user:
visible = True
elif group_name == '考勤' and is_kq_user:
visible = True
record.special_member_visible = visible
def _search_special_member_visible(self, operator, value):
user = self.env.user
hr_group = self.env['res.groups'].sudo().search([('name', '=', '本部-角色-人事专员')], limit=1)
kq_group = self.env['res.groups'].sudo().search([('name', '=', '集团-角色-考勤')], limit=1)
is_hr_user = bool(hr_group and user in hr_group.users)
is_kq_user = bool(kq_group and user in kq_group.users)
company_ids = self.env.companies.ids
# 注意:必须用扁平前缀形式(&/| 放在 domain 顶层),
# 不能把 ['&', ...] 作为子列表元素,否则 Odoo 会把它当叶子、把 & 当成字段名报错。
parts = []
if is_hr_user:
parts.append(['&', ('approvals_group_id.name', '=', '人事'), ('company_id', 'in', company_ids)])
if is_kq_user:
parts.append(['&', ('approvals_group_id.name', '=', '考勤'), ('company_id', 'in', company_ids)])
if not parts:
# 当前用户不属于任何特殊权限组,恒不满足
domain = [('id', '=', False)]
else:
domain = ['|'] * (len(parts) - 1)
for grp in parts:
domain += grp
if (operator == '=' and not value) or (operator == '!=' and value):
domain = ['!'] + domain
return domain
# ------------------------------------------------------------------
# 部门查询可见(排除考勤/人事):本部门数据 且 审批分组不是考勤/人事
# ------------------------------------------------------------------
@api.depends_context('uid', 'company')
@api.depends('member_of_department', 'approvals_group_id')
def _compute_dept_query_visible(self):
for record in self:
record.dept_query_visible = bool(
record.member_of_department
and record.approvals_group_id
and record.approvals_group_id.name not in ('考勤', '人事')
)
def _search_dept_query_visible(self, operator, value):
# 本部门数据 且 审批分组不是考勤/人事(member_of_department 由 search 方法内联展开,无嵌套)
domain = ['&',
('approvals_group_id.name', 'not in', ['考勤', '人事']),
('member_of_department', '=', True)]
if (operator == '=' and not value) or (operator == '!=' and value):
domain = ['!'] + domain
return domain
@api.model
def create(self, vals_list):
res = super().create(vals_list)
@@ -459,9 +459,15 @@
<field name="type">ir.actions.act_window</field>
<field name="res_model">soong.workflow.record</field>
<field name="view_mode">tree,kanban,search</field>
<!-- 部门流程查询:只看"自己发起的(create_uid=uid)"或"自己作为审批人/经办人参与的(users_ids包含uid)" -->
<!-- 删除原 member_of_department 分支,避免普通用户看到同部门其他同事发起的流程 -->
<field name="domain">[('reclaim_state', '=', False), ('approve_state','!=','start'), '|', ('create_uid', '=', uid), ('users_ids', 'in', [uid])]</field>
<field name="domain">[
('reclaim_state', '=', False),
('approve_state', '!=', 'start'),
'|',
'|',
('users_ids', 'in', [uid]),
('dept_query_visible', '=', True),
('special_member_visible', '=', True)
]</field>
<field name="context">{'search_default_my_department_shifts': True, 'default_order': 'display_end_time desc'}</field>
<field name="search_view_id" ref="soong_workflow_record_search1"/>
<field name="view_id" ref="soong_workflow_record_department_tree"/>
@@ -48,7 +48,11 @@ class SoongWorkflowCommentWizard(models.TransientModel):
employee_ids = fields.Many2many('hr.employee', 'employee_ids_rel', 'custom_id', 'employee_id', string="转交人员", store=True)
circulated_employee_ids = fields.Many2many('hr.employee', 'circulated_employee_rel', 'custom_id', 'employee_id', help='只可以看不可以评论,看过以后状态自动变为已阅', string="传阅人员", store=True)
dep_manager_employee_ids = fields.Many2many('hr.employee', 'dep_manager_employee_rel', 'custom_id', 'employee_id', string="承办", store=True)
add_employee_ids = fields.Many2many('hr.employee', 'add_employee_rel', 'custom_id', 'employee_id', string="加签人员", help='点击确认以后评论的人员', store=True)
add_employee_ids = fields.Many2many('hr.employee', 'add_employee_rel', 'custom_id', 'employee_id', string="加签人员", help='点击确认以后评论的人员', store=True, domain="[('id', 'in', add_employee_filter_ids)]")
add_employee_filter_ids = fields.Many2many('hr.employee', 'add_employee_filter_rel', 'custom_id', 'employee_id', string="加签过滤人员",
default=lambda self: self._default_add_employee_filter_ids(),
help='当前登录人所在部门及子部门(递归)的员工,用于过滤加签人员可选范围')
is_return = fields.Boolean('是否返回', help='勾选之后,加签返回自己')
supervising_employee_ids = fields.Many2many('hr.employee', 'supervising_employee_rel', 'custom_id', 'employee_id', string="督办人员", store=True)
approval_concatenation = fields.Selection([('chuan', '串申'), ('bing', '并申')], string="审批形式",
help='并:任何人均给意见,最后一个完成的人转交到下一节点.'
@@ -133,6 +137,35 @@ class SoongWorkflowCommentWizard(models.TransientModel):
])
self.employee_ids2 = self.env['hr.employee'].search(domain)
def _default_add_employee_filter_ids(self):
"""获取当前登录人所在部门及子部门(递归)的员工,作为加签人员的可选范围。
参考 yuthon_notice._constrains_employee_related_fields 中的
get_department_employees(department_id),递归获取部门及其所有子部门下的员工。
"""
department = self.env.user.department_id
if not department:
return self.env['hr.employee']
result = self.env['hr.employee']
def collect(dept):
nonlocal result
# 当前部门(含多部门字段 department_ids)下的员工
emps = self.env['hr.employee'].search([
('company_id', '=', self.env.user.company_id.id),
'|',
('department_id', '=', dept.id),
('department_ids', 'in', dept.ids),
])
result |= emps
# 递归处理子部门(部门及以下)
for child in dept.child_ids:
collect(child)
collect(department)
return result
@api.depends('comment_note_id', 'comment_note')
def _compute_comment(self):
for record in self:
@@ -754,7 +787,7 @@ class SoongWorkflowCommentWizard(models.TransientModel):
# 是否都完成了
all_done = all(log.approval_state == "2" for log in batch_logs)
# 如果都完成 → 创建一条新日志给加签发起人
if all_done:
if all_done and self.is_return:
log_vals = {
"model": self.res_model,
"res_id": self.res_id,
@@ -72,9 +72,10 @@
<label for="scope_type" string="范围"/>
<field name="scope_type" nolabel="1"/>
<field name="company_id" invisible="1"/>
<field name="is_return"/>
<field name="add_employee_ids" invisible="node_btn_name == '退回'"
widget="many2many_tags" options="{'no_create': True}"
domain="[('id', 'in', employee_ids2)]"/>
domain="[('id', 'in', add_employee_filter_ids)]"/>
</group>
</group>
<group invisible="node_btn_name != '结束'">
@@ -152,6 +153,7 @@
<field name="company_id" invisible="1"/>
<field name="employee_ids1" widget="many2many_tags" string="人员" invisible="1"/>
<field name="employee_ids2" widget="many2many_tags" invisible="1"/>
<field name="add_employee_filter_ids" widget="many2many_tags" invisible="1"/>
<field name="employee_ids" widget="many2many_tags" string="人员"
domain="[('id', 'in', employee_ids1)]"
options="{'no_create': True}"