!4384 添加功能

Merge pull request !4384 from 李鹏宇/dev_zhou
This commit is contained in:
李鹏宇
2025-08-07 09:13:30 +00:00
committed by Gitee
4 changed files with 166 additions and 123 deletions
+49 -42
View File
@@ -509,8 +509,6 @@ class HolidaysRequestBatch(models.Model):
# 提交
def action_submit(self):
"""提交请假申请,区分年假和其他假期处理"""
_logger.info(f"开始处理请假申请:{self.code},申请人:{self.users_id.employee_ids.name}")
self._process_specific_leaves('年假', is_annual_leave=True)
other_leave_types = [
'产假', '事假', '法定假', '调休', '补休', '值班调休',
@@ -537,45 +535,31 @@ class HolidaysRequestBatch(models.Model):
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(period['start'], leave, days, period)
else:
self._create_other_leave_line(period['start'], leave, days, period, leave_type_name)
if leave_type_name == '补休':
# 计算小时数(天数 * 8)
hours = self._compute_duration_day(leave['type_id'], period['start'], period['end']) * 8
if hours > 0:
self._create_overtime_leave_line(period_start=period['start'], leave_data=leave, hours=hours, period=period, leave_type_name=leave_type_name)
else:
days = self._compute_duration_day(leave['type_id'], period['start'], period['end'])
if days > 0:
if is_annual_leave:
# 年假以小时为单位(天数 * 8)
self._create_annual_leave_line(period_start=period['start'], leave_data=leave, hours=days * 8, period=period)
else:
self._create_other_leave_line(period_start=period['start'], leave_data=leave, days=days, period=period, leave_type_name=leave_type_name)
# 处理小时假
for leave in hourly_leaves:
leave_date = leave['date']
days = leave['days']
if days > 0:
hours = leave['days'] * 8
if hours > 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_date, leave_data=leave, hours=hours, period={'start': leave_date, 'end': leave_date})
elif leave_type_name == '补休':
self._create_overtime_leave_line(period_start=leave_date, leave_data=leave, hours=hours, period={'start': leave_date, 'end': leave_date}, leave_type_name=leave_type_name)
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记录"""
# 查找关联的假期额度记录
report_month = date(period_start.year, period_start.month, 1)
vacation_report = self.env['yuthon.vacation.reports'].search([
('employee_id', '=', self.users_id.employee_ids.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.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_ids.id,
'workflow_record_id': leave_data['workflow_id'],
'update_date': fields.Date.today(),
'update_type': 'reduce',
'lines': days,
'text': f"请假审批"
})
# 其他类型小时假,使用天数
self._create_other_leave_line(period_start=leave_date, leave_data=leave,days=leave['days'], period={'start': leave_date, 'end': leave_date}, leave_type_name=leave_type_name)
def _get_day_leaves(self, leave_type_name):
workflow_id = self.env['soong.workflow.record'].search([('code', '=', self.code)], limit=1).id
@@ -601,7 +585,7 @@ class HolidaysRequestBatch(models.Model):
'date': fields.Date.from_string(line.request_date_from),
'type_id': line.holiday_status_id,
'workflow_id': workflow_id,
'days': hours / 8 # 转换为天数
'days': hours / 8
})
return hourly_records
@@ -628,8 +612,33 @@ class HolidaysRequestBatch(models.Model):
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):
"""更新年假记录"""
def _create_overtime_leave_line(self, period_start, leave_data, hours, period, leave_type_name):
"""为补休类型创建加班明细行(vacation.over.line),类型为减少,值赋给workday"""
report_month = date(period_start.year, period_start.month, 1)
vacation_report = self.env['yuthon.vacation.reports'].search([
('employee_id', '=', self.users_id.employee_ids.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.over.line'].create({
'vacation_id': vacation_report.id if vacation_report else False,
'employee_id': self.users_id.employee_ids.id,
'workflow_record_id': leave_data['workflow_id'],
'update_type': 'reduce',
'workday': hours,
'legal_day': 0,
'public_holidays': 0,
'meal_number': 0,
'update_date': fields.Date.today(),
'is_void': False,
'text': f"请假审批"
})
def _create_annual_leave_line(self, period_start, leave_data, hours, period):
"""更新年假记录,使用小时作为单位"""
report_month = date(period_start.year, period_start.month, 1)
vacation_report = self.env['yuthon.vacation.reports'].search([
('employee_id', '=', self.users_id.employee_ids.id),
@@ -639,20 +648,18 @@ class HolidaysRequestBatch(models.Model):
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_ids.id,
'workflow_record_id': leave_data['workflow_id'],
'update_type': 'reduce',
'update_date': fields.Date.today(),
'update_lines': days,
'update_lines': hours,
'is_void': False,
'allocation_type': 'vacation',
'text': f"请假审批"
})
def _compute_duration_day(self, holiday_status_id, start_date, end_date):
"""
计算请假时长
@@ -100,38 +100,39 @@ class HrLeaveAllocation(models.Model):
for leave in leave_ids:
leave.employee_id.write({'quota_issued': leave.number_of_hours_display})
@api.model
def create(self, vals):
allocation = super(HrLeaveAllocation, self).create(vals)
employee = allocation.employee_id
hours = allocation.number_of_hours_display
if allocation.holiday_status_id.name == '年假' and allocation.state == 'validate':
employee.write({'quota_issued': employee.quota_issued + hours})
reports_id = self.env['yuthon.vacation.reports'].search([('employee_id', '=', employee.id)], limit=1)
# 创建假期明细记录
self.env['vacation.leave.line'].create({
'vacation_id': reports_id.id,
'update_type': 'add',
'update_date': fields.Datetime.now(),
'update_lines': hours,
'allocation_type': 'allocation',
'text': allocation.name
})
elif allocation.holiday_status_id.name == '补休':
reports_id = self.env['yuthon.vacation.reports'].search([
('employee_id', '=', employee.id)
], limit=1)
self.env['vacation.over.line'].create({
'vacation_id': reports_id.id,
'update_type': 'add',
'update_date': fields.Datetime.now(),
'workday': hours,
'legal_day': 0,
'public_holidays': 0,
'meal_number': 0,
'text': allocation.name
})
return allocation
# @api.model
# def create(self, vals):
# allocation = super(HrLeaveAllocation, self).create(vals)
# employee = allocation.employee_id
# hours = allocation.number_of_hours_display
# date_from = allocation.date_from.replace(day=1)
# if allocation.holiday_status_id.name == '年假' and allocation.state == 'validate':
# employee.write({'quota_issued': employee.quota_issued + hours})
# reports_id = self.env['yuthon.vacation.reports'].search([('employee_id', '=', employee.id), ('vacation_date', '=', date_from)], limit=1)
# # 创建假期明细记录
# self.env['vacation.leave.line'].create({
# 'vacation_id': reports_id.id,
# 'update_type': 'add',
# 'update_date': fields.Datetime.now(),
# 'update_lines': hours,
# 'allocation_type': 'allocation',
# 'text': allocation.name
# })
# elif allocation.holiday_status_id.name == '补休':
# reports_id = self.env['yuthon.vacation.reports'].search([
# ('employee_id', '=', employee.id), ('vacation_date', '=', date_from)
# ], limit=1)
# self.env['vacation.over.line'].create({
# 'vacation_id': reports_id.id,
# 'update_type': 'add',
# 'update_date': fields.Datetime.now(),
# 'workday': hours,
# 'legal_day': 0,
# 'public_holidays': 0,
# 'meal_number': 0,
# 'text': allocation.name
# })
# return allocation
def unlink(self):
"""删除记录时同步删除对应的假期明细行"""
@@ -156,7 +156,6 @@ class YuthonVacationReports(models.Model):
'调休': 'compensatory_leave',
'事假': 'leave_of_absence',
'法定假': 'statutory_leave',
'补休': 'cop_leave',
'值班调休': 'duty_off_leave',
'婚假': 'marriage_leave',
'产假': 'maternity_leave',
@@ -284,6 +283,9 @@ class YuthonVacationReports(models.Model):
def monthly_report(self):
today = fields.Date.today()
employees = self.env['hr.employee'].search([])
current_month_first = today.replace(day=1)
last_month_last = current_month_first - timedelta(days=1)
last_month_first = last_month_last.replace(day=1)
for employee in employees:
resource_user_ids = employee.resource_calendar_id.resource_user_ids.ids
is_resource_user = True if employee.id in resource_user_ids else False
@@ -292,10 +294,23 @@ class YuthonVacationReports(models.Model):
('vacation_date', '=', today)
], limit=1)
if not existing_record and not is_resource_user:
last_month_record = self.search([
('employee_id', '=', employee.id),
('vacation_date', '>=', fields.Date.to_string(last_month_first)),
('vacation_date', '<=', fields.Date.to_string(last_month_last))
], limit=1)
inherit_vals = {}
if last_month_record:
inherit_vals = {
'leave': last_month_record.leave,
'working_overtime': last_month_record.working_overtime,
'medical_fee': last_month_record.medical_fee,
}
self.create({
'employee_id': employee.id,
'vacation_date': today,
# 明细行和计算字段留空,由后续逻辑处理
**inherit_vals
})
def disposable_report(self):
@@ -403,15 +418,17 @@ class YuthonVacationReports(models.Model):
)
def _compute_working_overtime(self):
for record in self:
overtime_hours = 0.0
total_add = 0.0
total_reduce = 0.0
for line in record.overtime_ids:
if not line.is_void:
line_total = (line.workday or 0) + (line.legal_day or 0) + (line.public_holidays or 0)
if line.update_type == 'add':
overtime_hours += line_total
total_add += line_total
elif line.update_type == 'reduce':
overtime_hours -= line_total
record.working_overtime = overtime_hours / 8
total_reduce += line_total
record.working_overtime = total_add / 8
record.cop_leave = total_reduce / 8
@api.depends('meal_fee_ids.update_lines', 'meal_fee_ids.update_type', 'meal_fee_ids.is_void')
def _compute_meal_fee(self):
@@ -426,46 +443,71 @@ class YuthonVacationReports(models.Model):
record.meal_fee = meal_total
def update_vacation(self):
employees = self.env['hr.employee'].search([
('is_salary', '=', True),
('contract_id.state', '!=', 'cancel'),
('contract_id', '!=', False),
])
"""
从hr.leave.allocation中汇总年假和补休数据,更新到8月份的假期报表
"""
# 定义目标月份:8月1号(当年)
current_year = fields.Date.today().year
target_month = date(current_year, 8, 4)
target_month_str = fields.Date.to_string(target_month)
# 获取所有员工
employees = self.env['hr.employee'].search([])
for employee in employees:
vacation_id = self.env['yuthon.vacation.reports'].search([
# 1. 处理年假分配
annual_allocations = self.env['hr.leave.allocation'].search([
('employee_id', '=', employee.id),
('holiday_status_id.name', '=', '年假'),
('state', '=', 'validate')
])
if not vacation_id:
self.env['yuthon.vacation.reports'].create({
'employee_id': employee.id,
'leave': employee.remainder_year,
'working_overtime': employee.overtime_this_month,
'meal_fee': employee.meal_number,
})
else:
vacation_id.write({
'leave': employee.remainder_year,
'working_overtime': employee.overtime_this_month,
'meal_fee': employee.meal_number,
})
def update_log(self):
vacation_ids = self.env["yuthon.vacation.reports"].browse(
self._context.get('active_ids', self._context.get('active_id')))
for vacation_id in vacation_ids:
vacation_id.leave_ids.unlink()
vacation_id.overtime_ids.unlink()
vacation_id.meal_fee_ids.unlink()
# 累加年假总小时数
total_annual_hours = sum(alloc.number_of_hours_display for alloc in annual_allocations)
# 2. 处理补休分配
comp_allocations = self.env['hr.leave.allocation'].search([
('employee_id', '=', employee.id),
('holiday_status_id.name', '=', '补休'),
('state', '=', 'validate') # 只处理已验证的分配
])
# 累加补休总小时数
total_comp_hours = sum(alloc.number_of_hours_display for alloc in comp_allocations)
# 3. 查找或创建8月份的报表记录
vacation_report = self.search([
('employee_id', '=', employee.id),
('vacation_date', '=', target_month_str)
], limit=1)
self._update_leave_lines(vacation_report, annual_allocations, total_annual_hours)
self._update_over_lines(vacation_report, comp_allocations, total_comp_hours)
def _update_leave_lines(self, report, allocations, number_of_hours_display):
for alloc in allocations:
self.env['vacation.leave.line'].create({
'vacation_id': report.id,
'employee_id': report.employee_id.id,
'update_type': 'add',
'update_date': fields.Date.today(),
'update_lines': number_of_hours_display,
'is_void': False,
'allocation_type': 'allocation',
'text': f"年假分配"
})
def _update_over_lines(self, report, allocations, number_of_hours_display):
"""更新补休明细行"""
for alloc in allocations:
self.env['vacation.over.line'].create({
'vacation_id': report.id,
'employee_id': report.employee_id.id,
'update_type': 'add',
'update_date': fields.Date.today(),
'workday': number_of_hours_display,
'legal_day': 0,
'public_holidays': 0,
'meal_number': 0,
'text': f"补休分配"
})
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
'params': {
'type': 'success',
'message': '删除日志成功',
'sticky': False,
}
}
def log(self):
return {
@@ -410,13 +410,6 @@
<field name="binding_model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>
<field name="state">code</field>
<field name="code">action = model.update_vacation()</field>
</record>
<record id="all_update_log" model="ir.actions.server">
<field name="name">初始化日志</field>
<field name="model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>
<field name="binding_model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>
<field name="state">code</field>
<field name="code">action = model.update_log()</field>
</record>
<record id="all_data_attendance_put_month" model="ir.actions.server">
<field name="name">批量发送</field>
@@ -426,7 +419,7 @@
<field name="code">action = model.update_log()</field>
</record>
<record id="all_vacation_delete" model="ir.actions.server">
<field name="name">清零</field>
<field name="name">初始化日志</field>
<field name="model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>
<field name="binding_model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>
<field name="state">code</field>