diff --git a/soong_workflow/models/soong_workflow_node.py b/soong_workflow/models/soong_workflow_node.py index dcad702a1..71ffa25c7 100644 --- a/soong_workflow/models/soong_workflow_node.py +++ b/soong_workflow/models/soong_workflow_node.py @@ -102,6 +102,11 @@ class SoongWorkflowNode(models.Model): approval_concatenation = fields.Selection([('chuan', '串申'), ('bing', '并申')], string="审批形式", default="bing", help='并:任何人均给意见,最后一个完成的人转交到下一节点.' '串:都会收到消息,但任意一个人转交后,即到下一节点,其他人将不再显示,相当于收回.') + same_user_skip_type = fields.Selection([ + ('none', '不跳过'), + ('next', '跳过下一个相同人员节点'), + ('prev', '跳过上一个相同人员节点'), + ], string='相同人员节点处理', default='none') @api.onchange("is_apostille") def onchange_is_apostille(self): diff --git a/soong_workflow/views/soong_workflow_node_views.xml b/soong_workflow/views/soong_workflow_node_views.xml index 40439b58f..11a668c0f 100644 --- a/soong_workflow/views/soong_workflow_node_views.xml +++ b/soong_workflow/views/soong_workflow_node_views.xml @@ -17,6 +17,7 @@ + diff --git a/soong_workflow/wizard/soong_workflow_comment_wizard.py b/soong_workflow/wizard/soong_workflow_comment_wizard.py index a9851182e..023962772 100644 --- a/soong_workflow/wizard/soong_workflow_comment_wizard.py +++ b/soong_workflow/wizard/soong_workflow_comment_wizard.py @@ -39,9 +39,9 @@ class SoongWorkflowCommentWizard(models.TransientModel): return_link_id = fields.Many2one('trans.link', string='退回节点', ondelete='set null') invalid_link_ids = fields.Many2many( 'trans.link', - string='审批人节点,跳过节点', + string='跳过相同人员', compute='_compute_invalid_link_ids', - help='没有找到符合条件审批人的节点' + help='跳过相同人员的节点' ) employee_trans_domain_ids = fields.Many2many('hr.employee', 'employee_trans_domain_ids_rel', string="传阅人员", store=True) @@ -173,19 +173,33 @@ class SoongWorkflowCommentWizard(models.TransientModel): if current_link and all_links: sorted_all_links = all_links.sorted('sequence') for idx, link in enumerate(sorted_all_links): - if link.id == current_link.id and link.sequence == current_link.sequence: - approvers = self._get_approvers_for_link(link, record_id) - log_records = record_id.log_ids - approved_users = log_records.filtered(lambda log: log.node_btn_name != '1' and log.done_by).mapped('done_by.employee_ids') - approved_employee_ids = approved_users.ids - employee_ids = approvers.ids - if len(approvers) > 1: - is_all_included = all(emp_id in approved_employee_ids for emp_id in employee_ids) - if is_all_included: - if idx + 1 < len(sorted_all_links): - self.trans_link_id = sorted_all_links[idx + 1] - invalid_links |= current_link - break + approvers = self._get_approvers_for_link(link, record_id) + # 如果当前审批人是 1 个人,才判断跳过 + if len(approvers) == 1: + current_approver = approvers[0] + # 跳过规则 next:跳过【下一个】节点 + node_id = record_id.workflow_id.node_ids.search([ + ('name', '=', link.name), + ('workflow_id', '=', record_id.workflow_id.id) + ]) + if node_id.same_user_skip_type == 'next': + # 有下一个节点 + if idx + 1 < len(sorted_all_links): + next_link = sorted_all_links[idx + 1] + next_approvers = self._get_approvers_for_link(next_link, record_id) + # 下一个节点也是 1 个人,且和当前是同一个 + if len(next_approvers) == 1 and next_approvers[0] == current_approver: + invalid_links |= next_link # 下一个节点无效(跳过) + + # 跳过规则 prev:跳过【上一个】节点 + if node_id.same_user_skip_type == 'prev': + # 有上一个节点 + if idx - 1 >= 0: + prev_link = sorted_all_links[idx - 1] + prev_approvers = self._get_approvers_for_link(prev_link, record_id) + # 上一个节点也是 1 个人,且和当前是同一个 + if len(prev_approvers) == 1 and prev_approvers[0] == current_approver: + invalid_links |= prev_link record.invalid_link_ids = invalid_links diff --git a/yuthon_hr_attendance/models/overtime_approval.py b/yuthon_hr_attendance/models/overtime_approval.py index 1aa76aae6..2fb4a4be3 100644 --- a/yuthon_hr_attendance/models/overtime_approval.py +++ b/yuthon_hr_attendance/models/overtime_approval.py @@ -66,25 +66,31 @@ class OvertimeApprovals(models.Model): @api.constrains('start_time') def _check_start_time(self): for rec in self: - workflow_records = self.env['soong.workflow.record'].search([ - ('workflow_id.name', '=', '加班'), - ('create_uid', '=', self.users_id.id), - ('reclaim_state', '=', False), - ]) - if not workflow_records: + if not rec.employee_ids or not rec.start_time: continue - for wf_rec in workflow_records: - if wf_rec.res_model == rec._name and wf_rec.res_id == rec.id: + current_date = (rec.start_time + timedelta(hours=8)).date() + for employee in rec.employee_ids: + if not employee.user_id: continue - - target_model = self.env[wf_rec.res_model] - target_record = target_model.browse(wf_rec.res_id) - - if not target_record.exists() or not target_record.start_time: - continue - if (target_record.start_time + timedelta(hours=8)).date() == ( - rec.start_time + timedelta(hours=8)).date(): - raise UserError('当天已有加班审批,请重新选择开始时间') + workflow_records = self.env['soong.workflow.record'].search([ + ('workflow_id.name', '=', '加班'), + ('create_uid', '=', employee.user_id.id), + ('reclaim_state', '=', False), + ]) + for wf_rec in workflow_records: + # 跳过自己这条记录 + if wf_rec.res_model == rec._name and wf_rec.res_id == rec.id: + continue + target_model = self.env[wf_rec.res_model] + target_record = target_model.browse(wf_rec.res_id) + if not target_record.exists() or not target_record.start_time: + continue + exist_date = (target_record.start_time + timedelta(hours=8)).date() + if exist_date == current_date: + raise UserError('员工【%s】在【%s】已有加班记录,不可重复提交!' % ( + employee.name, + current_date + )) for employee in rec.employee_ids: holiday_status_id = self.env['hr.leave.type'].search([('name', '=', '补休')]) start_year = rec.start_time.date().year @@ -175,13 +181,20 @@ class OvertimeApprovals(models.Model): corrected_end_time = max_allowed_end_time - timedelta(hours=8) rec.end_time = corrected_end_time - @api.depends('users_id', 'duration', 'start_time') + @api.depends('employee_ids', 'duration', 'start_time') def _compute_overtime_hours(self): for rec in self: rec.overtime_hours = 0.0 - if not rec.users_id or not rec.start_time: + if not rec.employee_ids or len(rec.employee_ids) != 1: continue - now = rec.start_time # 获取当前时间(datetime类型) + employee = rec.employee_ids[0] + if not employee.user_id: + continue + + if not rec.start_time: + continue + + now = rec.start_time first_datetime = datetime(now.year, now.month, 1, 0, 0, 0) if now.month == 12: next_month_datetime = datetime(now.year + 1, 1, 1, 0, 0, 0) @@ -190,20 +203,20 @@ class OvertimeApprovals(models.Model): last_datetime = next_month_datetime - timedelta(seconds=1) workflow_records = self.env['soong.workflow.record'].search([ ('workflow_id.name', '=', '加班'), - ('create_uid', '=', rec.users_id.id), + ('create_uid', '=', employee.user_id.id), ('approve_state', 'in', ['pending', 'end']), ('reclaim_state', '!=', True), ]) - overtime_name_list = [] total_overtime = 0.0 for workflow in workflow_records: related_model = self.env[workflow.res_model].browse(workflow.res_id) + if not related_model.exists(): + continue start_time = related_model.start_time if first_datetime <= start_time <= last_datetime: if related_model.duration: total_overtime += related_model.duration - overtime_name_list.append(related_model.name) - rec.overtime_hours = total_overtime + rec.overtime_hours = total_overtime @api.constrains('users_id') def _check_overtime_hours(self): diff --git a/yuthon_hr_attendance/views/overtime_approval.xml b/yuthon_hr_attendance/views/overtime_approval.xml index a6cdc07b1..3cac05091 100644 --- a/yuthon_hr_attendance/views/overtime_approval.xml +++ b/yuthon_hr_attendance/views/overtime_approval.xml @@ -113,7 +113,7 @@ - + diff --git a/yuthon_hr_attendance/views/yuthon_vacation_reports_views.xml b/yuthon_hr_attendance/views/yuthon_vacation_reports_views.xml index a0782eeb3..91fe581b0 100644 --- a/yuthon_hr_attendance/views/yuthon_vacation_reports_views.xml +++ b/yuthon_hr_attendance/views/yuthon_vacation_reports_views.xml @@ -619,6 +619,22 @@ + + + + + + + + + + + + +