悠修复自定义实收金额和求和采集功能增强
This commit is contained in:
@@ -27,6 +27,9 @@ sum_data_bp = Blueprint('sum_data', __name__, url_prefix='/api')
|
||||
# 认证蓝图
|
||||
from .auth_api import auth_bp
|
||||
|
||||
# 全局配置蓝图
|
||||
from .global_config_api import global_config_api
|
||||
|
||||
# 导入各模块的路由
|
||||
from . import config_api, entity_api, field_api, report_api, init_api, download_api, sum_data_api
|
||||
|
||||
@@ -41,3 +44,4 @@ def register_blueprints(app):
|
||||
app.register_blueprint(download_bp)
|
||||
app.register_blueprint(sum_data_bp)
|
||||
app.register_blueprint(auth_bp)
|
||||
app.register_blueprint(global_config_api)
|
||||
|
||||
36
lib/api/global_config_api.py
Normal file
36
lib/api/global_config_api.py
Normal file
@@ -0,0 +1,36 @@
|
||||
from flask import Blueprint, jsonify, request
|
||||
from lib.db import execute_query, execute_update
|
||||
import json
|
||||
|
||||
global_config_api = Blueprint('global_config_api', __name__)
|
||||
|
||||
|
||||
@global_config_api.route('/api/global-config/sum-data-fields', methods=['GET'])
|
||||
def get_sum_data_fields():
|
||||
"""获取求和数据采集字段配置"""
|
||||
try:
|
||||
result = execute_query("SELECT sum_data_fields FROM t_daily_report_global_config WHERE id = 1")
|
||||
if result and result[0]['sum_data_fields']:
|
||||
fields = json.loads(result[0]['sum_data_fields'])
|
||||
return jsonify({'success': True, 'data': fields})
|
||||
return jsonify({'success': True, 'data': []})
|
||||
except Exception as e:
|
||||
return jsonify({'success': False, 'message': str(e)}), 500
|
||||
|
||||
|
||||
@global_config_api.route('/api/global-config/sum-data-fields', methods=['POST'])
|
||||
def save_sum_data_fields():
|
||||
"""保存求和数据采集字段配置"""
|
||||
try:
|
||||
data = request.get_json()
|
||||
fields = data.get('sum_data_fields', [])
|
||||
fields_json = json.dumps(fields)
|
||||
|
||||
execute_update(
|
||||
"UPDATE t_daily_report_global_config SET sum_data_fields = %s, update_time = NOW() WHERE id = 1",
|
||||
(fields_json,)
|
||||
)
|
||||
|
||||
return jsonify({'success': True, 'message': '配置保存成功'})
|
||||
except Exception as e:
|
||||
return jsonify({'success': False, 'message': str(e)}), 500
|
||||
@@ -182,6 +182,33 @@ def init_database_tables():
|
||||
"total_amount_name VARCHAR(100) NULL COMMENT '实收金额报表表头名称'",
|
||||
'total_amount_name'
|
||||
)
|
||||
|
||||
# 创建全局配置表
|
||||
create_global_config_table = """
|
||||
CREATE TABLE IF NOT EXISTS t_daily_report_global_config (
|
||||
id BIGINT NOT NULL DEFAULT 1 COMMENT '主键(固定为1)',
|
||||
sum_data_fields VARCHAR(1000) NULL COMMENT '求和数据采集和显示字段列表(JSON格式)',
|
||||
create_time DATETIME NULL COMMENT '创建时间',
|
||||
update_time DATETIME NULL COMMENT '更新时间'
|
||||
)
|
||||
UNIQUE KEY(id)
|
||||
DISTRIBUTED BY HASH(id) BUCKETS 1
|
||||
PROPERTIES("replication_num" = "1")
|
||||
"""
|
||||
execute_update(create_global_config_table)
|
||||
_set_table_comment('t_daily_report_global_config', '日报全局配置表')
|
||||
log_info("[数据库] t_daily_report_global_config 表已就绪", 'db_init')
|
||||
|
||||
# 初始化全局配置记录(如果不存在)
|
||||
try:
|
||||
exists = execute_query("SELECT COUNT(*) as cnt FROM t_daily_report_global_config WHERE id = 1")
|
||||
if not exists or exists[0]['cnt'] == 0:
|
||||
execute_update(
|
||||
"INSERT INTO t_daily_report_global_config (id, create_time, update_time) VALUES (1, NOW(), NOW())"
|
||||
)
|
||||
log_info("[数据库] 初始化全局配置记录成功", 'db_init')
|
||||
except Exception as e:
|
||||
log_warning(f"[数据库] 初始化全局配置记录失败: {e}", 'db_init')
|
||||
|
||||
# 数据迁移:给 sort_order 为 NULL 的配置记录按 id 顺序赋值
|
||||
try:
|
||||
|
||||
@@ -172,7 +172,7 @@ FIELD_MAPPING = {
|
||||
|
||||
# 自定义计算字段(虚拟字段)
|
||||
'custom_service_fee': '自定义服务费(元)',
|
||||
'total_amount': '实收金额(元)',
|
||||
'custom_total_amount': '自定义实收总金额(元)',
|
||||
|
||||
# 车辆信息(从 t_car 表关联)
|
||||
'car_bus_path': '公交线路',
|
||||
|
||||
@@ -319,6 +319,16 @@ def generate_daily_report(config_id, start_time=None, end_time=None):
|
||||
selected_fields = json.loads(config['selected_fields'])
|
||||
sum_fields = json.loads(config['sum_fields']) if config['sum_fields'] else []
|
||||
|
||||
# 根据配置自动添加虚拟字段到选中字段列表
|
||||
show_custom_service_fee = config.get('show_custom_service_fee', 0) == 1
|
||||
show_total_amount = config.get('show_total_amount', 0) == 1
|
||||
|
||||
if show_custom_service_fee and 'custom_service_fee' not in selected_fields:
|
||||
selected_fields.append('custom_service_fee')
|
||||
|
||||
if show_total_amount and 'custom_total_amount' not in selected_fields:
|
||||
selected_fields.append('custom_total_amount')
|
||||
|
||||
# 设置时间范围
|
||||
if not start_time or not end_time:
|
||||
now = get_beijing_time()
|
||||
@@ -340,17 +350,18 @@ 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 - 过滤掉虚拟字段(时段电量、自定义服务费、自定义实收总金额、车辆信息等)
|
||||
# 虚拟字段不是数据库表中的实际字段,需要动态计算或关联查询
|
||||
VIRTUAL_FIELDS = {'sharp_electricity', 'peak_electricity', 'flat_electricity', 'valley_electricity', 'custom_service_fee', 'total_amount', 'car_bus_path', 'car_sn'}
|
||||
# 注意:total_amount 是旧版虚拟字段名,为了向后兼容也需要包含在内
|
||||
VIRTUAL_FIELDS = {'sharp_electricity', 'peak_electricity', 'flat_electricity', 'valley_electricity', 'custom_service_fee', 'custom_total_amount', 'total_amount', 'car_bus_path', 'car_sn'}
|
||||
db_fields = [f for f in selected_fields if f not in VIRTUAL_FIELDS]
|
||||
|
||||
# 确保 charge_degree 总是被查询(用于计算总电量)
|
||||
if 'charge_degree' not in db_fields:
|
||||
db_fields.append('charge_degree')
|
||||
|
||||
# 如果选择了实收金额字段,需要确保查询 charge_elecfee_amount(电费金额)
|
||||
if 'total_amount' in selected_fields and 'charge_elecfee_amount' not in db_fields:
|
||||
# 如果选择了自定义实收总金额字段,需要确保查询 charge_elecfee_amount(电费金额)
|
||||
if 'custom_total_amount' in selected_fields and 'charge_elecfee_amount' not in db_fields:
|
||||
db_fields.append('charge_elecfee_amount')
|
||||
|
||||
# 确保至少有 order_no 字段用于关联分时数据
|
||||
@@ -506,6 +517,31 @@ def generate_daily_report(config_id, start_time=None, end_time=None):
|
||||
|
||||
log_info(f"[日报生成] 已计算 {len(time_period_electricity)} 条订单的分时段电量", 'report')
|
||||
|
||||
# 计算虚拟字段(自定义服务费、自定义实收总金额)并添加到订单数据中
|
||||
# 这样求和数据才能正确计算这些字段的总和
|
||||
has_custom_service_fee = config.get('custom_service_fee_price') is not None and str(config.get('custom_service_fee_price', '')).strip() != ''
|
||||
if has_custom_service_fee:
|
||||
custom_service_fee_price = float(config['custom_service_fee_price'])
|
||||
for order in orders:
|
||||
charge_degree = float(order.get('charge_degree', 0) or 0)
|
||||
custom_service_fee = round(charge_degree * custom_service_fee_price, 2)
|
||||
order['custom_service_fee'] = custom_service_fee
|
||||
|
||||
# 计算自定义实收总金额(实收电费 + 自定义服务费)
|
||||
actual_money = float(order.get('charge_elecfee_amount', 0) or 0)
|
||||
custom_total_amount = round(actual_money + custom_service_fee, 2)
|
||||
order['custom_total_amount'] = custom_total_amount
|
||||
# 兼容旧版字段名 total_amount
|
||||
order['total_amount'] = custom_total_amount
|
||||
else:
|
||||
# 如果没有自定义服务费,自定义实收总金额 = 实收电费
|
||||
for order in orders:
|
||||
actual_money = float(order.get('charge_elecfee_amount', 0) or 0)
|
||||
custom_total_amount = round(actual_money, 2)
|
||||
order['custom_total_amount'] = custom_total_amount
|
||||
# 兼容旧版字段名 total_amount
|
||||
order['total_amount'] = custom_total_amount
|
||||
|
||||
# 计算求和(保留三位小数)
|
||||
sum_results = {}
|
||||
for field in sum_fields:
|
||||
@@ -523,6 +559,27 @@ def generate_daily_report(config_id, start_time=None, end_time=None):
|
||||
sum_results['charge_degree'] = round(total_charge_degree, 3)
|
||||
log_info(f"[日报生成] 强制采集充电电量: {sum_results['charge_degree']} kWh", 'report')
|
||||
|
||||
# 强制采集实收电费(charge_elecfee_amount),用于计算自定义实收总金额的求和
|
||||
if 'charge_elecfee_amount' not in sum_results and orders:
|
||||
has_charge_elecfee_amount = any('charge_elecfee_amount' in order for order in orders)
|
||||
if has_charge_elecfee_amount:
|
||||
total_charge_elecfee_amount = sum(float(order.get('charge_elecfee_amount', 0) or 0) for order in orders)
|
||||
sum_results['charge_elecfee_amount'] = round(total_charge_elecfee_amount, 3)
|
||||
|
||||
# 强制采集自定义服务费(custom_service_fee),直接使用订单中已计算好的值求和
|
||||
if 'custom_service_fee' not in sum_results and orders:
|
||||
has_custom_service_fee_field = any('custom_service_fee' in order for order in orders)
|
||||
if has_custom_service_fee_field:
|
||||
total_custom_service_fee = sum(float(order.get('custom_service_fee', 0) or 0) for order in orders)
|
||||
sum_results['custom_service_fee'] = round(total_custom_service_fee, 2)
|
||||
|
||||
# 强制采集自定义实收总金额(custom_total_amount),直接使用订单中已计算好的值求和
|
||||
if 'custom_total_amount' not in sum_results and orders:
|
||||
has_custom_total_amount = any('custom_total_amount' in order for order in orders)
|
||||
if has_custom_total_amount:
|
||||
total_custom_total_amount = sum(float(order.get('custom_total_amount', 0) or 0) for order in orders)
|
||||
sum_results['custom_total_amount'] = round(total_custom_total_amount, 2)
|
||||
|
||||
# 构建ID到名称的映射
|
||||
id_name_maps = build_id_to_name_map(orders, selected_fields)
|
||||
|
||||
@@ -772,11 +829,11 @@ def generate_excel(orders, selected_fields, sum_fields, sum_results,
|
||||
display_name = f'自定义服务费({custom_service_fee_price}元/kWh)'
|
||||
else:
|
||||
display_name = '自定义服务费'
|
||||
elif field == 'total_amount':
|
||||
elif field == 'custom_total_amount' or field == 'total_amount':
|
||||
if total_amount_name and str(total_amount_name).strip():
|
||||
display_name = str(total_amount_name).strip()
|
||||
else:
|
||||
display_name = '实收金额'
|
||||
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]:
|
||||
@@ -810,19 +867,11 @@ def generate_excel(orders, selected_fields, sum_fields, sum_results,
|
||||
cell = ws.cell(row=row_idx, column=col_idx)
|
||||
|
||||
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)
|
||||
# 直接使用订单数据中已计算好的值
|
||||
value = order.get('custom_service_fee', '')
|
||||
elif field == 'custom_total_amount' or field == 'total_amount':
|
||||
# 直接使用订单数据中已计算好的值(兼容旧版字段名 total_amount)
|
||||
value = order.get('custom_total_amount', order.get('total_amount', ''))
|
||||
else:
|
||||
value = order.get(field, '')
|
||||
|
||||
@@ -842,7 +891,7 @@ def generate_excel(orders, selected_fields, sum_fields, sum_results,
|
||||
cell.border = thin_border
|
||||
|
||||
# 数字字段靠右对齐,其他居中或靠左
|
||||
if field in numeric_fields or field in ['custom_service_fee', 'total_amount']:
|
||||
if field in numeric_fields or field in ['custom_service_fee', 'custom_total_amount', 'total_amount']:
|
||||
cell.alignment = Alignment(horizontal='right', vertical='center')
|
||||
if isinstance(value, (int, float)):
|
||||
cell.number_format = '0.00'
|
||||
@@ -873,21 +922,30 @@ def generate_excel(orders, selected_fields, sum_fields, sum_results,
|
||||
cell.border = thin_border
|
||||
|
||||
if field == 'custom_service_fee':
|
||||
if has_custom_service_fee:
|
||||
# 直接使用订单中已计算好的值求和,确保与数据行一致
|
||||
if 'custom_service_fee' in sum_results:
|
||||
value = sum_results['custom_service_fee']
|
||||
elif 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)
|
||||
value = ''
|
||||
cell.value = value
|
||||
cell.font = sum_font
|
||||
cell.alignment = Alignment(horizontal='right', vertical='center')
|
||||
cell.number_format = '0.00'
|
||||
elif field == 'custom_total_amount' or field == 'total_amount':
|
||||
# 直接使用订单中已计算好的值求和,确保与数据行一致
|
||||
if 'custom_total_amount' in sum_results:
|
||||
value = sum_results['custom_total_amount']
|
||||
else:
|
||||
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')
|
||||
@@ -1022,7 +1080,7 @@ def generate_excel(orders, selected_fields, sum_fields, sum_results,
|
||||
col_widths[col_idx] = min(max_length + 2, 50)
|
||||
|
||||
# 标记数值类型字段(求和类列)
|
||||
if field in numeric_fields or field in ['custom_service_fee', 'total_amount']:
|
||||
if field in numeric_fields or field in ['custom_service_fee', 'custom_total_amount', 'total_amount']:
|
||||
numeric_cols.append(col_idx)
|
||||
|
||||
# 计算数值类型列的最大宽度,使所有求和类列宽度一致
|
||||
|
||||
@@ -51,6 +51,17 @@ def collect_sum_data_from_history(history_id=None, start_date=None, end_date=Non
|
||||
skipped_count = 0
|
||||
config_cache = {} # 缓存配置的排序号和自定义服务费单价
|
||||
|
||||
# 获取全局配置的求和数据采集字段
|
||||
sum_data_fields = None
|
||||
try:
|
||||
global_config_result = execute_query(
|
||||
'SELECT sum_data_fields FROM t_daily_report_global_config WHERE id = 1 LIMIT 1'
|
||||
)
|
||||
if global_config_result and global_config_result[0].get('sum_data_fields'):
|
||||
sum_data_fields = json.loads(global_config_result[0]['sum_data_fields'])
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
for history in history_list:
|
||||
sum_results = history.get('sum_results')
|
||||
|
||||
@@ -115,6 +126,13 @@ def collect_sum_data_from_history(history_id=None, start_date=None, end_date=Non
|
||||
(history['report_date'], history['config_id'], history['split_value'])
|
||||
)
|
||||
|
||||
# 根据配置过滤采集字段
|
||||
# 如果配置了 sum_data_fields,则只采集这些字段(charge_degree 始终采集)
|
||||
if sum_data_fields and isinstance(sum_data_fields, list):
|
||||
filtered_fields = set(sum_data_fields)
|
||||
filtered_fields.add('charge_degree') # 充电电量始终采集
|
||||
sum_results = {k: v for k, v in sum_results.items() if k in filtered_fields}
|
||||
|
||||
# 逐条插入求和字段数据
|
||||
for field_key, field_value in sum_results.items():
|
||||
sum_data_id = int(datetime.now().timestamp() * 1000000) + collected_count
|
||||
@@ -179,6 +197,30 @@ def collect_sum_data_from_history(history_id=None, start_date=None, end_date=Non
|
||||
)
|
||||
execute_insert(sql, params)
|
||||
collected_count += 1
|
||||
|
||||
# 计算自定义实收总金额(实收电费 + 自定义服务费)
|
||||
# 实收电费从 sum_results 中获取(charge_elecfee_amount)
|
||||
charge_elecfee_amount = float(sum_results.get('charge_elecfee_amount', 0) or 0)
|
||||
custom_total_amount = round(charge_elecfee_amount + custom_service_fee, 2)
|
||||
sum_data_id = int(datetime.now().timestamp() * 1000000) + collected_count
|
||||
params = (
|
||||
sum_data_id,
|
||||
history['report_date'],
|
||||
history['config_id'],
|
||||
history.get('config_name', ''),
|
||||
history.get('split_type', ''),
|
||||
history.get('split_value', ''),
|
||||
history.get('split_name', ''),
|
||||
'custom_total_amount',
|
||||
'自定义实收总金额',
|
||||
custom_total_amount,
|
||||
history.get('total_orders', 0),
|
||||
sort_order,
|
||||
'auto',
|
||||
f'自动计算:实收电费{charge_elecfee_amount}元 + 自定义服务费{custom_service_fee}元'
|
||||
)
|
||||
execute_insert(sql, params)
|
||||
collected_count += 1
|
||||
except Exception as fee_error:
|
||||
log_error(f"[采集] 计算自定义服务费失败: {fee_error}", 'sum_data')
|
||||
|
||||
|
||||
Reference in New Issue
Block a user