From 56ff0c8bbf5c4432200b3b24dc2b9481549e4e72 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: Fri, 6 Feb 2026 21:01:22 +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 --- .../models/yuthon_vacation_reports.py | 117 ++++++++---------- 1 file changed, 49 insertions(+), 68 deletions(-) diff --git a/yuthon_hr_attendance/models/yuthon_vacation_reports.py b/yuthon_hr_attendance/models/yuthon_vacation_reports.py index afb0d0092..2f014b047 100644 --- a/yuthon_hr_attendance/models/yuthon_vacation_reports.py +++ b/yuthon_hr_attendance/models/yuthon_vacation_reports.py @@ -648,13 +648,10 @@ class YuthonVacationReports(models.Model): is_early = 0 is_no = 0 is_work = 0 - leave_days = 0 - test_days = 0 - statutory_days = 0 is_abnormal = 0 - right_days = 0 - actual_attendance = 0 # 实到天数 = 应到天数 - 请假总天数 - 异常天数 + 法定节假日 - total_leave_days = 0 # 请假工作流总天数(含小时折算) + probation_days = 0 # 试用期天数 + regular_days = 0 # 转正天数 + actual_attendance = 0 # 实到天数 = 应到天数 - 请假总天数 - 异常天数 is_retired = rec.employee_id.user_state in ('leave', 'withdraw') if rec.employee_id and rec.vacation_date and not is_retired: year = rec.vacation_date.year @@ -677,8 +674,10 @@ class YuthonVacationReports(models.Model): if attendances: valid_attendances = [ att for att in attendances - if (att.check_in or att.check_out) # 有有效打卡 + if (att.check_in or att.check_out) and att.shift_name != '休息' + and (not att.workflow_id or att.workflow_id.workflow_id.name != '请假') + and not att.is_abnormal ] if valid_attendances: actual_attendance += 1 @@ -695,21 +694,6 @@ class YuthonVacationReports(models.Model): if att.is_abnormal: is_abnormal += 1 - for att in attendances: - if att.workflow_id and att.workflow_id.workflow_id.name == '请假': - res_model = att.workflow_id.res_model - res_id = att.workflow_id.res_id - if res_model and res_id: - related_model = self.env[res_model].sudo().browse(res_id) - if related_model.exists(): - if related_model.days: - total_leave_days += float(related_model.days) - # 小时数折算为天数(1天=8小时) - elif related_model.hours: - total_leave_days += float(related_model.hours) / 8 - - actual_attendance = actual_attendance - total_leave_days - is_abnormal - employee = rec.employee_id contract = employee.contract_id is_outside = employee.user_role_id.name == '外派' @@ -722,32 +706,34 @@ class YuthonVacationReports(models.Model): start_date = month_start # 计算end_date:外派且无合同时用month_end;有合同且有结束日则取最小值;其他情况用month_end end_date = month_end if (is_outside and not contract) else (min(contract.date_end, month_end) if contract.date_end else month_end) - leave_days, statutory_days = rec._create_leave_record(rec.employee_id, start_date, end_date) + work_days = rec._create_leave_record(rec.employee_id, start_date, end_date) probation_contract = self.env['hr.contract'].search([ ('employee_id', '=', rec.employee_id.id), ('is_probation', '=', True), ('end_date', '>=', month_start), ], limit=1) if probation_contract: - end_date = min(probation_contract.end_date, month_end) - start_date = max(probation_contract.start_date, month_start) - work_days, statutory_days = rec._create_leave_record(rec.employee_id, start_date, end_date) - test_days = work_days + statutory_days - right_days = (leave_days + statutory_days) - (work_days + statutory_days) - else: - test_days = 0 - right_days = 0 + prob_end = min(probation_contract.end_date, month_end) + prob_start = max(probation_contract.start_date, month_start) + if prob_start <= prob_end: # 避免开始日期大于结束日期 + probation_days = rec._create_leave_record(rec.employee_id, prob_start, prob_end) - rec.should_attendance = leave_days + statutory_days - rec.test_days = test_days - rec.right_days = right_days - rec.is_late_card = is_late - rec.is_early_card = is_early - rec.is_no_card = is_no - rec.is_work = is_work - rec.is_abnormal = is_abnormal - rec.actual_attendance = max(actual_attendance + statutory_days, 0) - rec.att_mount = actual_attendance + # 转正阶段的时间范围:当月剩余时段(实习结束后 → 月末) + reg_start = prob_end + timedelta(days=1) + reg_end = month_end + if reg_start <= reg_end: + regular_days = rec._create_leave_record(rec.employee_id, reg_start, reg_end) + + rec.should_attendance = work_days + rec.test_days = probation_days + rec.right_days = regular_days + rec.is_late_card = is_late + rec.is_early_card = is_early + rec.is_no_card = is_no + rec.is_work = is_work + rec.is_abnormal = is_abnormal + rec.actual_attendance = actual_attendance + rec.att_mount = actual_attendance def update_is_confirm1(self): records = self.env["yuthon.vacation.reports"].browse( @@ -857,8 +843,9 @@ class YuthonVacationReports(models.Model): def _create_leave_record(self, employee_id, start_date, end_date): entry_date = employee_id.entry_date - # 调整日期范围:如果开始日期早于入职日期,则从入职日期开始计算 actual_start_date = max(start_date, entry_date) if entry_date else start_date + if actual_start_date > end_date: + return 0 current_year = (fields.Date.today() + timedelta(hours=8)).year query_start = datetime(current_year, 1, 1, 0, 0, 0) - timedelta(hours=8) query_end = datetime(current_year, 12, 31, 23, 59, 59) - timedelta(hours=8) @@ -867,43 +854,37 @@ class YuthonVacationReports(models.Model): ("date_from", ">=", query_start), ("date_from", "<=", query_end) ]) - holidays_list = [] # 节假日列表 - statutory_list = [] # 法定节假日列表 - shift_days_list = [] # 调休日列表 - # 提取节假日和调休日 + exclude_days = set() + include_shift_days = set() + for leave in calendar_leaves: + # 法定节假日 if leave.holidays: - holidays_list.extend(leave.holidays.split(',')) - statutory_list.extend(leave.holidays.split(',')) + exclude_days.update([self.remove_leading_zero(d) for d in leave.holidays.split(',')]) + # 调休休息日 if leave.alternate_rest_day: - holidays_list.extend(leave.alternate_rest_day.split(',')) + exclude_days.update([self.remove_leading_zero(d) for d in leave.alternate_rest_day.split(',')]) + # 调班日 if leave.shift_replacement_day: - shift_days_list.extend(leave.shift_replacement_day.split(',')) + include_shift_days.update([self.remove_leading_zero(d) for d in leave.shift_replacement_day.split(',')]) - # 去除日期中的前导零(如"01月05日"→"1月5日") - holidays_list = [self.remove_leading_zero(date) for date in holidays_list] - shift_days_list = [self.remove_leading_zero(date) for date in shift_days_list] - statutory_list = [self.remove_leading_zero(date) for date in statutory_list] - - work_days = 0 # 工作日计数 - statutory_days = 0 # 法定节假日计数 + total_days = 0 current_date = actual_start_date - while current_date <= end_date: - current_date_str = current_date.strftime('%m月%d日') - current_date_str = self.remove_leading_zero(current_date_str) + current_date_str = self.remove_leading_zero(current_date.strftime('%m月%d日')) is_weekend = current_date.weekday() in [5, 6] - is_statutory = current_date_str in statutory_list - is_holiday = current_date_str in holidays_list - is_shift_day = current_date_str in shift_days_list - if is_shift_day or (not is_weekend and not is_holiday): - work_days += 1 - if is_statutory: - statutory_days += 1 + is_exclude = current_date_str in exclude_days + is_shift_day = current_date_str in include_shift_days + + if not is_exclude: + if not is_weekend: + total_days += 1 + elif is_shift_day: + total_days += 1 current_date += timedelta(days=1) - return work_days, statutory_days + return total_days def remove_leading_zero(self, date_str): month, day = date_str.split('月')