Files
gzth/yuthon_hr_attendance/wizard/export_date_wizard.py
T
2026-08-20 19:17:05 +08:00

473 lines
20 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
from odoo import fields, models
import json
from odoo.tools import date_utils
from datetime import datetime, timedelta
from odoo.exceptions import UserError
class ExportDateWizard(models.TransientModel):
_name = 'export.date.wizard'
_description = '导出日期选择向导'
year = fields.Integer(string='结转年份', required=True, default=lambda self: datetime.now().year)
month = fields.Selection([
('1', '1月'), ('2', '2月'), ('3', '3月'), ('4', '4月'),
('5', '5月'), ('6', '6月'), ('7', '7月'), ('8', '8月'),
('9', '9月'), ('10', '10月'), ('11', '11月'), ('12', '12月'),
], string='结转月份', required=True, default=lambda self: str(datetime.now().month))
export_type = fields.Char(string='导出类型')
model_name = fields.Char(string='模型名称')
active_ids = fields.Char(string='活动记录ID')
def action_confirm_export(self):
"""确认导出"""
self.ensure_one()
start_date = datetime(int(self.year), int(self.month), 1)
if int(self.month) == 12:
end_date = datetime(int(self.year) + 1, 1, 1)
else:
end_date = datetime(int(self.year), int(self.month) + 1, 1)
if self.export_type == 'leave':
return self._export_leave(start_date, end_date)
elif self.export_type == 'leave_filing':
return self._export_leave_filing(start_date, end_date)
elif self.export_type == 'overtime':
return self._export_overtime(start_date, end_date)
elif self.export_type == 'overtime_detail':
return self._export_overtime_detail(start_date, end_date)
elif self.export_type == 'overtime_active':
return self._export_overtime_active(start_date, end_date)
elif self.export_type == 'meal':
return self._export_meal(start_date, end_date)
elif self.export_type == 'meal_active':
return self._export_meal_active(start_date, end_date)
elif self.export_type == 'overtime_carryover':
return self._export_overtime_carryover(start_date, end_date)
else:
raise UserError('未知的导出类型')
def _export_leave(self, start_date, end_date):
"""导出请假情况"""
active_ids = json.loads(self.active_ids) if self.active_ids else []
domain = [('date_from', '>=', start_date), ('date_from', '<', end_date), ('state', '!=', 'refuse')]
if active_ids:
domain = [('id', 'in', active_ids)] + domain
filtered_records = self.env['hr.leave'].search(domain)
if not filtered_records:
raise UserError(f'在 {self.year} 年 {self.month} 月没有找到符合条件的请假记录')
filtered_ids = filtered_records.ids
fields_name = ['employee_id', 'department_id', 'holiday_status_id',
'date_from', 'date_to', 'length_leave', 'application_reason', 'mobile_phone']
field_label = ['发起人', '部门', '休假类型', '开始时间', '结束时间',
'请假时长', '申请原因', '手机号']
data = {
'report_name': '请假情况报表',
'model_name': 'hr.leave',
'fields_name': fields_name,
'field_label': field_label,
'active_ids': filtered_ids,
}
return {
'type': 'ir.actions.report',
'data': {
'model': 'report.excel',
'options': json.dumps(data, default=date_utils.json_default),
'output_format': 'xlsx',
'report_name': '请假情况报表',
},
'report_type': 'xlsx',
}
def _export_leave_filing(self, start_date, end_date):
"""导出归档请假情况(is_filing=True)"""
active_ids = json.loads(self.active_ids) if self.active_ids else []
domain = [
('date_from', '>=', start_date),
('date_from', '<', end_date),
('is_filing', '=', True)
]
if active_ids:
domain = [('id', 'in', active_ids)] + domain
filtered_records = self.env['hr.leave'].search(domain)
if not filtered_records:
raise UserError(f'在 {self.year} 年 {self.month} 月没有找到符合条件的归档请假记录')
filtered_ids = filtered_records.ids
fields_name = ['employee_id', 'department_id', 'holiday_status_id',
'date_from', 'date_to', 'length_leave', 'application_reason', 'mobile_phone']
field_label = ['发起人', '部门', '休假类型', '开始时间', '结束时间',
'请假时长', '申请原因', '手机号']
data = {
'report_name': '归档请假情况报表',
'model_name': 'hr.leave',
'fields_name': fields_name,
'field_label': field_label,
'active_ids': filtered_ids,
}
return {
'type': 'ir.actions.report',
'data': {
'model': 'report.excel',
'options': json.dumps(data, default=date_utils.json_default),
'output_format': 'xlsx',
'report_name': '归档请假情况报表',
},
'report_type': 'xlsx',
}
def _export_overtime(self, start_date, end_date):
"""导出加班明细"""
active_ids = json.loads(self.active_ids) if self.active_ids else []
domain = [('start_time', '>=', start_date), ('start_time', '<', end_date),
'|', ('workflow_record_id', '!=', False), ('is_initial_number', '=', True),
('update_type', '=', 'add'), ('is_filing', '=', False), ('is_visible', '=', False)]
if active_ids:
domain = [('id', 'in', active_ids)] + domain
filtered_records = self.env['vacation.over.line'].search(domain)
if not filtered_records:
raise UserError(f'在 {self.year} 年 {self.month} 月没有找到符合条件的加班记录')
filtered_ids = filtered_records.ids
fields_name = ['employee_id', 'department_id', 'start_time', 'carry_forward_date',
'duration', 'carry_result']
field_label = ['员工', '部门', '加班时间', '结转日期', '结转时长', '结转结果']
data = {
'report_name': '加班明细报表',
'model_name': 'vacation.over.line',
'fields_name': fields_name,
'field_label': field_label,
'active_ids': filtered_ids,
}
return {
'type': 'ir.actions.report',
'data': {
'model': 'report.excel',
'options': json.dumps(data, default=date_utils.json_default),
'output_format': 'xlsx',
'report_name': '加班明细报表',
},
'report_type': 'xlsx',
}
def _export_overtime_detail(self, start_date, end_date):
"""导出加班详情 - 对应 vacation.over.line.overtime.tree 视图字段"""
active_ids = json.loads(self.active_ids) if self.active_ids else []
carry_forward_state_map = {
'pending': '待结转',
'completed': '已结转',
'partial': '部分结转',
}
if active_ids:
records = self.env['vacation.over.line'].browse(active_ids)
else:
domain = [('start_time', '>=', start_date), ('start_time', '<', end_date)]
records = self.env['vacation.over.line'].search(domain)
if not records:
raise UserError(f'在 {self.year} 年 {self.month} 月没有找到符合条件的加班记录')
export_data = []
for rec in records:
export_data.append({
'overtime_name': rec.overtime_name or '',
'employee_id': rec.employee_id.name if rec.employee_id else '',
'department_id': rec.department_id.name if rec.department_id else '',
'start_time': (rec.start_time + timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S') if rec.start_time else '',
'end_time': (rec.end_time + timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S') if rec.end_time else '',
'duration': rec.duration,
'carry_forward_quantity': rec.carry_forward_quantity,
'carry_forward_date': rec.carry_forward_date,
'carry_forward_state': carry_forward_state_map.get(rec.carry_forward_state, rec.carry_forward_state or ''),
'remaining_quantity': rec.remaining_quantity,
'validity': rec.validity or '',
})
fields_name = ['overtime_name', 'employee_id', 'department_id', 'start_time', 'end_time',
'duration', 'carry_forward_quantity', 'carry_forward_date',
'carry_forward_state', 'remaining_quantity', 'validity']
field_label = ['标题', '员工', '部门', '开始时间', '结束时间',
'加班时长(小时)', '结转时长(小时)', '结转日期',
'结转状态', '剩余数', '有效期']
data = {
'report_name': '加班详情报表',
'model_name': 'vacation.over.line',
'fields_name': fields_name,
'field_label': field_label,
'export_data': export_data,
'date_field': None,
}
return {
'type': 'ir.actions.report',
'data': {
'model': 'report.excel',
'options': json.dumps(data, default=date_utils.json_default),
'output_format': 'xlsx',
'report_name': '加班详情报表',
},
'report_type': 'xlsx',
}
def _export_overtime_active(self, start_date, end_date):
"""导出加班归档明细
规则:弹窗填N年M月 → 查 select_year/select_month = N年(M-1)月 的 vacation.overtime.active 记录(每人一行),
对每条归档记录复用 open_record 的 domain + 累减逻辑,汇总为每人一行后导出。
"""
import datetime as dt
year = int(self.year)
month = int(self.month)
# 往前推一个月
if month == 1:
prev_year, prev_month = year - 1, 12
else:
prev_year, prev_month = year, month - 1
carry_forward_state_map = {
'pending': '待结转',
'completed': '已结转',
'partial': '部分结转',
}
active_records = self.env['vacation.overtime.active'].search([
('select_year', '=', str(prev_year)),
('select_month', '=', str(prev_month)),
('select_revoke', '=', False)
])
if not active_records:
raise UserError(f'在 {prev_year} 年 {prev_month} 月没有找到加班归档记录')
export_data = []
for active in active_records:
# 复用 open_record 的 domain
final_domain = [
('over_line_id.vacation_id.employee_id', '=', active.employee_id.id),
('is_void', '=', False),
('carryover_type', '=', 'fee'),
('carry_forward_date', '=', active.carry_forward_date),
]
carryover_records = self.env['overtime.carryover'].search(final_domain, order='start_time asc')
if not carryover_records:
continue
# 复用 open_record 的累减逻辑,实时计算每条的 last_month/this_month
current_remaining = active.vacation_sum
for carry in carryover_records:
last_month_val = current_remaining
this_month_val = round(current_remaining - carry.carry_forward_quantity, 3)
current_remaining = this_month_val
over_line = carry.over_line_id
export_data.append({
'employee_id': active.employee_id.name if active.employee_id else '',
'department_id': carry.department_id.name if carry.department_id else '',
'start_time': (over_line.start_time + timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S') if over_line and over_line.start_time else '',
'end_time': (over_line.end_time + timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S') if over_line and over_line.end_time else '',
'carry_forward_date': carry.carry_forward_date,
'carry_forward_quantity1': carry.carry_forward_quantity,
'carry_forward_state': carry_forward_state_map.get(carry.carry_forward_state, carry.carry_forward_state or ''),
})
if not export_data:
raise UserError(f'在 {prev_year} 年 {prev_month} 月没有找到符合条件的加班归档记录')
fields_name = ['employee_id', 'department_id', 'start_time', 'end_time',
'carry_forward_date', 'carry_forward_quantity1', 'carry_forward_state']
field_label = ['姓名', '部门', '加班开始时间', '加班结束时间',
'结转日期', '结转时长(小时)', '结转状态']
data = {
'report_name': '加班归档明细报表',
'model_name': 'overtime.carryover',
'fields_name': fields_name,
'field_label': field_label,
'export_data': export_data,
'date_field': None,
}
return {
'type': 'ir.actions.report',
'data': {
'model': 'report.excel',
'options': json.dumps(data, default=date_utils.json_default),
'output_format': 'xlsx',
'report_name': '加班归档明细报表',
},
'report_type': 'xlsx',
}
def _export_overtime_carryover(self, start_date, end_date):
"""导出加班结转明细(overtime.carryover.tree1 视图数据)"""
active_ids = json.loads(self.active_ids) if self.active_ids else []
if active_ids:
records = self.env['overtime.carryover'].browse(active_ids)
else:
records = self.env['overtime.carryover'].search([
('carry_forward_date', '>=', start_date.date()),
('carry_forward_date', '<', end_date.date()),
])
if not records:
raise UserError(f'在 {self.year} 年 {self.month} 月没有找到符合条件的加班结转记录')
export_data = []
for record in records:
over_line = record.over_line_id
export_data.append({
'employee_id': record.employee_id.name if record.employee_id else '',
'department_id': record.department_id.name if record.department_id else '',
'start_time': (over_line.start_time + timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S') if over_line and over_line.start_time else '',
'end_time': (over_line.end_time + timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S') if over_line and over_line.end_time else '',
'carry_forward_date': record.carry_forward_date,
'last_month': record.last_month,
'carry_forward_quantity1': record.carry_forward_quantity1,
'this_month': record.this_month,
'carry_result': '成功',
})
fields_name = ['employee_id', 'department_id', 'start_time', 'end_time',
'carry_forward_date', 'last_month', 'carry_forward_quantity1', 'this_month', 'carry_result']
field_label = ['姓名', '部门', '加班开始时间', '加班结束时间',
'结转日期', '上期剩余', '结转时长', '本期结余', '结转结果']
data = {
'report_name': '加班结转明细报表',
'model_name': 'overtime.carryover',
'fields_name': fields_name,
'field_label': field_label,
'export_data': export_data,
'date_field': None,
}
return {
'type': 'ir.actions.report',
'data': {
'model': 'report.excel',
'options': json.dumps(data, default=date_utils.json_default),
'output_format': 'xlsx',
'report_name': '加班结转明细报表',
},
'report_type': 'xlsx',
}
def _export_meal(self, start_date, end_date):
"""导出误餐明细"""
active_ids = json.loads(self.active_ids) if self.active_ids else []
domain = [('carry_forward_date', '>=', start_date), ('carry_forward_date', '<', end_date)]
if active_ids:
domain = [('id', 'in', active_ids)] + domain
filtered_records = self.env['vacation.meal.line'].search(domain)
if not filtered_records:
raise UserError(f'在 {self.year} 年 {self.month} 月没有找到符合条件的误餐记录')
filtered_ids = filtered_records.ids
fields_name = ['employee_id', 'department_id', 'workflow_id', 'start_time',
'end_time', 'duration', 'reasons', 'meal']
field_label = ['发起人', '部门', '审批类型', '加班开始时间', '加班结束时间',
'加班时长(小时)', '事由', '加班餐费']
data = {
'report_name': '误餐明细报表',
'model_name': 'vacation.meal.line',
'fields_name': fields_name,
'field_label': field_label,
'active_ids': filtered_ids,
}
return {
'type': 'ir.actions.report',
'data': {
'model': 'report.excel',
'options': json.dumps(data, default=date_utils.json_default),
'output_format': 'xlsx',
'report_name': '误餐明细报表',
},
'report_type': 'xlsx',
}
def _export_meal_active(self, start_date, end_date):
"""导出误餐归档明细"""
active_ids = json.loads(self.active_ids) if self.active_ids else []
domain = [('carry_forward_date', '>=', start_date.date()), ('carry_forward_date', '<', end_date.date())]
if active_ids:
domain = [('id', 'in', active_ids)] + domain
filtered_records = self.env['vacation.meal.active'].search(domain)
if not filtered_records:
raise UserError(f'在 {self.year} 年 {self.month} 月没有找到符合条件的误餐归档记录')
export_data = []
for record in filtered_records:
export_data.append({
'employee_id': record.employee_id.name if record.employee_id else '',
'department_id': record.employee_id.department_id.name if record.employee_id and record.employee_id.department_id else '',
'workflow_id': record.workflow_id.name if record.workflow_id else '',
'start_time': (record.start_time + timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S') if record.start_time else '',
'end_time': (record.end_time + timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S') if record.end_time else '',
'duration': record.duration,
'update_lines': record.update_lines,
'reasons': record.reasons or '',
'meal': record.meal,
})
fields_name = ['employee_id', 'department_id', 'workflow_id', 'start_time',
'end_time', 'duration', 'update_lines', 'reasons', 'meal']
field_label = ['发起人', '部门', '审批类型', '开始时间', '结束时间',
'时长', '额度', '事由', '加班餐费']
data = {
'report_name': '误餐归档明细报表',
'model_name': 'vacation.meal.active',
'fields_name': fields_name,
'field_label': field_label,
'export_data': export_data,
}
return {
'type': 'ir.actions.report',
'data': {
'model': 'report.excel',
'options': json.dumps(data, default=date_utils.json_default),
'output_format': 'xlsx',
'report_name': '误餐归档明细报表',
},
'report_type': 'xlsx',
}