Files
QaAutomationHub/yun8_sync/main.py
T
xst 73b93bdf0c feat(yun8_sync): add API pipeline automating full freight flow (18 interfaces + SQL)
Implements the "运输流程" collection from yun8.postman_collection.json as a
Python pipeline: driver-side order accept/load/unload -> freight accounting
-> payment, with SQL writes, driven by yun8_sync/config.yaml
(api/auth/accounting/payment/database/sql/dianyuntong sections).
2026-08-17 14:30:40 +08:00

179 lines
6.2 KiB
Python

#!/usr/bin/env python3
"""
yun8 运输流程完整自动化
=======================
将 Postman Collection (yun8.postman_collection.json) 中
"运输流程" 全部 17 个接口 + SQL 写入实现为 Python 流水线。
阶段 A — 司机端 (步骤 1-5) 查询货源→接单→待运输→装货→卸货
阶段 B — 运费核算 (步骤 6-9) 查询→详情→试算→提交核算
阶段 C — 审核 & 付款 (步骤 10-16) 查询审核→审核通过→司机打款→货主打款
阶段 D — 回单文件 + SQL (步骤 14-16) payNo→打款记录→文件名前缀→INSERT
阶段 E — 上报运单 (步骤 17) reportOrderDetail
用法:
# 完整流程
python main.py --auth-driver "Bearer xxx" --auth-admin "Bearer yyy"
# 仅跑特定阶段
python main.py --stage driver --auth-driver "Bearer xxx" --auth-admin "Bearer yyy"
# 循环执行 10 次,间隔 3 秒
python main.py --repeat 10 --delay 3
# 预览 SQL 不写库
python main.py --dry-run
"""
import argparse
import sys
import time
import traceback
from datetime import datetime
from pathlib import Path
import yaml
from pipeline import Pipeline
def load_config(path: str | Path) -> dict:
with open(path, "r", encoding="utf-8") as fh:
return yaml.safe_load(fh)
STAGE_HELP = """阶段选择:
all 完整流程 (默认): 司机端 → 核算 → 付款 → 回单SQL → 上报
driver 仅司机端 (步骤 1-5)
accounting 仅运费核算 (步骤 6-9)
payment 仅审核付款 (步骤 10-16)
receipt 仅回单文件+SQL+上报 (步骤 14-17)
"""
def run_one_cycle(config: dict, stage: str, driver_token: str,
admin_token: str, dry_run: bool) -> bool:
"""执行一次完整流水线,返回 True 表示成功"""
pipe = Pipeline(config)
pipe.set_auth(driver_token, admin_token)
if stage in ("all", "driver"):
pipe.run_driver_flow()
# reset_order_detail 模式:仅跑司机端,跳过后续全部步骤
dp = config.get("driver_params", {})
if dp.get("reset_order_detail", False):
print(f"\n [stop] reset_order_detail=true,跳过步骤 06-21")
return True
if stage in ("all", "accounting"):
pipe.run_accounting_flow()
if stage in ("all", "payment"):
pipe.run_audit_payment_flow()
ac = config.get("accounting", {})
if ac.get("execute_after_audit", True):
if stage in ("all", "receipt"):
pipe.run_receipt_file_flow(dry_run=dry_run)
# ETC 开票 SQL 写入 (步骤 22-23)
if stage in ("all", "receipt"):
pipe.run_etc_invoice_flow(dry_run=dry_run)
else:
if stage in ("all", "receipt"):
print(f"\n [stop] execute_after_audit=false,跳过 receipt 阶段")
return True
def main():
parser = argparse.ArgumentParser(
description="yun8 运输流程完整自动化",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=STAGE_HELP,
)
parser.add_argument("--config", default=None,
help="配置文件路径 (默认: 脚本同目录下 config.yaml)")
parser.add_argument("--auth-driver", default="",
help="司机端 Bearer Token (含 'Bearer ' 前缀)")
parser.add_argument("--auth-admin", default="",
help="管理端 Bearer Token (含 'Bearer ' 前缀)")
parser.add_argument("--stage", default="all",
choices=["all", "driver", "accounting", "payment", "receipt"],
help="运行阶段 (默认: all)")
parser.add_argument("--dry-run", action="store_true",
help="仅预览 SQL,不实际写入数据库")
parser.add_argument("--repeat", type=int, default=1,
help="循环执行次数 (默认: 1)")
parser.add_argument("--delay", type=int, default=0,
help="每次循环之间的等待秒数 (默认: 0)")
args = parser.parse_args()
# 加载配置
config_path = args.config or (Path(__file__).parent / "config.yaml")
config = load_config(config_path)
# 读取 Token
driver_token = args.auth_driver or config.get("auth", {}).get("driver_token", "")
admin_token = args.auth_admin or config.get("auth", {}).get("admin_token", "")
print("=" * 60)
print(f" yun8 运输流程自动化")
print(f" config: {config_path}")
print(f" stage: {args.stage}")
print(f" dry-run: {args.dry_run}")
print(f" repeat: {args.repeat}")
print(f" delay: {args.delay}s")
print(f" 开始时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print("=" * 60)
ok_count = 0
fail_count = 0
cycle_start = time.time()
for i in range(1, args.repeat + 1):
if args.repeat > 1:
print(f"\n{'#' * 60}")
print(f"# 第 {i}/{args.repeat} 次循环")
print(f"# 时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print(f"{'#' * 60}")
try:
run_one_cycle(config, args.stage, driver_token,
admin_token, args.dry_run)
ok_count += 1
if args.repeat > 1:
print(f"\n--- 第 {i}/{args.repeat} 次循环: 成功 ---")
except KeyboardInterrupt:
print(f"\n 用户中断,已执行 {i-1} 次")
fail_count += (args.repeat - i + 1)
break
except Exception as exc:
fail_count += 1
print(f"\n--- 第 {i}/{args.repeat} 次循环: 失败 ---")
print(f" 错误: {exc}")
traceback.print_exc()
# 失败后继续下一次(不中断循环)
# 循环间隔
if i < args.repeat and args.delay > 0:
print(f" 等待 {args.delay}s 后进入下一次循环...")
time.sleep(args.delay)
# 汇总
elapsed = time.time() - cycle_start
print(f"\n{'=' * 60}")
print(f" 全部循环完成")
print(f" 成功: {ok_count} 失败: {fail_count} 总计: {args.repeat}")
print(f" 耗时: {elapsed:.0f}s")
print(f" 结束时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print(f"{'=' * 60}")
if fail_count > 0:
sys.exit(1)
if __name__ == "__main__":
main()