修复求和数据统计的问题

This commit is contained in:
2026-07-23 14:57:29 +08:00
parent 03098a553e
commit fa884ae782
11 changed files with 550 additions and 184 deletions

View File

@@ -340,10 +340,14 @@ def generate_daily_report(config_id, start_time=None, end_time=None):
report_date = start_time.strftime('%Y-%m-%d')
delete_old_history(config_id, report_date, config['split_type'], config['split_value'])
# 构建查询SQL - 过滤掉虚拟字段(时段电量等)
# 构建查询SQL - 过滤掉虚拟字段(时段电量、自定义服务费、实收金额等)
# 虚拟字段不是数据库表中的实际字段,需要动态计算
TIME_PERIOD_FIELDS = {'sharp_electricity', 'peak_electricity', 'flat_electricity', 'valley_electricity'}
db_fields = [f for f in selected_fields if f not in TIME_PERIOD_FIELDS]
VIRTUAL_FIELDS = {'sharp_electricity', 'peak_electricity', 'flat_electricity', 'valley_electricity', 'custom_service_fee', 'total_amount'}
db_fields = [f for f in selected_fields if f not in VIRTUAL_FIELDS]
# 如果选择了实收金额字段,需要确保查询 charge_elecfee_amount电费金额
if 'total_amount' in selected_fields and 'charge_elecfee_amount' not in db_fields:
db_fields.append('charge_elecfee_amount')
# 确保至少有 order_no 字段用于关联分时数据
if 'order_no' not in db_fields:
@@ -501,7 +505,10 @@ def generate_daily_report(config_id, start_time=None, end_time=None):
split_type=config.get('split_type'),
split_value=config.get('split_value'),
custom_service_fee_price=config.get('custom_service_fee_price'),
custom_service_fee_name=config.get('custom_service_fee_name')
custom_service_fee_name=config.get('custom_service_fee_name'),
show_custom_service_fee=config.get('show_custom_service_fee', 0) == 1,
show_total_amount=config.get('show_total_amount', 0) == 1,
total_amount_name=config.get('total_amount_name')
)
log_info(f"[日报生成] Excel文件已生成: {file_path}", 'report')
@@ -591,7 +598,8 @@ def generate_excel(orders, selected_fields, sum_fields, sum_results,
id_name_maps=None, field_custom_names=None, has_supplement=False,
show_monthly_total=False, config_id=None, report_date=None, sort_order=None,
split_type=None, split_value=None,
custom_service_fee_price=None, custom_service_fee_name=None):
custom_service_fee_price=None, custom_service_fee_name=None,
show_custom_service_fee=False, show_total_amount=False, total_amount_name=None):
"""
生成Excel文件
@@ -711,35 +719,36 @@ def generate_excel(orders, selected_fields, sum_fields, sum_results,
cell.alignment = header_alignment
cell.border = thin_border
has_custom_service_fee = custom_service_fee_price is not None and custom_service_fee_price != ''
for col_idx, field in enumerate(selected_fields, 2):
cell = ws.cell(row=header_row, column=col_idx)
if field in field_custom_names and field_custom_names[field]:
if field == 'custom_service_fee':
if custom_service_fee_name and str(custom_service_fee_name).strip():
display_name = str(custom_service_fee_name).strip()
elif has_custom_service_fee:
display_name = f'自定义服务费({custom_service_fee_price}元/kWh)'
else:
display_name = '自定义服务费'
elif field == 'total_amount':
if total_amount_name and str(total_amount_name).strip():
display_name = str(total_amount_name).strip()
else:
display_name = '实收金额'
elif field in field_custom_names and field_custom_names[field]:
display_name = field_custom_names[field]
elif field in id_name_maps and id_name_maps[field]:
display_name = get_field_display_name(field).replace('ID', '')
else:
display_name = get_field_display_name(field)
cell.value = display_name
cell.font = header_font
cell.fill = header_fill
cell.alignment = header_alignment
cell.border = thin_border
# 自定义服务费列表头(如果设置了单价)
has_custom_service_fee = custom_service_fee_price is not None and custom_service_fee_price != ''
if has_custom_service_fee:
custom_fee_col = len(selected_fields) + 2
cell = ws.cell(row=header_row, column=custom_fee_col)
if custom_service_fee_name and str(custom_service_fee_name).strip():
header_name = str(custom_service_fee_name).strip()
else:
header_name = f'自定义服务费({custom_service_fee_price}元/kWh)'
cell.value = header_name
cell.font = header_font
cell.fill = header_fill
cell.alignment = header_alignment
cell.border = thin_border
ws.row_dimensions[header_row].height = 25
# 写入数据
@@ -758,29 +767,44 @@ def generate_excel(orders, selected_fields, sum_fields, sum_results,
for col_idx, field in enumerate(selected_fields, 2):
cell = ws.cell(row=row_idx, column=col_idx)
value = order.get(field, '')
# 格式化时间字段
if field in ['report_time', 'start_time', 'end_time', 'create_time', 'update_time', 'pay_time']:
if isinstance(value, datetime):
value = value.strftime('%Y-%m-%d %H:%M:%S')
# 将ID转换为名称
if field in id_name_maps and value is not None and value != '':
name_map = id_name_maps[field]
name_value = name_map.get(str(value))
if name_value:
value = name_value
if field == 'custom_service_fee':
if has_custom_service_fee:
charge_degree = float(order.get('charge_degree', 0) or 0)
value = round(charge_degree * float(custom_service_fee_price), 2)
else:
value = ''
elif field == 'total_amount':
actual_money = float(order.get('charge_elecfee_amount', 0) or 0)
if has_custom_service_fee:
charge_degree = float(order.get('charge_degree', 0) or 0)
custom_fee = round(charge_degree * float(custom_service_fee_price), 2)
value = round(actual_money + custom_fee, 2)
else:
value = round(actual_money, 2)
else:
value = order.get(field, '')
# 格式化时间字段
if field in ['report_time', 'start_time', 'end_time', 'create_time', 'update_time', 'pay_time']:
if isinstance(value, datetime):
value = value.strftime('%Y-%m-%d %H:%M:%S')
# 将ID转换为名称
if field in id_name_maps and value is not None and value != '':
name_map = id_name_maps[field]
name_value = name_map.get(str(value))
if name_value:
value = name_value
cell.value = value
cell.border = thin_border
# 数字字段靠右对齐,其他居中或靠左
if field in numeric_fields:
if field in numeric_fields or field in ['custom_service_fee', 'total_amount']:
cell.alignment = Alignment(horizontal='right', vertical='center')
if isinstance(value, (int, float)):
if field in decimal3_fields:
cell.number_format = '0.000'
cell.number_format = '0.00'
elif field in ['order_no', 'vehicle_no', 'gun_no', 'connector_no']:
cell.alignment = Alignment(horizontal='center', vertical='center')
else:
@@ -790,19 +814,6 @@ def generate_excel(orders, selected_fields, sum_fields, sum_results,
if is_even:
cell.fill = even_row_fill
# 自定义服务费列(如果设置了单价)
if has_custom_service_fee:
custom_fee_col = len(selected_fields) + 2
cell = ws.cell(row=row_idx, column=custom_fee_col)
charge_degree = float(order.get('charge_degree', 0) or 0)
custom_fee = round(charge_degree * float(custom_service_fee_price), 2)
cell.value = custom_fee
cell.border = thin_border
cell.alignment = Alignment(horizontal='right', vertical='center')
cell.number_format = '0.00'
if is_even:
cell.fill = even_row_fill
ws.row_dimensions[row_idx].height = 22
# 写入求和行
@@ -819,25 +830,33 @@ def generate_excel(orders, selected_fields, sum_fields, sum_results,
cell = ws.cell(row=sum_row, column=col_idx)
cell.fill = sum_fill
cell.border = thin_border
if field in sum_fields and field in sum_results:
if field == 'custom_service_fee':
if has_custom_service_fee:
total_charge_degree = sum_results.get('charge_degree', 0)
value = round(float(total_charge_degree) * float(custom_service_fee_price), 2)
cell.value = value
cell.font = sum_font
cell.alignment = Alignment(horizontal='right', vertical='center')
cell.number_format = '0.00'
elif field == 'total_amount':
total_actual_money = sum_results.get('charge_elecfee_amount', 0)
if has_custom_service_fee:
total_charge_degree = sum_results.get('charge_degree', 0)
total_custom_fee = round(float(total_charge_degree) * float(custom_service_fee_price), 2)
value = round(float(total_actual_money) + total_custom_fee, 2)
else:
value = round(float(total_actual_money), 2)
cell.value = value
cell.font = sum_font
cell.alignment = Alignment(horizontal='right', vertical='center')
cell.number_format = '0.00'
elif field in sum_fields and field in sum_results:
cell.value = sum_results[field]
cell.font = sum_font
cell.alignment = Alignment(horizontal='right', vertical='center')
cell.number_format = '0.000'
# 自定义服务费合计
if has_custom_service_fee:
custom_fee_col = len(selected_fields) + 2
cell = ws.cell(row=sum_row, column=custom_fee_col)
cell.fill = sum_fill
cell.border = thin_border
total_charge_degree = sum_results.get('charge_degree', 0)
total_custom_fee = round(float(total_charge_degree) * float(custom_service_fee_price), 2)
cell.value = total_custom_fee
cell.font = sum_font
cell.alignment = Alignment(horizontal='right', vertical='center')
cell.number_format = '0.00'
ws.row_dimensions[sum_row].height = 25
# 写入当月充电量累计总计行(从求和采集表查询,对账后数据)
@@ -881,8 +900,6 @@ def generate_excel(orders, selected_fields, sum_fields, sum_results,
# 总列数
total_cols = len(selected_fields) + 2
if has_custom_service_fee:
total_cols += 1
# 标题文字
title_text = f'当月累计充电量(共{total_days}天,截止{report_date}'
@@ -935,10 +952,15 @@ def generate_excel(orders, selected_fields, sum_fields, sum_results,
log_error(f"[日报生成] 写入月度总计时出错: {e}", 'report')
# 调整列宽中文按2个字符宽度计算
# 序号列固定宽度
from openpyxl.utils import get_column_letter
# 序号列固定宽度
ws.column_dimensions['A'].width = 8
# 计算所有字段的宽度
col_widths = {}
numeric_cols = []
for col_idx, field in enumerate(selected_fields, 2):
header_name = get_field_display_name(field)
if field in field_custom_names and field_custom_names[field]:
@@ -955,21 +977,25 @@ def generate_excel(orders, selected_fields, sum_fields, sum_results,
cell_len = len(cell_str) + cn_count
max_length = max(max_length, cell_len)
from openpyxl.utils import get_column_letter
col_letter = get_column_letter(col_idx)
ws.column_dimensions[col_letter].width = min(max_length + 2, 50)
col_widths[col_idx] = min(max_length + 2, 50)
# 标记数值类型字段(求和类列)
if field in numeric_fields or field in ['custom_service_fee', 'total_amount']:
numeric_cols.append(col_idx)
# 自定义服务费列宽度
if has_custom_service_fee:
custom_fee_col = len(selected_fields) + 2
if custom_service_fee_name and str(custom_service_fee_name).strip():
header_name = str(custom_service_fee_name).strip()
else:
header_name = f'自定义服务费({custom_service_fee_price}元/kWh)'
cn_count = sum(1 for c in str(header_name) if '\u4e00' <= c <= '\u9fff')
max_length = len(str(header_name)) + cn_count
col_letter = get_column_letter(custom_fee_col)
ws.column_dimensions[col_letter].width = min(max_length + 2, 50)
# 计算数值类型列的最大宽度,使所有求和类列宽度一致
if numeric_cols:
max_numeric_width = max(col_widths[col] for col in numeric_cols)
for col_idx in numeric_cols:
col_letter = get_column_letter(col_idx)
ws.column_dimensions[col_letter].width = max_numeric_width
# 设置非数值类型列的宽度
for col_idx, width in col_widths.items():
if col_idx not in numeric_cols:
col_letter = get_column_letter(col_idx)
ws.column_dimensions[col_letter].width = width
# 冻结首行
ws.freeze_panes = 'A2'