@@ -520,8 +520,6 @@ class HolidaysRequestBatch(models.Model):
|
||||
]
|
||||
for leave_type in other_leave_types:
|
||||
self._process_specific_leaves(leave_type, is_annual_leave=False)
|
||||
|
||||
_logger.info(f"请假申请:{self.code} 处理完成")
|
||||
return True
|
||||
|
||||
def _process_specific_leaves(self, leave_type_name, is_annual_leave):
|
||||
@@ -530,209 +528,130 @@ class HolidaysRequestBatch(models.Model):
|
||||
:param leave_type_name: 假期类型名称
|
||||
:param is_annual_leave: 是否为年假(True/False)
|
||||
"""
|
||||
_logger.info(f"开始处理假期类型:{leave_type_name},是否为年假:{is_annual_leave},申请编号:{self.code}")
|
||||
|
||||
# 收集天假和小时假记录
|
||||
day_leaves = self._get_day_leaves(leave_type_name)
|
||||
hourly_leaves = self._get_hourly_leaves(leave_type_name)
|
||||
|
||||
_logger.debug(f"假期类型:{leave_type_name},天假记录数:{len(day_leaves)},小时假记录数:{len(hourly_leaves)}")
|
||||
|
||||
# 处理天假
|
||||
for idx, leave in enumerate(day_leaves):
|
||||
try:
|
||||
# 跨月拆分逻辑(仅非年假)
|
||||
date_ranges = self._split_by_month(leave['start'], leave['end']) if not is_annual_leave else [
|
||||
{'start': leave['start'], 'end': leave['end']}
|
||||
]
|
||||
_logger.debug(
|
||||
f"天假记录 {idx + 1} 拆分后日期段数:{len(date_ranges)},原始起止:{leave['start']}至{leave['end']}")
|
||||
|
||||
for period in date_ranges:
|
||||
days = self._compute_duration_day(leave['type_id'], period['start'], period['end'])
|
||||
_logger.debug(f"日期段 {period['start']}至{period['end']} 计算天数:{days}")
|
||||
|
||||
if days > 0:
|
||||
if is_annual_leave:
|
||||
self._create_annual_leave_line(period['start'], leave, days, period)
|
||||
else:
|
||||
self._create_other_leave_line(period['start'], leave, days, period, leave_type_name)
|
||||
except Exception as e:
|
||||
_logger.error(f"处理天假记录 {idx + 1} 失败(类型:{leave_type_name}):{str(e)}", exc_info=True)
|
||||
|
||||
# 处理小时假
|
||||
for idx, leave in enumerate(hourly_leaves):
|
||||
try:
|
||||
leave_date = leave['date']
|
||||
days = leave['days']
|
||||
_logger.debug(f"小时假记录 {idx + 1} 日期:{leave_date},转换天数:{days}")
|
||||
|
||||
for leave in day_leaves:
|
||||
date_ranges = self._split_by_month(leave['start'], leave['end']) if not is_annual_leave else [
|
||||
{'start': leave['start'], 'end': leave['end']}]
|
||||
for period in date_ranges:
|
||||
days = self._compute_duration_day(leave['type_id'], period['start'], period['end'])
|
||||
if days > 0:
|
||||
if is_annual_leave:
|
||||
self._create_annual_leave_line(leave_date, leave, days,
|
||||
{'start': leave_date, 'end': leave_date})
|
||||
self._create_annual_leave_line(period['start'], leave, days, period)
|
||||
else:
|
||||
self._create_other_leave_line(leave_date, leave, days, {'start': leave_date, 'end': leave_date},
|
||||
leave_type_name)
|
||||
except Exception as e:
|
||||
_logger.error(f"处理小时假记录 {idx + 1} 失败(类型:{leave_type_name}):{str(e)}", exc_info=True)
|
||||
|
||||
_logger.info(f"假期类型:{leave_type_name} 处理完成")
|
||||
self._create_other_leave_line(period['start'], leave, days, period, leave_type_name)
|
||||
# 处理小时假
|
||||
for leave in hourly_leaves:
|
||||
leave_date = leave['date']
|
||||
days = leave['days']
|
||||
if days > 0:
|
||||
if is_annual_leave:
|
||||
self._create_annual_leave_line(leave_date, leave, days, {'start': leave_date, 'end': leave_date})
|
||||
else:
|
||||
self._create_other_leave_line(leave_date, leave, days,{'start': leave_date, 'end': leave_date}, leave_type_name)
|
||||
|
||||
def _create_other_leave_line(self, period_start, leave_data, days, period, leave_type_name):
|
||||
"""为非年假类型创建vacation.other.line记录"""
|
||||
try:
|
||||
report_month = date(period_start.year, period_start.month, 1)
|
||||
vacation_report = self.env['yuthon.vacation.reports'].search([
|
||||
('employee_id', '=', self.users_id.employee_id.id),
|
||||
('vacation_date', '>=', fields.Date.to_string(report_month)),
|
||||
('vacation_date', '<=', fields.Date.to_string(
|
||||
date(period_start.year, period_start.month,
|
||||
calendar.monthrange(period_start.year, period_start.month)[1]))
|
||||
)
|
||||
], limit=1)
|
||||
# 查找关联的假期额度记录
|
||||
report_month = date(period_start.year, period_start.month, 1)
|
||||
vacation_report = self.env['yuthon.vacation.reports'].search([
|
||||
('employee_id', '=', self.users_id.employee_id.id),
|
||||
('vacation_date', '>=', fields.Date.to_string(report_month)),
|
||||
('vacation_date', '<=', fields.Date.to_string(
|
||||
date(period_start.year, period_start.month,
|
||||
calendar.monthrange(period_start.year, period_start.month)[1]))
|
||||
)
|
||||
], limit=1)
|
||||
|
||||
_logger.debug(
|
||||
f"创建非年假明细(类型:{leave_type_name}),关联假期记录:{vacation_report.id if vacation_report else '无'},天数:{days}")
|
||||
|
||||
record = self.env['vacation.other.line'].sudo().create({
|
||||
'vacation_id': vacation_report.id if vacation_report else False,
|
||||
'holiday_type': leave_data['type_id'].id,
|
||||
'employee_id': self.users_id.employee_id.id,
|
||||
'workflow_record_id': leave_data['workflow_id'],
|
||||
'update_date': fields.Date.today(),
|
||||
'update_type': 'reduce',
|
||||
'lines': days,
|
||||
'text': f"请假审批"
|
||||
})
|
||||
_logger.info(f"成功创建非年假明细记录:{record.id}(类型:{leave_type_name})")
|
||||
except Exception as e:
|
||||
_logger.error(f"创建非年假明细失败(类型:{leave_type_name}):{str(e)}", exc_info=True)
|
||||
self.env['vacation.other.line'].create({
|
||||
'vacation_id': vacation_report.id if vacation_report else False,
|
||||
'holiday_type': leave_data['type_id'].id,
|
||||
'employee_id': self.users_id.employee_id.id,
|
||||
'workflow_record_id': leave_data['workflow_id'],
|
||||
'update_date': fields.Date.today(),
|
||||
'update_type': 'reduce',
|
||||
'lines': days,
|
||||
'text': f"请假审批"
|
||||
})
|
||||
_logger.info(f"成功创建非年假明细记录(类型:{leave_type_name}),天数为{days}天,员工ID为{self.users_id.employee_id.id}")
|
||||
|
||||
def _get_day_leaves(self, leave_type_name):
|
||||
try:
|
||||
workflow_id = self.env['soong.workflow.record'].search([('code', '=', self.code)], limit=1).id
|
||||
records = [{
|
||||
workflow_id = self.env['soong.workflow.record'].search([('code', '=', self.code)], limit=1).id
|
||||
return [{
|
||||
'start': fields.Date.from_string(leave.request_date_from),
|
||||
'end': fields.Date.from_string(leave.request_date_to),
|
||||
'type_id': leave.holiday_status_id,
|
||||
'workflow_id': workflow_id}
|
||||
for leave in self.leave_ids
|
||||
if leave.holiday_status_id.name == leave_type_name
|
||||
and leave.request_date_from
|
||||
and leave.request_date_to
|
||||
]
|
||||
_logger.debug(f"收集天假记录(类型:{leave_type_name}):{len(records)}条")
|
||||
return records
|
||||
except Exception as e:
|
||||
_logger.error(f"收集天假记录失败(类型:{leave_type_name}):{str(e)}", exc_info=True)
|
||||
return []
|
||||
for leave in self.leave_ids
|
||||
if leave.holiday_status_id.name == leave_type_name
|
||||
and leave.request_date_from
|
||||
and leave.request_date_to
|
||||
]
|
||||
|
||||
def _get_hourly_leaves(self, leave_type_name):
|
||||
try:
|
||||
workflow_id = self.env['soong.workflow.record'].search([('code', '=', self.code)], limit=1).id
|
||||
hourly_records = []
|
||||
for line in self.hour_leave_ids:
|
||||
if line.holiday_status_id.name == leave_type_name and line.request_date_from:
|
||||
hours_match = re.search(r'(\d+(?:\.\d+)?)', line.number_of_hours_text or '')
|
||||
hours = float(hours_match.group(1)) if hours_match else 0
|
||||
days = hours / 8
|
||||
hourly_records.append({
|
||||
'date': fields.Date.from_string(line.request_date_from),
|
||||
'type_id': line.holiday_status_id,
|
||||
'workflow_id': workflow_id,
|
||||
'days': days
|
||||
})
|
||||
_logger.debug(f"收集小时假记录(类型:{leave_type_name}):{len(hourly_records)}条")
|
||||
return hourly_records
|
||||
except Exception as e:
|
||||
_logger.error(f"收集小时假记录失败(类型:{leave_type_name}):{str(e)}", exc_info=True)
|
||||
return []
|
||||
workflow_id = self.env['soong.workflow.record'].search([('code', '=', self.code)], limit=1).id
|
||||
hourly_records = []
|
||||
for line in self.hour_leave_ids:
|
||||
if line.holiday_status_id.name == leave_type_name and line.request_date_from:
|
||||
hours_match = re.search(r'(\d+(?:\.\d+)?)', line.number_of_hours_text or '')
|
||||
hours = float(hours_match.group(1)) if hours_match else 0
|
||||
hourly_records.append({
|
||||
'date': fields.Date.from_string(line.request_date_from),
|
||||
'type_id': line.holiday_status_id,
|
||||
'workflow_id': workflow_id,
|
||||
'days': hours / 8 # 转换为天数
|
||||
})
|
||||
return hourly_records
|
||||
|
||||
def _split_by_month(self, start_date, end_date):
|
||||
try:
|
||||
date_ranges = []
|
||||
if start_date.month == end_date.month and start_date.year == end_date.year:
|
||||
date_ranges.append({'start': start_date, 'end': end_date})
|
||||
_logger.debug(f"无需跨月拆分:{start_date}至{end_date}")
|
||||
return date_ranges
|
||||
|
||||
first_month_end = date(start_date.year, start_date.month,
|
||||
calendar.monthrange(start_date.year, start_date.month)[1])
|
||||
date_ranges.append({'start': start_date, 'end': first_month_end})
|
||||
|
||||
current_month = start_date.month + 1
|
||||
current_year = start_date.year
|
||||
while (current_year < end_date.year) or (current_year == end_date.year and current_month < end_date.month):
|
||||
if current_month > 12:
|
||||
current_month = 1
|
||||
current_year += 1
|
||||
month_end = date(current_year, current_month, calendar.monthrange(current_year, current_month)[1])
|
||||
date_ranges.append({'start': date(current_year, current_month, 1), 'end': month_end})
|
||||
current_month += 1
|
||||
|
||||
date_ranges.append({'start': date(end_date.year, end_date.month, 1), 'end': end_date})
|
||||
|
||||
_logger.debug(f"跨月拆分完成:原始{start_date}至{end_date},拆分为{len(date_ranges)}段")
|
||||
# 跨月拆分逻逻辑
|
||||
date_ranges = []
|
||||
if start_date.month == end_date.month and start_date.year == end_date.year:
|
||||
date_ranges.append({'start': start_date, 'end': end_date})
|
||||
return date_ranges
|
||||
except Exception as e:
|
||||
_logger.error(f"跨月拆分失败({start_date}至{end_date}):{str(e)}", exc_info=True)
|
||||
return []
|
||||
|
||||
def _compute_duration_day(self, holiday_type_id, start_date, end_date):
|
||||
try:
|
||||
if not start_date or not end_date or start_date > end_date:
|
||||
_logger.warning(f"无效日期范围:{start_date}至{end_date},返回0天")
|
||||
return 0.0
|
||||
first_month_end = date(start_date.year, start_date.month,
|
||||
calendar.monthrange(start_date.year, start_date.month)[1])
|
||||
date_ranges.append({'start': start_date, 'end': first_month_end})
|
||||
current_month = start_date.month + 1
|
||||
current_year = start_date.year
|
||||
while (current_year < end_date.year) or (current_year == end_date.year and current_month < end_date.month):
|
||||
if current_month > 12:
|
||||
current_month = 1
|
||||
current_year += 1
|
||||
month_end = date(current_year, current_month, calendar.monthrange(current_year, current_month)[1])
|
||||
date_ranges.append({'start': date(current_year, current_month, 1), 'end': month_end})
|
||||
current_month += 1
|
||||
|
||||
holiday = self.env['hr.leave.type'].browse(holiday_type_id.id)
|
||||
total_days = (end_date - start_date).days + 1
|
||||
|
||||
if holiday.work_entry_type_id:
|
||||
work_days = 0
|
||||
current_date = start_date
|
||||
while current_date <= end_date:
|
||||
if current_date.isoweekday() not in [6, 7]:
|
||||
work_days += 1
|
||||
current_date += timedelta(days=1)
|
||||
_logger.debug(f"工作日计算:{start_date}至{end_date},共{work_days}天(排除周末)")
|
||||
return work_days
|
||||
|
||||
_logger.debug(f"自然日计算:{start_date}至{end_date},共{total_days}天")
|
||||
return total_days
|
||||
except Exception as e:
|
||||
_logger.error(f"计算天数失败({start_date}至{end_date}):{str(e)}", exc_info=True)
|
||||
return 0.0
|
||||
date_ranges.append({'start': date(end_date.year, end_date.month, 1), 'end': end_date})
|
||||
return date_ranges
|
||||
|
||||
def _create_annual_leave_line(self, period_start, leave_data, days, period):
|
||||
"""更新年假记录"""
|
||||
try:
|
||||
report_month = date(period_start.year, period_start.month, 1)
|
||||
vacation_report = self.env['yuthon.vacation.reports'].search([
|
||||
('employee_id', '=', self.users_id.employee_id.id),
|
||||
('vacation_date', '>=', fields.Date.to_string(report_month)),
|
||||
('vacation_date', '<=', fields.Date.to_string(
|
||||
date(period_start.year, period_start.month,
|
||||
calendar.monthrange(period_start.year, period_start.month)[1]))
|
||||
)
|
||||
], limit=1)
|
||||
|
||||
_logger.debug(f"创建年假明细,关联假期记录:{vacation_report.id if vacation_report else '无'},天数:{days}")
|
||||
|
||||
record = self.env['vacation.leave.line'].create({
|
||||
'vacation_id': vacation_report.id if vacation_report else False,
|
||||
'employee_id': self.users_id.employee_id.id,
|
||||
'workflow_record_id': leave_data['workflow_id'],
|
||||
'update_type': 'reduce',
|
||||
'update_date': fields.Date.today(),
|
||||
'update_lines': days,
|
||||
'is_void': False,
|
||||
'allocation_type': 'vacation',
|
||||
'text': f"请假审批"
|
||||
})
|
||||
_logger.info(f"成功创建年假明细记录:{record.id}")
|
||||
except Exception as e:
|
||||
_logger.error(f"创建年假明细失败:{str(e)}", exc_info=True)
|
||||
report_month = date(period_start.year, period_start.month, 1)
|
||||
vacation_report = self.env['yuthon.vacation.reports'].search([
|
||||
('employee_id', '=', self.users_id.employee_id.id),
|
||||
('vacation_date', '>=', fields.Date.to_string(report_month)),
|
||||
('vacation_date', '<=', fields.Date.to_string(
|
||||
date(period_start.year, period_start.month,
|
||||
calendar.monthrange(period_start.year, period_start.month)[1]))
|
||||
)
|
||||
], limit=1)
|
||||
# 创建年假明细记录
|
||||
self.env['vacation.leave.line'].create({
|
||||
'vacation_id': vacation_report.id if vacation_report else False,
|
||||
'employee_id': self.users_id.employee_id.id,
|
||||
'workflow_record_id': leave_data['workflow_id'],
|
||||
'update_type': 'reduce',
|
||||
'update_date': fields.Date.today(),
|
||||
'update_lines': days,
|
||||
'is_void': False,
|
||||
'allocation_type': 'vacation',
|
||||
'text': f"请假审批"
|
||||
})
|
||||
|
||||
|
||||
def _compute_duration_day(self, holiday_status_id, start_date, end_date):
|
||||
|
||||
Reference in New Issue
Block a user