From 19ab661946684bb8481ecec48eb2c3e38c8f430a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=AE=87?= <9664676+pengyuthon@user.noreply.gitee.com> Date: Thu, 2 Apr 2026 11:21:41 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wizard/attendance_correct_wizard.py | 146 ++++++------------ .../models/yuthon_onboard_approval.py | 3 + .../views/yuthon_onboard_approval_views.xml | 1 + 3 files changed, 50 insertions(+), 100 deletions(-) diff --git a/yuthon_hr_attendance/wizard/attendance_correct_wizard.py b/yuthon_hr_attendance/wizard/attendance_correct_wizard.py index 04ecb7b2a..5b948ed4e 100644 --- a/yuthon_hr_attendance/wizard/attendance_correct_wizard.py +++ b/yuthon_hr_attendance/wizard/attendance_correct_wizard.py @@ -18,7 +18,7 @@ class AttendanceCorrectWizard(models.TransientModel): def confirm(self): for record in self: - values = { + base_vals = { 'correct_result': record.correct_result, 'is_approval': True, 'is_abnormal': False, @@ -29,123 +29,69 @@ class AttendanceCorrectWizard(models.TransientModel): 'is_check_out_red': False, 'absenteeism_card': False, } - for attendance in record.attendance_ids: - - if not attendance.shift_id: - year = attendance.current_data.year - month = attendance.current_data.month - day = attendance.current_data.day - current_date = datetime.today() - resource_calendar = attendance.employee_id.resource_id.calendar_id - if not resource_calendar: - raise ValidationError(_("员工 %s 未配置工作日历") % attendance.employee_id.name) - + values = base_vals.copy() + employee = attendance.employee_id + current_date = datetime.combine(attendance.current_data, datetime.min.time()) + if not employee.default_planning_role_id: + resource_calendar = employee.resource_id.calendar_id attendances = resource_calendar.attendance_ids.sorted(key=lambda a: a.hour_from) - if not attendances: - raise ValidationError(_("员工 %s 的工作日历缺少考勤时间段配置") % attendance.employee_id.name) + min_att = attendances[0] + max_att = attendances[-1] - # 计算正常上下班时间 - min_attendance = attendances[0] - max_attendance = attendances[-1] - - # 上半天时间 half_day_start = current_date.replace( - year=year, month=month, day=day, - hour=int(min_attendance.hour_from), - minute=int((min_attendance.hour_from % 1) * 60) + hour=int(min_att.hour_from), + minute=int((min_att.hour_from % 1) * 60) ) - timedelta(hours=8) - # 下半天时间 second_half_end = current_date.replace( - year=year, month=month, day=day, - hour=int(max_attendance.hour_to), - minute=int((max_attendance.hour_to % 1) * 60) + hour=int(max_att.hour_to), + minute=int((max_att.hour_to % 1) * 60) ) - timedelta(hours=8) - - # 根据选择的时间区间处理 - if record.correct_interval == 'half': - if not attendance.check_in: - values['check_in'] = half_day_start - values['is_check_in_red'] = True - elif attendance.check_in > half_day_start: - values['check_in'] = half_day_start - values['is_check_in_red'] = True - elif record.correct_interval == 'second_half': - if not attendance.check_out: - values['check_out'] = second_half_end - values['is_check_out_red'] = True - elif attendance.check_out < second_half_end: - values['check_out'] = second_half_end - values['is_check_out_red'] = True - else: - if not attendance.check_in: - values['check_in'] = half_day_start - values['is_check_in_red'] = True - elif attendance.check_in > half_day_start: - values['check_in'] = half_day_start - values['is_check_in_red'] = True - - if not attendance.check_out: - values['check_out'] = second_half_end - values['is_check_out_red'] = True - elif attendance.check_out < second_half_end: - values['check_out'] = second_half_end - values['is_check_out_red'] = True else: - shift = attendance.shift_id - template = shift.template_id - shift_date = shift.start_datetime.date() - # 计算正常上下班时间 - normal_check_in = datetime.combine(shift_date, datetime.min.time()).replace( + role_id = employee.default_planning_role_id + template = self.env['planning.slot.template'].search( + [('role_id', '=', role_id.id)], limit=1) + normal_check_in = current_date.replace( hour=int(template.start_time), minute=int((template.start_time % 1) * 60) ) - timedelta(hours=8) - normal_check_out = datetime.combine(shift_date, datetime.min.time()).replace( - hour=int(template.end_time), - minute=int((template.end_time % 1) * 60) - ) - timedelta(hours=8) - # 处理次日班次 - if template.day2 == '次日' and template.planning_name != '中夜': - normal_check_out = datetime.combine(shift_date, datetime.min.time()).replace( + + # 下班时间(支持次日) + if template.day2 == '次日': + normal_check_out = current_date.replace( hour=int(template.end_time2), minute=int((template.end_time2 % 1) * 60) ) - timedelta(hours=8) + timedelta(days=1) - # 根据选择的时间区间处理 - if record.correct_interval == 'half': - if not attendance.check_in: - values['check_in'] = normal_check_in - values['is_check_in_red'] = True - elif attendance.check_in > normal_check_in: - values['check_in'] = normal_check_in - values['is_check_in_red'] = True + else: + normal_check_out = current_date.replace( + hour=int(template.end_time), + minute=int((template.end_time % 1) * 60) + ) - timedelta(hours=8) - elif record.correct_interval == 'second_half': - if not attendance.check_out: - values['check_out'] = normal_check_out - values['is_check_out_red'] = True - elif attendance.check_out < normal_check_out: - values['check_out'] = normal_check_out - values['is_check_out_red'] = True + half_day_start = normal_check_in + second_half_end = normal_check_out - else: # 全天 - # 处理上班打卡 - if not attendance.check_in: - values['check_in'] = normal_check_in - values['is_check_in_red'] = True - elif attendance.check_in > normal_check_in: - values['check_in'] = normal_check_in - values['is_check_in_red'] = True + check_in = attendance.check_in + check_out = attendance.check_out - # 处理下班打卡 - if not attendance.check_out: - values['check_out'] = normal_check_out - values['is_check_out_red'] = True - elif attendance.check_out < normal_check_out: - values['check_out'] = normal_check_out - values['is_check_out_red'] = True + if record.correct_interval == 'half': + if not check_in or check_in > half_day_start: + values['check_in'] = half_day_start + values['is_check_in_red'] = True + + elif record.correct_interval == 'second_half': + if not check_out or check_out < second_half_end: + values['check_out'] = second_half_end + values['is_check_out_red'] = True + + else: + if not check_in or check_in > half_day_start: + values['check_in'] = half_day_start + values['is_check_in_red'] = True + if not check_out or check_out < second_half_end: + values['check_out'] = second_half_end + values['is_check_out_red'] = True attendance.write(values) - - diff --git a/yuthon_hr_employee_approval/models/yuthon_onboard_approval.py b/yuthon_hr_employee_approval/models/yuthon_onboard_approval.py index b1be9e200..7b395b65c 100644 --- a/yuthon_hr_employee_approval/models/yuthon_onboard_approval.py +++ b/yuthon_hr_employee_approval/models/yuthon_onboard_approval.py @@ -71,6 +71,7 @@ class YuthonOnboardApproval(models.Model): representatives = fields.Char(related='party_id.representatives', string='法定代表人或委托代理人') economy_type = fields.Char(related='party_id.economy_type', string='经济类型') address = fields.Text(related='party_id.address', string='通讯地址') + shift_role_id = fields.Many2one('planning.role', string='班次角色') phone = fields.Char(string='联系电话', required=True) card = fields.Char(string='身份证号码', required=True) salary_group_id = fields.Many2one( @@ -197,6 +198,8 @@ class YuthonOnboardApproval(models.Model): 'is_annual_salary': self.is_annual_salary, 'work_email': login_id.email, 'job_id': self.job_id.id, + 'planning_role_ids': [(6, 0, [self.shift_role_id.id])] if self.shift_role_id.name != "集团行政" else [], + 'default_planning_role_id': self.shift_role_id.id if self.shift_role_id.name != "集团行政" else False, 'resource_calendar_id': resource_calendar_id.id, 'department_id': self.department_id1.id }) diff --git a/yuthon_hr_employee_approval/views/yuthon_onboard_approval_views.xml b/yuthon_hr_employee_approval/views/yuthon_onboard_approval_views.xml index 05e71e579..bebcd1667 100644 --- a/yuthon_hr_employee_approval/views/yuthon_onboard_approval_views.xml +++ b/yuthon_hr_employee_approval/views/yuthon_onboard_approval_views.xml @@ -75,6 +75,7 @@ +