diff --git a/soong_workflow/wizard/soong_workflow_comment_wizard.py b/soong_workflow/wizard/soong_workflow_comment_wizard.py index 266ee4540..b8d01b638 100644 --- a/soong_workflow/wizard/soong_workflow_comment_wizard.py +++ b/soong_workflow/wizard/soong_workflow_comment_wizard.py @@ -484,7 +484,7 @@ class SoongWorkflowCommentWizard(models.TransientModel): ("done_by", "=", query_user_id), ("node_id", "=", self.node_btn_id.node_id.id), ], - order="lase_click_date DESC", + order="create_date DESC", limit=1 ) # 创建或更新当前用户的审批记录 diff --git a/yuthon_holiday/views/hr_leave_batch.xml b/yuthon_holiday/views/hr_leave_batch.xml index 21b35f395..f1dbe7d51 100644 --- a/yuthon_holiday/views/hr_leave_batch.xml +++ b/yuthon_holiday/views/hr_leave_batch.xml @@ -412,6 +412,13 @@ code action = model.update_state() + + 标识改成True + + + code + action = model.update_is_vacation() + =', first_day) ], order='vacation_date asc') for rep in future_reps: diff --git a/yuthon_hr_attendance/models/yuthon_vacation_reports.py b/yuthon_hr_attendance/models/yuthon_vacation_reports.py index 6a96d5a19..1881e0025 100644 --- a/yuthon_hr_attendance/models/yuthon_vacation_reports.py +++ b/yuthon_hr_attendance/models/yuthon_vacation_reports.py @@ -315,6 +315,9 @@ class YuthonVacationReports(models.Model): self_overtime = rec.overtime_ids.filtered(lambda o: not o.workflow_record_id and o.text == '上月额度继承') self_overtime.workday = (rec.dynamic_previous_year1 + rec.this_year1) * 8 + self_meal = rec.meal_fee_ids.filtered(lambda o: not o.workflow_record_id and o.text == '上月额度继承') + self_meal.update_lines = rec.remain_missed_meals + valid_leave_lines = rec.leave_ids.filtered( lambda l: l.workflow_record_id and l.update_type == 'reduce' and l.is_void != True ) @@ -1401,6 +1404,13 @@ class YuthonVacationReports(models.Model): employee_ids = calendar.resource_user_ids.ids target_employee_ids.update(employee_ids) for rec in self: + employee = rec.employee_id + vacation_date = rec.vacation_date + unpaid_leaves = self.env['hr.leave'].search([ + ('employee_id', '=', employee.id), + ('holiday_status_id.name', '=', ['产假']), + ('state', '=', 'validate') + ]) last_month_last = rec.vacation_date - timedelta(days=1) last_month_first = last_month_last.replace(day=1) last_month_record = self.search([ @@ -1454,6 +1464,49 @@ class YuthonVacationReports(models.Model): inherit_vals['valid_date1'] = last_month_record.valid_date1 rec.write(inherit_vals) + if unpaid_leaves: + for leave in unpaid_leaves: + leave_start = leave.date_from.date() + leave_end = leave.date_to.date() + current_month_start = vacation_date + current_month_end = (current_month_start + relativedelta(months=1)) - timedelta(days=1) + real_start = max(leave_start, current_month_start) + real_end = min(leave_end, current_month_end) + if real_start > real_end: + continue + # 计算当前月的天数 + days = self._compute_duration_day(leave.holiday_status_id, real_start, real_end) + # 取 workflow + if leave.batch_id: + main_leave_record = leave.batch_id + elif leave.hour_batch_id: + main_leave_record = leave.hour_batch_id + else: + main_leave_record = leave + + workflow = self.env['soong.workflow.record'].search([ + ('code', '=', main_leave_record.code) + ], limit=1) + # 防重 + existing_line = self.env['vacation.other.line'].search([ + ('vacation_id', '=', rec.id), + ('employee_id', '=', employee.id), + ('text', '=', '请假审批'), + ('workflow_record_id', '=', workflow.id if workflow else False), + ], limit=1) + # 创建 + if not existing_line and days > 0: + self.env['vacation.other.line'].create({ + 'vacation_id': rec.id, + 'employee_id': employee.id, + 'workflow_record_id': workflow.id if workflow else False, + 'update_type': 'reduce', + 'update_date': fields.Date.today(), + 'lines': days, + 'text': '请假审批', + 'is_void': False, + }) + if rec.remain_missed_meals: self._update_meal_lines(rec, [rec], rec.remain_missed_meals) if rec.leave: @@ -1659,6 +1712,89 @@ class YuthonVacationReports(models.Model): record.overtime_public_holidays_total = public_holidays_total record.overtime_grand_total = workday_total + legal_day_total + public_holidays_total + def _compute_duration_day(self, holiday_status_id, start_date, end_date): + """ + 计算请假时长 + :param holiday_status_id: 请假类型 + :param start_date: 开始时间 + :param end_date: 结束时间 + :return:天 + """ + employee_id = self.employee_id + use_planning = False + if employee_id and employee_id.resource_id: + roles = self.env['planning.role'].sudo().search([ + ('name', 'in', ['保安部', '工程部', '联安粮储']) + ]) + all_resources = roles.mapped('resource_ids') + if employee_id.resource_id in all_resources: + use_planning = True + if use_planning: + if not start_date or not end_date: + return 0 + slots = self.env['planning.slot'].sudo().search([ + ('resource_id', '=', employee_id.resource_id.id), + ('start_datetime', '>=', datetime.combine(start_date, datetime.min.time())), + ('end_datetime', '<=', datetime.combine(end_date, datetime.max.time())), + ]) + work_days = set() + for slot in slots: + day = slot.start_datetime.date() + if start_date <= day <= end_date: + work_days.add(day) + return len(work_days) + + else: + # 如果是自然日: + if holiday_status_id.type_of_work == "1": + if start_date and end_date: + days = (end_date - start_date).days + 1 + else: + days = 0 + return days + if holiday_status_id.type_of_work == "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) + calendar_leaves = self.env['resource.calendar.leaves'].sudo().search([ + ("calendar_id.name", "=", "行政考勤工作日"), + ("date_from", ">=", query_start), + ("date_from", "<=", query_end) + ]) + holidays_list = [] + shift_days_list = [] + # 提取节假日和调休日 + for leave in calendar_leaves: + if leave.holidays: + holidays_list.extend(leave.holidays.split(',')) + if leave.alternate_rest_day: + holidays_list.extend(leave.alternate_rest_day.split(',')) + if leave.shift_replacement_day: + shift_days_list.extend(leave.shift_replacement_day.split(',')) + + 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] + days = 0 # 初始化工作日计数 + current_date = 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) + is_weekend = current_date.weekday() in [5, 6] + if current_date_str in holidays_list: + # 如果是法定节假日,不计为工作日 + pass + elif current_date_str in shift_days_list: + # 如果是调休日,无论是否周末都算作工作日 + days += 1 + elif not is_weekend: + # 如果不是周末且不是节假日,算作工作日 + days += 1 + current_date += timedelta(days=1) + else: + delta = end_date - start_date + days = delta.days + 1 + return days + def action_overtime_change(self): """打开加班变更向导""" self.ensure_one() @@ -1737,28 +1873,30 @@ class YuthonVacationReports(models.Model): rec.vacation_state = 'confirmed' def monthly_report(self): - # fixed_date = date(2026, 2, 1) today = fields.Date.today() current_month_first = today.replace(day=1) + from dateutil.relativedelta import relativedelta + next_month_first = current_month_first + relativedelta(months=1) + target_months = [current_month_first, next_month_first] employees = self.env['hr.employee'].search([ ('user_state', '=', 'in') ]) - # today = fields.Date.today() for employee in employees: resource_user_ids = employee.resource_calendar_id.resource_user_ids.ids is_resource_user = employee.id in resource_user_ids - existing_record = self.search([ - ('employee_id', '=', employee.id), - ('vacation_date', '=', current_month_first) - ], limit=1) - # if not existing_record and not is_resource_user: - if not existing_record: - report_id = self.create({ - 'employee_id': employee.id, - 'vacation_date': current_month_first, - }) - report_id.manage_reject() - report_id.vacation_state = 'not_sent' + for target_month in target_months: + existing_record = self.search([ + ('employee_id', '=', employee.id), + ('vacation_date', '=', target_month) + ], limit=1) + + if not existing_record: + report_id = self.create({ + 'employee_id': employee.id, + 'vacation_date': target_month, + }) + report_id.update_line() + report_id.vacation_state = 'not_sent' def _update_leave_lines(self, report, allocations, number_of_hours_display): for alloc in allocations: