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).
179 lines
6.2 KiB
Python
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()
|