!12657 添加功能

Merge pull request !12657 from 李鹏宇/dev_zhou
This commit is contained in:
李鹏宇
2026-08-18 04:24:23 +00:00
committed by Gitee
2 changed files with 79 additions and 62 deletions
+16 -14
View File
@@ -864,30 +864,32 @@ class HolidaysRequestBatch(models.Model):
interval_hours = hours / 8
else:
interval_hours = self._compute_duration_day(holiday_type, interval_start, interval_end)
period_start = interval['period_start']
vacation_report1 = self.env['yuthon.vacation.reports'].search([
period_start = interval['period_start']
if not employee_id:
continue
# 严格按请假所属月份定位报表(不再回退到当前月 first_day)。
# 产假等长假期会落到未来月份,而 yuthon.vacation.reports 只提前一个月生成,
# 未来月份报表尚未生成 → 按需生成(与 monthly_report 创建方式一致)。
vacation_report = self.env['yuthon.vacation.reports'].search([
('employee_id', '=', employee_id),
('vacation_date', '=', period_start),
], limit=1)
first_day = fields.Date.today().replace(day=1)
vacation_report = self.env['yuthon.vacation.reports'].search([
('employee_id', '=', employee_id),
('vacation_date', '=', first_day),
], limit=1)
actual_vacation_report = vacation_report
if vacation_report1 and vacation_report1.vacation_state != 'confirmed':
actual_vacation_report = vacation_report1
if not actual_vacation_report:
continue # 无报表,跳过创建
if not vacation_report:
vacation_report = self.env['yuthon.vacation.reports'].create({
'employee_id': employee_id,
'vacation_date': period_start,
})
vacation_report.update_line()
vacation_report.vacation_state = 'not_sent'
leave_id = leave_data.get('leave_id', False)
existing_leave_line = self.env['vacation.other.line'].search([
('vacation_id', '=', actual_vacation_report.id),
('vacation_id', '=', vacation_report.id),
('leave_id', '=', leave_id),
], limit=1)
if not existing_leave_line:
self.env['vacation.other.line'].create({
'leave_id': leave_id,
'vacation_id': actual_vacation_report.id,
'vacation_id': vacation_report.id,
'employee_id': employee_id,
'workflow_record_id': leave_data.get('workflow_id', False),
'update_type': 'reduce',
@@ -11,6 +11,17 @@ from odoo.tools import date_utils
from dateutil.relativedelta import relativedelta
from odoo.exceptions import UserError, ValidationError
# 与 inherit_hr_leave.action_submit 中的 OTHER_LEAVE_TYPES 保持一致:
# 排除「年假」「补休」(它们分别落到 vacation.leave.line / vacation.over.line),其余都进 vacation.other.line。
# 注:原 update_line 中专门的「产假」分支(unpaid_leaves)已移除,产假统一由此处自愈逻辑处理,
# 去重键为 (vacation_id, leave_id),与提交侧 _create_other_leave_line 一致,不会重复。
# 如 action_submit 的类型列表有调整,需同步此处。
OTHER_LEAVE_SYNC_TYPES = [
'产假', '事假', '法定假', '调休', '值班调休', '婚假', '陪产假',
'计生假', '丧假', '探亲假', '哺乳假', '家长会假', '病假(普通)',
'病假(住院期)', '育儿假', '病假(出院恢复期)', '考试假',
]
class YuthonVacationReports(models.Model):
_name = 'yuthon.vacation.reports'
@@ -482,6 +493,58 @@ class YuthonVacationReports(models.Model):
rec._compute_parental_leave()
rec._compute_working_overtime()
# ========== 第三步:自愈 - 补建未计入的「其他类型」请假明细 ==========
# 针对产假等长假期:请假跨度覆盖未来月份,而 yuthon.vacation.reports 只提前一个月生成,
# 未来月份的报表在对应月份真正到来、重新计算(update_line)时,需把尚未计入的请假补建到明细行。
# 年假/补休有各自明细模型(vacation.leave.line / vacation.over.line),不在此处理。
for rec in self:
rep_month_start = rec.vacation_date
if not rep_month_start or not rec.employee_id:
continue
# 该月最后一天
if rep_month_start.month == 12:
rep_month_end = date(rep_month_start.year + 1, 1, 1) - timedelta(days=1)
else:
rep_month_end = date(rep_month_start.year, rep_month_start.month + 1, 1) - timedelta(days=1)
# 找覆盖本月、属于「其他类型」的请假明细(hr.leave.detail,batch_id 非空)
leaves = self.env['hr.leave'].search([
('employee_id', '=', rec.employee_id.id),
('holiday_status_id.name', 'in', OTHER_LEAVE_SYNC_TYPES),
('state', '=', 'validate'),
('request_date_from', '<=', fields.Date.to_string(rep_month_end)),
('request_date_to', '>=', fields.Date.to_string(rep_month_start)),
('batch_id', '!=', False),
])
for leave in leaves:
# 去重:同一报表 + 同一明细请假 已存在则跳过(避免与提交侧重复创建)
if self.env['vacation.other.line'].search([
('vacation_id', '=', rec.id),
('leave_id', '=', leave.id),
], limit=1):
continue
# 计算本月区间内的天数(与提交侧 _create_other_leave_line 的算法一致)
seg_start = max(fields.Date.from_string(leave.request_date_from), rep_month_start)
seg_end = min(fields.Date.from_string(leave.request_date_to), rep_month_end)
batch = leave.batch_id
days = self._compute_duration_day(leave.holiday_status_id, seg_start, seg_end)
if not days or days <= 0:
continue
workflow_id = False
if batch and batch.code:
workflow_id = self.env['soong.workflow.record'].search([('code', '=', batch.code)], limit=1).id
self.env['vacation.other.line'].create({
'leave_id': leave.id,
'vacation_id': rec.id,
'employee_id': rec.employee_id.id,
'workflow_record_id': workflow_id,
'update_type': 'reduce',
'lines': days,
'holiday_type': leave.holiday_status_id.id,
'update_date': fields.Date.today(),
'is_void': False,
'text': '请假审批',
})
def update_vacation(self):
records = self.env["yuthon.vacation.reports"].browse(
self._context.get('active_ids', self._context.get('active_id', self.ids))
@@ -1753,11 +1816,6 @@ class YuthonVacationReports(models.Model):
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([
@@ -1811,49 +1869,6 @@ 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 != 0: