diff --git a/excel_report_designer/models/report_excel.py b/excel_report_designer/models/report_excel.py
index 9c9832614..a19ff576a 100644
--- a/excel_report_designer/models/report_excel.py
+++ b/excel_report_designer/models/report_excel.py
@@ -366,6 +366,34 @@ class ReportExcel(models.Model):
'align': 'center',
'valign': 'vcenter'
})
+ # 定义备注格式
+ note_format = workbook.add_format({
+ 'font_size': 10,
+ 'border': 1,
+ 'align': 'left',
+ 'valign': 'top',
+ 'text_wrap': True
+ })
+ # 定义审批字段格式
+ approval_format = workbook.add_format({
+ 'font_size': 10,
+ 'border': 1,
+ 'align': 'center',
+ 'valign': 'vcenter'
+ })
+ # 定义靠右无边框显示的格式
+ right_align_format = workbook.add_format({
+ 'font_size': 10,
+ 'align': 'right',
+ 'valign': 'vcenter'
+ })
+ # 定义靠右有边框显示的格式
+ right_format = workbook.add_format({
+ 'font_size': 10,
+ 'align': 'right',
+ 'valign': 'vcenter',
+ 'border': 1,
+ })
header_format = workbook.add_format({'font_size': 11, 'bold': True, 'border': 1})
data_format = workbook.add_format({'font_size': 10, 'border': 1})
domain = self._get_payslip_domain(data)
@@ -375,6 +403,7 @@ class ReportExcel(models.Model):
for record in records:
group_id = record.salary_group_id.id if record.salary_group_id else None
grouped_records[group_id].append(record)
+
for group_id, group_records in grouped_records.items():
if group_id:
group_name = self.env['yuthon.salary.group'].browse(group_id).name
@@ -383,21 +412,107 @@ class ReportExcel(models.Model):
# 创建新的工作表
sheet = workbook.add_worksheet(group_name[:31])
# 写入公司和年月信息
- sheet.merge_range(0, 0, 0, len(data['field_label']) - 1, f'员工{data["current_year"]}年{data["current_month"]}工资表({company_name})', title_format)
+ headers = ['序号'] + data['field_label']
+ columns_data = [[] for _ in range(len(headers) - 1)]
+ float_totals = [0] * (len(headers) - 1)
+
+ current_year = int(data['current_year'])
+ current_month = int(data['current_month'])
+ valid_columns = []
+ for index, field_name in enumerate(data['fields_name']):
+ field = self.env[data['model_name']]._fields.get(field_name)
+ if not field:
+ continue
+ # 检查字段是否存在于 yuthon.payroll.common 和 yuthon.payroll.temporary 模型中
+ common_model = self.env['yuthon.payroll.common']
+ temp_model = self.env['yuthon.payroll.temporary']
+ common_records = common_model.search([('name', '=', field.string)])
+ temp_records = temp_model.search([('name', '=', field.string)])
+ if not common_records and not temp_records:
+ # 若两个模型中都没找到该字段,跳过日期判断,直接认为有效
+ valid_columns.append(index)
+ continue
+
+ valid = False
+ if field.type == 'float':
+ # 分别处理 common_records
+ for rec in common_records:
+ start_date = rec.start_date
+ end_date = rec.end_date
+ if not end_date:
+ end_date = datetime.date(current_year + 99, current_month, 1)
+ if start_date and end_date:
+ start_year_month = (start_date.year, start_date.month)
+ end_year_month = (end_date.year, end_date.month)
+ current_year_month = (current_year, current_month)
+ if start_year_month <= current_year_month <= end_year_month:
+ valid = True
+ break
+ # 如果 common_records 未找到有效记录,再处理 temp_records
+ if not valid:
+ for rec in temp_records:
+ start_date = rec.start_date
+ end_date = rec.end_date
+ if not end_date:
+ end_date = datetime.date(current_year + 99, current_month, 1)
+ if start_date and end_date:
+ start_year_month = (start_date.year, start_date.month)
+ end_year_month = (end_date.year, end_date.month)
+ current_year_month = (current_year, current_month)
+ if start_year_month <= current_year_month <= end_year_month:
+ valid = True
+ break
+ else:
+ valid = True
+
+ if valid:
+ valid_columns.append(index)
+
+ for record in group_records:
+ col_num = 1
+ for index, field_name in enumerate(data['fields_name']):
+ if index in valid_columns and index < len(columns_data):
+ value = record[field_name]
+ columns_data[index].append(value)
+ field = self.env[data['model_name']]._fields.get(field_name)
+ if field and field.type == 'float':
+ float_totals[index] += float(value) if value else 0
+ col_num += 1
+
+ # 记录实际显示的列索引
+ visible_cols = [0]
+ first_float_col_index = None
+ for index in range(len(headers) - 1):
+ if index in valid_columns and not all([x == 0 for x in columns_data[index]]):
+ visible_cols.append(index + 1)
+ if first_float_col_index is None and self.env[data['model_name']]._fields[
+ data['fields_name'][index]].type == 'float':
+ first_float_col_index = len(visible_cols) - 1
+ actual_header_length = len(visible_cols)
+
+ # 写入大表头,根据实际显示列数确定合并范围
+ company_year_month_text = f'员工{data["current_year"]}年{data["current_month"]}工资表({company_name})'
+ sheet.merge_range(0, 0, 0, actual_header_length - 1, company_year_month_text, title_format)
+
+ # 添加单位和日期
+ current_date_str = datetime.datetime.now().strftime('%Y年%m月%d日')
+ sheet.write(1, actual_header_length - 1, f"单位:元 日期:{current_date_str}", right_align_format)
+
# 写入表头
- headers = ['序号']+data['field_label']
col_num = 0
- for label in headers:
- sheet.write(1, col_num, label, header_format)
+ for index in visible_cols:
+ sheet.write(2, col_num, headers[index], header_format)
col_num += 1
- row_num = 2
+ # 写入数据
+ row_num = 3
serial_number = 1
for record in group_records:
col_num = 0
sheet.write(row_num, col_num, serial_number, serial_number_format)
col_num += 1
- for field_name in data['fields_name']:
+ for index in visible_cols[1:]:
+ field_name = data['fields_name'][index - 1]
field = self.env[data['model_name']]._fields.get(field_name)
value = record[field_name]
if isinstance(value, datetime.date):
@@ -421,6 +536,45 @@ class ReportExcel(models.Model):
col_num += 1
row_num += 1
serial_number += 1 # 序号递增
+
+ if first_float_col_index is not None:
+ # 合并从首列到首个float类型字段所在列的前一列的单元格
+ sheet.merge_range(row_num, 0, row_num, first_float_col_index - 1, "总计", serial_number_format)
+ # 调整起始列索引
+ start_col = first_float_col_index
+ for col_index, visible_col in enumerate(visible_cols[first_float_col_index:]):
+ field_name = data['fields_name'][visible_col - 1]
+ field = self.env[data['model_name']]._fields.get(field_name)
+ if field and field.type == 'float':
+ # 计算正确的列索引
+ target_col = start_col + col_index
+ sheet.write(row_num, target_col, float_totals[visible_col - 1], right_format)
+ else:
+ # 计算正确的列索引
+ target_col = start_col + col_index
+ sheet.write(row_num, target_col, "", right_format)
+
+ # 写入备注,根据实际显示列数确定合并范围
+ start_row = row_num + 1
+ end_row = start_row + 4
+ note_text = "备注"
+ sheet.merge_range(start_row, 0, end_row, actual_header_length - 1, note_text, note_format)
+
+ col_num = 0
+ # 记录表头实际占据的列数
+ header_column_count = len(visible_cols)
+ for index in visible_cols:
+ sheet.write(2, col_num, headers[index], header_format)
+ col_num += 1
+
+ # 添加审批字段行
+ approval_row = end_row + 1
+ approval_fields = ["领导审批:", "财务审核:", "部门审核:", "制表:"]
+ approval_text = " ".join(approval_fields)
+
+ # 合并单元格,使其宽度和表头一致
+ sheet.merge_range(approval_row, 0, approval_row, header_column_count - 1, approval_text, approval_format)
+
# 创建劳务信息工作表
labor_sheet = workbook.add_worksheet('劳务信息')
labor_fields = ['employee_id', 'labor_amount']
@@ -431,20 +585,39 @@ class ReportExcel(models.Model):
labor_sheet.merge_range(0, 0, 0, len(labor_headers) - 1, labor_title, title_format)
title_width = len(labor_title) + 2 # 适当增加一些宽度余量
labor_sheet.set_column(0, len(labor_headers) - 1, title_width)
+ # 添加单位和日期信息
+ current_time = datetime.datetime.now().strftime('%Y-%m-%d')
+ info_text = f"单位:元 日期:{current_time}"
+ labor_sheet.merge_range(1, 0, 1, len(labor_headers) - 1, info_text, right_align_format)
# 写入表头
col_num = 0
for label in labor_headers:
- labor_sheet.write(1, col_num, label, header_format)
+ labor_sheet.write(2, col_num, label, header_format)
col_num += 1
labor_records = self.env['yuthon.payroll.labor'].search([
('current_year', '=', data['current_year']),
('current_month', '=', data['current_month'])
])
- row_num = 2
+ row_num = 3
serial_number = 1
+ column_totals = [0] * len(labor_headers)
+ first_float_col_index = None
+
+ # 找出首个 float 类型字段所在列的索引
+ for col_index, field_name in enumerate(['serial_number'] + labor_fields):
+ field = self.env['yuthon.payroll.labor']._fields.get(field_name) if field_name in labor_fields else None
+ if field and field.type == 'float':
+ first_float_col_index = col_index
+ break
+
for labor_record in labor_records:
col_num = 0
labor_sheet.write(row_num, col_num, serial_number, serial_number_format)
+ if first_float_col_index is not None and col_num >= first_float_col_index:
+ try:
+ column_totals[col_num] += float(serial_number)
+ except (ValueError, TypeError):
+ pass
col_num += 1
for field_name in labor_fields:
field = self.env['yuthon.payroll.labor']._fields.get(field_name)
@@ -465,9 +638,28 @@ class ReportExcel(models.Model):
selection_options = dict(field.selection)
value = selection_options.get(value, value)
labor_sheet.write(row_num, col_num, value, data_format)
+ if first_float_col_index is not None and col_num >= first_float_col_index:
+ try:
+ column_totals[col_num] += float(value)
+ except (ValueError, TypeError):
+ pass
col_num += 1
row_num += 1
serial_number += 1
+ # 写入总计行
+ total_row = row_num
+ if first_float_col_index is not None:
+ labor_sheet.merge_range(total_row, 0, total_row, first_float_col_index - 1, '合计', serial_number_format)
+ for col_num in range(first_float_col_index, len(labor_headers)):
+ labor_sheet.write(total_row, col_num, column_totals[col_num], data_format)
+
+ end_row = total_row # 假设 end_row 是总计行
+ approval_row = end_row + 1
+ approval_fields = ["领导审批:", "财务审核:", "部门审核:", "制表:"]
+ approval_text = " ".join(approval_fields)
+
+ # 合并单元格,使其宽度和表头一致
+ labor_sheet.merge_range(approval_row, 0, approval_row, len(labor_headers) - 1, approval_text, approval_format)
# 创建退休人员费用工作表
retired_sheet = workbook.add_worksheet('退休人员费用')
@@ -479,20 +671,38 @@ class ReportExcel(models.Model):
retired_sheet.merge_range(0, 0, 0, len(labor_headers) - 1, retired_title, title_format)
title_width = len(retired_title) + 2 # 适当增加一些宽度余量
retired_sheet.set_column(0, len(retired_headers) - 1, title_width)
+ # 添加单位和日期信息
+ current_time = datetime.datetime.now().strftime('%Y-%m-%d')
+ info_text = f"单位:元 日期:{current_time}"
+ retired_sheet.merge_range(1, 0, 1, len(retired_headers) - 1, info_text, right_align_format)
# 写入表头
col_num = 0
for label in retired_headers:
- retired_sheet.write(1, col_num, label, header_format)
+ retired_sheet.write(2, col_num, label, header_format)
col_num += 1
retired_records = self.env['yuthon.payroll.retired'].search([
('current_year', '=', data['current_year']),
('current_month', '=', data['current_month'])
])
- row_num = 2
+ row_num = 3
serial_number = 1
+ column_totals = [0] * len(retired_headers)
+ first_float_col_index = None
+
+ for col_index, field_name in enumerate(['serial_number'] + retired_fields):
+ field = self.env['yuthon.payroll.retired']._fields.get(field_name) if field_name in retired_fields else None
+ if field and field.type == 'float':
+ first_float_col_index = col_index
+ break
+
for retired_record in retired_records:
col_num = 0
retired_sheet.write(row_num, col_num, serial_number, serial_number_format)
+ if first_float_col_index is not None and col_num >= first_float_col_index:
+ try:
+ column_totals[col_num] += float(serial_number)
+ except (ValueError, TypeError):
+ pass
col_num += 1
for field_name in retired_fields:
field = self.env['yuthon.payroll.retired']._fields.get(field_name)
@@ -513,9 +723,28 @@ class ReportExcel(models.Model):
selection_options = dict(field.selection)
value = selection_options.get(value, value)
retired_sheet.write(row_num, col_num, value, data_format)
+ if first_float_col_index is not None and col_num >= first_float_col_index:
+ try:
+ column_totals[col_num] += float(value)
+ except (ValueError, TypeError):
+ pass
col_num += 1
row_num += 1
serial_number += 1
+ # 写入总计行
+ total_row = row_num
+ if first_float_col_index is not None:
+ retired_sheet.merge_range(total_row, 0, total_row, first_float_col_index - 1, '合计', serial_number_format)
+ for col_num in range(first_float_col_index, len(retired_headers)):
+ retired_sheet.write(total_row, col_num, column_totals[col_num], data_format)
+
+ end_row = total_row # 假设 end_row 是总计行
+ approval_row = end_row + 1
+ approval_fields = ["领导审批:", "财务审核:", "部门审核:", "制表:"]
+ approval_text = " ".join(approval_fields)
+
+ # 合并单元格,使其宽度和表头一致
+ retired_sheet.merge_range(approval_row, 0, approval_row, len(labor_headers) - 1, approval_text, approval_format)
# 关闭工作簿
workbook.close()
@@ -548,7 +777,6 @@ class ReportExcel(models.Model):
chinese_month = month_mapping.get(current_month)
target_name = f"{current_year}年-{chinese_month}"
return [
- ('is_salary_push', '=', True),
- ('is_salary_release', '=', True),
+ ('is_push', '=', False),
('payslip_run_id.name', '=', target_name)
- ]
\ No newline at end of file
+ ]
diff --git a/yuthon_hr_employee/views/yuthon_hr_employee_views.xml b/yuthon_hr_employee/views/yuthon_hr_employee_views.xml
index e4f03fc7e..33fd3882b 100644
--- a/yuthon_hr_employee/views/yuthon_hr_employee_views.xml
+++ b/yuthon_hr_employee/views/yuthon_hr_employee_views.xml
@@ -390,6 +390,19 @@
+
+
+ hr.employee.inherit.del.form
+ hr.employee
+
+
+
+
+
+
+
+
+
hr.employee.inherit.search
hr.employee
@@ -408,7 +421,14 @@
code
action = model.action_hr_employee()
-
+
+ 通讯录
+ hr.employee
+ tree,kanban,form,search
+
+
tree,kanban,form,activity,graph,pivot,hierarchy
diff --git a/yuthon_salary/models/inherit_hr_payslip.py b/yuthon_salary/models/inherit_hr_payslip.py
index 0f9ff1e0f..bdf1e2025 100644
--- a/yuthon_salary/models/inherit_hr_payslip.py
+++ b/yuthon_salary/models/inherit_hr_payslip.py
@@ -8,6 +8,7 @@ class InheritHrPayslip(models.Model):
company_id = fields.Many2one('res.company', string="公司", default=lambda self: self.env.company)
employee_id = fields.Many2one('hr.employee', string="姓名")
+ date_of_entry = fields.Date(related='employee_id.entry_date', string="入职时间", store=True)
base_salary = fields.Float(string='基本工资', compute='_compute_salary', store=True)
bank_account_id = fields.Many2one(string='银行账号', related='employee_id.bank_account_id', store=True)
tax_payable = fields.Float(string='应补(退)税额', store=True)
diff --git a/yuthon_salary/models/yuthon_payroll_labor.py b/yuthon_salary/models/yuthon_payroll_labor.py
index d6aae88ed..c25e2bd9d 100644
--- a/yuthon_salary/models/yuthon_payroll_labor.py
+++ b/yuthon_salary/models/yuthon_payroll_labor.py
@@ -7,6 +7,7 @@ class YuthonPayrollLabor(models.Model):
employee_id = fields.Many2one('hr.employee', string='姓名')
current_year = fields.Integer(string='年份')
+ date_of_entry = fields.Date(related='employee_id.entry_date', string="入职时间", store=True)
current_month = fields.Selection([
('1', '1月份'),
('2', '2月份'),
diff --git a/yuthon_salary/views/inherit_hr_payslip_views.xml b/yuthon_salary/views/inherit_hr_payslip_views.xml
index 3f255cc4e..76a7a39aa 100644
--- a/yuthon_salary/views/inherit_hr_payslip_views.xml
+++ b/yuthon_salary/views/inherit_hr_payslip_views.xml
@@ -7,9 +7,14 @@
- custom_documents_button
+ custom_salary_validation_button
employee_id
+
+
+
1
@@ -32,6 +37,7 @@
1
+
@@ -85,12 +91,10 @@
hr.payslip.tree
hr.payslip
-
-
+
-
+
+
@@ -241,6 +245,7 @@
+
@@ -286,6 +291,7 @@
+
@@ -354,9 +360,6 @@
tree,form,search
[('is_salary_push', '=', True), ('is_salary_release', '=', False)]
{'search_default_group_by_employee': 1}
-
薪资发放
diff --git a/yuthon_salary/views/yuthon_payroll_labor_views.xml b/yuthon_salary/views/yuthon_payroll_labor_views.xml
index 46fcc3d75..5c922aeb4 100644
--- a/yuthon_salary/views/yuthon_payroll_labor_views.xml
+++ b/yuthon_salary/views/yuthon_payroll_labor_views.xml
@@ -6,6 +6,7 @@
+
diff --git a/yuthon_salary/wizard/salary_print_wizard.py b/yuthon_salary/wizard/salary_print_wizard.py
index 378bad5da..f5bd39b12 100644
--- a/yuthon_salary/wizard/salary_print_wizard.py
+++ b/yuthon_salary/wizard/salary_print_wizard.py
@@ -28,6 +28,7 @@ class SalaryPrintWizard(models.Model):
def print_fixed_report(self):
fields_list = [
'employee_id',
+ 'date_of_entry',
'company_id',
'struct_id',
'bank_account_id',
@@ -66,7 +67,6 @@ class SalaryPrintWizard(models.Model):
'continuing_education',
'infant_care',
'meal_misunderstanding_fee',
- 'salary_state'
]
data = {
'report_name': '薪资',
@@ -75,6 +75,7 @@ class SalaryPrintWizard(models.Model):
'current_year': self.current_year,
'fields_name': [
'employee_id',
+ 'date_of_entry',
'company_id',
'struct_id',
'bank_account_id',
@@ -113,10 +114,10 @@ class SalaryPrintWizard(models.Model):
'continuing_education',
'infant_care',
'meal_misunderstanding_fee',
- 'salary_state'
],
'field_label': [
'姓名',
+ '入职时间',
'公司',
'职级',
'银行账号',
@@ -155,7 +156,6 @@ class SalaryPrintWizard(models.Model):
'累计继续教育',
'累计3岁以下婴幼儿照护',
'误餐费',
- '状态'
],
'field_order': str([i for i in range(1, len(fields_list) + 1)])
}
diff --git a/yuthon_work_brand/views/hr_menus.xml b/yuthon_work_brand/views/hr_menus.xml
index 29dfd0716..bbe3f0226 100644
--- a/yuthon_work_brand/views/hr_menus.xml
+++ b/yuthon_work_brand/views/hr_menus.xml
@@ -114,6 +114,11 @@
parent="human_resources_menu_root_board"
action="hr.open_view_employee_list_my"
sequence="1"/>
+