Files
kra-new/scripts/sw_export_compare.py
T

77 lines
4.2 KiB
Python

"""以同一主账号的实际数据请求新旧明细导出,并逐单元格核对,文件保留在仓库外。"""
import argparse
import decimal
import io
import json
import time
import urllib.parse
import urllib.request
from pathlib import Path
import openpyxl
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--runtime", type=Path, required=True)
parser.add_argument("--old-url", default="http://127.0.0.1:18080")
parser.add_argument("--new-url", default="http://127.0.0.1:19001")
parser.add_argument("--output", type=Path, required=True)
args = parser.parse_args()
if args.runtime.resolve().is_relative_to(Path(__file__).resolve().parents[1]):
raise ValueError("导出文件必须保存在仓库外")
client = json.loads((args.runtime / "legacy-client.json").read_text(encoding="utf-8"))["client_id"]
headers = [{"Authorization": "Bearer " + (args.runtime / "legacy-admin.token").read_text().strip(), "clientid": client},
{"x-token": (args.runtime / "new-admin.token").read_text().strip()}]
reports = []
for kind, time_key in (("register", "Register"), ("spend", "Pay")):
params = {"sourceDb": "lx", "pageSize": 10, "begin" + time_key + "Time": "2026-11-03", "end" + time_key + "Time": "2026-11-03"}
request = urllib.request.Request(args.new_url + "/sw/" + kind + "/list?" + urllib.parse.urlencode(params), headers=headers[1])
with urllib.request.urlopen(request, timeout=60) as response:
body = json.load(response)
if body.get("code") != 0:
raise RuntimeError("读取导出样本失败:" + kind)
sample = next(row for row in body["data"]["rows"] if row.get("userId") is not None)
params["userId"] = sample["userId"]
sheets, durations = [], []
for i, base in enumerate((args.old_url, args.new_url)):
payload = urllib.parse.urlencode(params).encode()
request = urllib.request.Request(base + ("/system/" if i == 0 else "/sw/") + kind + "/export", data=payload,
headers={**headers[i], "Content-Type": "application/x-www-form-urlencoded"}, method="POST")
started = time.monotonic()
with urllib.request.urlopen(request, timeout=120) as response:
raw = response.read()
durations.append(round((time.monotonic() - started) * 1000))
if not raw.startswith(b"PK"):
raise RuntimeError("导出未返回工作簿:" + kind + "/" + str(i))
(args.runtime / (("legacy-" if i == 0 else "new-") + kind + "-export.xlsx")).write_bytes(raw)
workbook = openpyxl.load_workbook(io.BytesIO(raw), read_only=True, data_only=True)
sheets.append(list(workbook.worksheets[0].values))
workbook.close()
differences = []
for row_number, (old, new) in enumerate(zip(*sheets), 1):
if len(old) != len(new):
differences.append({"row": row_number, "kind": "columns"})
for col, (a, b) in enumerate(zip(old, new), 1):
if a == b or (a in (None, "") and b in (None, "")):
continue
if isinstance(a, (int, float)) or isinstance(b, (int, float)):
try:
if decimal.Decimal(str(a)) == decimal.Decimal(str(b)):
continue
except decimal.InvalidOperation:
pass
differences.append({"row": row_number, "column": col, "kind": "value"})
rows = [len(sheet) - 1 for sheet in sheets]
reports.append({"kind": kind, "rows": rows, "columns": [len(sheet[0]) for sheet in sheets], "elapsed_ms": durations,
"differences": differences, "passed": rows[0] > 0 and rows[0] == rows[1] and not differences})
print(json.dumps(reports[-1], ensure_ascii=False), flush=True)
args.output.write_text(json.dumps({"checks": reports, "passed": all(row["passed"] for row in reports)}, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
if not all(row["passed"] for row in reports):
raise SystemExit(1)
if __name__ == "__main__":
main()