102 lines
3.6 KiB
Python
102 lines
3.6 KiB
Python
from ast import parse, walk, Call, Constant, keyword
|
|
from collections import defaultdict
|
|
from datetime import datetime, date
|
|
from pathlib import Path
|
|
import re
|
|
import shutil
|
|
|
|
import openpyxl
|
|
import pymysql
|
|
|
|
|
|
OUTPUT = Path('/Users/kkfluous/Downloads/7月核算结果/7月考核车辆多源里程汇总.xlsx')
|
|
BACKUP = Path('/Users/kkfluous/Downloads/7月核算结果/7月考核车辆多源里程汇总_GPS全量回补前.xlsx')
|
|
|
|
|
|
def norm(value):
|
|
return re.sub(r'\s+', '', str(value or '')).upper()
|
|
|
|
|
|
def db_config():
|
|
tree = parse(Path('/Users/kkfluous/Downloads/replace_gps_jun.py').read_text())
|
|
for node in walk(tree):
|
|
if not isinstance(node, Call) or getattr(node.func, 'attr', None) != 'connect':
|
|
continue
|
|
values = {}
|
|
for item in node.keywords:
|
|
if isinstance(item, keyword) and isinstance(item.value, Constant):
|
|
values[item.arg] = item.value.value
|
|
if {'host', 'user', 'password', 'database'} <= values.keys():
|
|
return values
|
|
raise RuntimeError('未找到既有GPS数据库配置')
|
|
|
|
|
|
wb = openpyxl.load_workbook(OUTPUT)
|
|
ws = wb.active
|
|
header_row = next(r for r in range(1, 8) if ws.cell(r, 12).value == 'GPS里程(km)')
|
|
data_start = header_row + 1
|
|
plates = sorted({norm(ws.cell(r, 2).value) for r in range(data_start, ws.max_row + 1) if ws.cell(r, 2).value})
|
|
|
|
cfg = db_config()
|
|
cfg.update(charset='utf8mb4', connect_timeout=8, read_timeout=30, write_timeout=30)
|
|
conn = pymysql.connect(**cfg)
|
|
try:
|
|
with conn.cursor() as cur:
|
|
placeholders = ','.join(['%s'] * len(plates))
|
|
cur.execute(
|
|
f'''SELECT plate_number, dates, total_mileage
|
|
FROM ln_vehicle_g7_mileage
|
|
WHERE dates >= %s AND dates <= %s
|
|
AND plate_number IN ({placeholders})''',
|
|
[date(2026, 7, 1), date(2026, 7, 31), *plates],
|
|
)
|
|
db_rows = cur.fetchall()
|
|
finally:
|
|
conn.close()
|
|
|
|
daily = defaultdict(dict)
|
|
for plate, day, raw_mileage in db_rows:
|
|
if isinstance(day, datetime):
|
|
day = day.date()
|
|
daily[norm(plate)][day] = float(raw_mileage or 0) / 100000.0
|
|
|
|
if not BACKUP.exists():
|
|
shutil.copy2(OUTPUT, BACKUP)
|
|
|
|
filled = []
|
|
still_missing = []
|
|
for row in range(data_start, ws.max_row + 1):
|
|
cell = ws.cell(row, 12)
|
|
if cell.value != '无来源':
|
|
continue
|
|
plate = norm(ws.cell(row, 2).value)
|
|
start = ws.cell(row, 4).value
|
|
end = ws.cell(row, 5).value
|
|
if isinstance(start, datetime):
|
|
start = start.date()
|
|
if isinstance(end, datetime):
|
|
end = end.date()
|
|
matched = [value for day, value in daily.get(plate, {}).items() if start <= day <= end]
|
|
if matched:
|
|
cell.value = round(sum(matched), 2)
|
|
cell.number_format = '#,##0.0'
|
|
filled.append((plate, start, end, cell.value))
|
|
else:
|
|
still_missing.append((plate, start, end))
|
|
|
|
ws['A1'] = (
|
|
'1. 纯氢里程(km)、纯电里程(km)来源于广州平台统计,TBOX里程来源于车机上报的仪表盘里程统计,'
|
|
'GPS里程优先使用两份7月GPS日明细,缺失车辆由GPS数据库每日里程按考核区间回补;测试车辆以7月最终考核源表已确认GPS为准\n'
|
|
'2. 广州平台总里程(km)=纯氢里程(km)+纯电里程(km)\n'
|
|
'3. 已确认广州平台暂未接入86辆普货车数据;所有GPS来源均无对应记录时标记为“无来源”'
|
|
)
|
|
wb.save(OUTPUT)
|
|
|
|
print({
|
|
'database_rows': len(db_rows),
|
|
'database_plates': len(daily),
|
|
'backfilled_records': len(filled),
|
|
'remaining_missing_records': len(still_missing),
|
|
'remaining_missing_plates': len({x[0] for x in still_missing}),
|
|
})
|