#!/usr/bin/env python3 """按三份GPS日里程文件处理2026年7月测试车辆考核源表。""" from copy import copy from collections import defaultdict from datetime import datetime from pathlib import Path import re import shutil import openpyxl from openpyxl.styles import PatternFill BASE = Path('/Users/kkfluous/Downloads') OUT = BASE / '7月核算结果' SRC = BASE / '租赁任务考核_2026年7月 (1).xlsx' TEST = Path('/Users/kkfluous/Library/Containers/com.tencent.xinWeChat/Data/Documents/xwechat_files/wxid_1704407055112_3af8/temp/RWTemp/2026-08/4340099467fbf08b4c6583c49adba4ee/7月测试车辆明细.xlsx') GPS_DAILY = BASE / '智能管车_车辆里程日报-140106360.xlsx' GPS_DETAIL = [ BASE / '里程统计[天][2026-07-01至2026-07-31].xlsx', BASE / '里程统计[天][2026-07-01至2026-07-31] (1).xlsx', ] EXCLUDED_TEST_PLATES = {'粤AG37316'} ZERO_OVERRIDE = set() DEPARTMENT_OVERRIDE = {'粤AGP6675': '业务六部', '粤AGP9757': '业务六部'} def norm(v): return re.sub(r'\s+', '', str(v or '')).upper() def number(v): try: return float(v or 0) except (TypeError, ValueError): return 0.0 def read_test_plates(): wb = openpyxl.load_workbook(TEST, data_only=True) ws = wb.active plates = {norm(r[0]) for r in ws.iter_rows(min_row=2, values_only=True) if norm(r[0])} wb.close() return plates - EXCLUDED_TEST_PLATES def read_daily_matrix(): wb = openpyxl.load_workbook(GPS_DAILY, data_only=True) ws = wb.active headers = [c.value for c in ws[1]] day_cols = {} for i, v in enumerate(headers): m = re.fullmatch(r'07月(\d{2})日', str(v or '')) if m: day_cols[int(m.group(1))] = i data = {} for row in ws.iter_rows(min_row=2, values_only=True): plate = norm(row[0]) if plate: data[plate] = {d: number(row[i]) for d, i in day_cols.items()} wb.close() return data def read_detail_files(): data = defaultdict(lambda: defaultdict(float)) for path in GPS_DETAIL: wb = openpyxl.load_workbook(path, data_only=True) ws = wb.active headers = [c.value for c in ws[3]] pcol = next(i for i, v in enumerate(headers) if v and '车牌' in str(v)) dcol = next(i for i, v in enumerate(headers) if str(v or '').strip() == '日期') mcol = next(i for i, v in enumerate(headers) if v and '里程' in str(v) and 'km' in str(v).lower()) for row in ws.iter_rows(min_row=4, values_only=True): plate = norm(row[pcol]) if not plate: continue try: dt = row[dcol] if isinstance(row[dcol], datetime) else datetime.strptime(str(row[dcol])[:10], '%Y-%m-%d') except (TypeError, ValueError): continue # 同一车辆同一天在两份明细中如重复,取较大值,避免重复累计。 data[plate][dt.day] = max(data[plate][dt.day], number(row[mcol])) wb.close() return {p: dict(days) for p, days in data.items()} def copy_cell_style(src, dst): dst._style = copy(src._style) if src.has_style: dst.number_format = src.number_format dst.protection = copy(src.protection) dst.alignment = copy(src.alignment) def main(): OUT.mkdir(parents=True, exist_ok=True) shutil.copy2(SRC, OUT / '租赁任务考核_2026年7月_原版备份.xlsx') tests = read_test_plates() matrix = read_daily_matrix() details = read_detail_files() wb = openpyxl.load_workbook(SRC) ws = wb['业务考核视图'] # 原表O列是实际里程。插入后统一为 O原TBOX、P实际、Q测试、R完成率、S是否达标。 ws.insert_cols(15, 1) ws.insert_cols(17, 1) ws['O1'] = '原TBOX里程(km)' ws['Q1'] = '测试里程(km)' copy_cell_style(ws['P1'], ws['O1']) copy_cell_style(ws['P1'], ws['Q1']) yellow = PatternFill(fill_type='solid', fgColor='FFFF00') records = [] missing = [] for ri in range(2, ws.max_row + 1): plate = norm(ws.cell(ri, 1).value) if plate in DEPARTMENT_OVERRIDE: ws.cell(ri, 4).value = DEPARTMENT_OVERRIDE[plate] original = number(ws.cell(ri, 16).value) ws.cell(ri, 15).value = round(original, 2) copy_cell_style(ws.cell(ri, 16), ws.cell(ri, 15)) copy_cell_style(ws.cell(ri, 16), ws.cell(ri, 17)) if plate not in tests: ws.cell(ri, 17).value = 0 continue start = ws.cell(ri, 11).value end = ws.cell(ri, 12).value start_day = start.day if isinstance(start, datetime) else 1 end_day = end.day if isinstance(end, datetime) else 31 if plate in ZERO_OVERRIDE: actual = 0.0 source = 'GPS缺失,业务确认暂按0' elif plate in matrix: actual = sum(matrix[plate].get(d, 0) for d in range(start_day, end_day + 1)) source = GPS_DAILY.name elif plate in details: actual = sum(details[plate].get(d, 0) for d in range(start_day, end_day + 1)) source = '里程统计日明细' else: missing.append(plate) continue target = number(ws.cell(ri, 14).value) test_mileage = max(0.0, original - actual) rate = actual / target * 100 if target > 0 else 0 ws.cell(ri, 16).value = round(actual, 2) ws.cell(ri, 17).value = round(test_mileage, 2) ws.cell(ri, 18).value = round(rate, 2) ws.cell(ri, 19).value = '达标' if target > 0 and actual >= target else '未达标' for cell in ws[ri]: cell.fill = copy(yellow) records.append((plate, ri, original, actual, test_mileage, source)) if missing: raise RuntimeError('仍缺GPS车牌: ' + ','.join(sorted(set(missing)))) # 对齐5/6月的宽度、筛选和冻结窗格;保留原表其余样式。 ref = openpyxl.load_workbook(BASE / '租赁任务考核_2026年6月.xlsx', read_only=False) rws = ref['业务考核视图'] for i in range(1, 24): letter = openpyxl.utils.get_column_letter(i) if rws.column_dimensions[letter].width: ws.column_dimensions[letter].width = rws.column_dimensions[letter].width ws.freeze_panes = rws.freeze_panes ws.auto_filter.ref = f'A1:W{ws.max_row}' ref.close() out = OUT / '租赁任务考核_2026年7月.xlsx' wb.save(out) wb.close() print(f'output={out}') print(f'test_list={len(tests)} intervention_records={len(records)} intervention_plates={len(set(r[0] for r in records))}') print(f'zero_override={sorted(ZERO_OVERRIDE)}') print(f'department_override={DEPARTMENT_OVERRIDE}') print(f'total_original={sum(r[2] for r in records):.2f} total_gps={sum(r[3] for r in records):.2f} total_test={sum(r[4] for r in records):.2f}') if __name__ == '__main__': main()