# yun8 运输流程 API 造数(接口自动化) 将 `yun8.postman_collection.json` 中 **"运输流程"** 全部 18 个接口 + SQL 写入实现为 pytest 用例 + 造数 CLI,与 `tests/` 框架分层对齐(`apis/` 接口层 ≙ `pages/` PO 层)。 > ⚠️ 本套件会**真实调用测试环境接口并写入数据库**(造运单、打款、回单、ETC 发票), > 使用 `yun8_sync` marker 隔离,不会混入默认冒烟扫描。 --- ## 分层结构 ``` tests/ ├── apis/yun8/ # 接口层(≙ pages/ PO 层) │ ├── client.py # Yun8ApiClient 门面: 司机/管理/滇运通 3 套会话 │ ├── driver_api.py # step01-05 司机端接口 │ ├── accounting_api.py # step06-09 运费核算 │ ├── audit_payment_api.py # step10-16 审核 & 付款 │ ├── receipt_api.py # step17-20 回单/上报 │ ├── third_party_api.py # step21 滇运通(独立 host/token) │ ├── sql_templates.py # 全部 SQL(参数化,%s 占位) │ ├── pipeline.py # Yun8Pipeline 24 步编排(Postman 变量上下文) │ └── cli.py # 造数 CLI(python -m tests.apis.yun8.cli) ├── api/ # 用例层 │ ├── conftest.py # yun8_config / yun8_db / yun8_pipeline fixtures │ └── test_yun8_transport_flow.py # P0 E2E: 5 个有序阶段用例 └── config/test_config.yaml # yun8_api 配置段(数据库复用 database 段) ``` --- ## 流程概览 ``` ┌─────────────────────────────────────────────────────────────────┐ │ 阶段 A: 司机端 (Step 01-05) │ │ 查询货源 → 接单 → 查询待运输单 → 装货 → 卸货 │ │ 变量: mainOrderCode → code / vehicleCode / orderCode │ ├─────────────────────────────────────────────────────────────────┤ │ 阶段 B: 运费核算 (Step 06-09) │ │ 查询运单 → 运单详情 → 核算试算 → 核算提交 │ │ 变量: 30+ 核算字段 + ticketImageUrls │ ├─────────────────────────────────────────────────────────────────┤ │ 阶段 C: 审核 & 付款 (Step 10-16) │ │ 查询审核 → 审核通过 → 队长分账(可选) → 油卡充值 → 司机打款 → 货主打款│ ├─────────────────────────────────────────────────────────────────┤ │ 阶段 D: 回单文件 + SQL (Step 17-21) │ │ 运单上传(payNo) → 打款记录 → 文件名前缀 → INSERT → 上报运单 │ ├─────────────────────────────────────────────────────────────────┤ │ 阶段 E: ETC 开票 SQL (Step 22-24) │ │ 写入 base_etc_invoice (多条) → 写入 tms_order_etc_push │ │ → 更新 tms_order_detail 开票状态 │ └─────────────────────────────────────────────────────────────────┘ ``` ### 上下游变量传递 | 步骤 | 产出变量 | 消费步骤 | |------|---------|---------| | 01 查询货源 | `mainOrderCode`, `residueNumber` | 02, 09 | | 03 查询待运输单 | `code`, `vehicleCode`, `orderCode` | 04-24 | | 06 运费核算 | 30+ 字段 (branchCode, oilFee, ...) | 09, 12 | | 07 运单详情 | `deliveryCashFee`, `driverActualFreight`, ... | 09, 15 | | 08 核算试算 | `ticketImageUrls` | 09 | | 17 运单上传 | `payNo` (sendMsg 正则提取) | SQL | | 18 打款记录 | 所有 `code` | 19 | | 19 文件名前缀 | `filePrefix` | SQL | --- ## 使用 ### pytest 用例(5 阶段有序 E2E,带 Allure 报告与断言) ```bash # 完整流程(5 个阶段用例,前置失败自动 skip 后续) pytest tests/api -m yun8_sync -v # 生成 Allure 报告 allure generate output/allure-results -o output/allure-report --clean ``` 阶段与用例对应: A 司机端 / B 运费核算 / C 审核付款 / D 回单+SQL / E ETC 开票。 `execute_after_audit=false` 时 D、E 阶段自动 skip。 ### 造数 CLI(循环造数 / 分阶段运行) ```bash # 完整流程 python -m tests.apis.yun8.cli --auth-driver "Bearer xxx" --auth-admin "Bearer yyy" # 仅司机端 (Step 01-05) / 仅核算 (06-09) / 仅审核付款 (10-16) / 仅回单+SQL+上报 (17-24) python -m tests.apis.yun8.cli --stage driver python -m tests.apis.yun8.cli --stage accounting python -m tests.apis.yun8.cli --stage payment python -m tests.apis.yun8.cli --stage receipt # 循环执行 10 次,每次间隔 5 秒 python -m tests.apis.yun8.cli --repeat 10 --delay 5 # 仅 receipt 阶段循环 100 次 python -m tests.apis.yun8.cli --stage receipt --repeat 100 --delay 2 # 预览 SQL 不写库(配合 random 重量模式,每次自动换新重量) python -m tests.apis.yun8.cli --dry-run python -m tests.apis.yun8.cli --repeat 5 --dry-run ``` > ⚠️ **`--dry-run` 不是只读模式**:仅跳过回单/ETC 的 SQL 写入(打印 mogrify 渲染的 > SQL),HTTP 步骤仍真实执行,driver 阶段的 reset SQL 也不受 dry-run 影响。 > 独立运行 `payment` 或 `receipt` 阶段时,会自动从 admin 端补全前置数据 > (code/orderCode),无需手动指定。 ### 配置 统一在 `tests/config/test_config.yaml` 的 **`yun8_api:`** 段维护: - `tokens`: 司机端/管理端 Bearer Token(CLI `--auth-driver` / `--auth-admin` 可覆盖) - `driver_params`: 重量模式(`fixed` 固定值 / `random` 每次随机 1.0~10.0)、 装卸货经纬度覆盖、待运输单重置、装卸货照片 URL - `accounting`: 核算固定参数 + `execute_after_audit`(是否执行 12-21 步) - `payment`: 打款参数;`etc_invoice`: ETC 发票条数 - `dianyuntong.enabled`: 滇运通审核开关(默认关闭) > `branchCode` / `businessTypeCode` / `payeeCode` / `shipmentPhone` / > `shipmentPartyCode` 优先从 step06 返回值读取,配置仅作兜底。 --- ## 故障处理 | 现象 | 处理方式 | |------|---------| | WAF 拦截 (SQL注入误判) | 已内置:直连服务器(trust_env=False)+ 手工 query string 编码 | | "运单正被处理中" | 已内置:自动重试 5 次,间隔递增 5~13s | | "货运单不存在" | Token 过期或运单状态不对,检查 admin token | | 业务 code≠0 | **会直接失败**(迁移后行为):CLI 计入失败循环,pytest 用例 RED | | 提取不到 payNo | **会直接失败**(迁移后行为):不再写空 front_seq_no 的脏行 | | 独立阶段提示 code 为空 | 已内置:自动从 admin 端补全 | | 日志 | `output/logs/test_run_*.log`(DEBUG 全量 URL,含 WAF 排查线索) | --- ## 接口对照表 (Step 编号与 `tests/apis/yun8` 代码中的 stepNN 方法一一对应) | Step | 名称 | 方法 | 路径 | Auth | |------|------|------|------|------| | 01 | 查询货源 | GET | `/ntocc-tms-api/order/orderHallList` | Driver | | 02 | 接单 | POST | `/ntocc-tms-api/orderDetail/receive` | Driver | | 03 | 查询待运输单 | GET | `/ntocc-tms-api/orderDetail` | Driver | | 04 | 装货 | PUT | `/ntocc-tms-api/orderDetail/fill` | Driver | | 05 | 卸货 | PUT | `/ntocc-tms-api/orderDetail/uploadTicketImage` | Driver | | 06 | 运费核算查询运单 | GET | `/ntocc-tms-api/orderDetail/orderDetailHandlePageList` | Admin | | 07 | 查询运单详情 | POST | `/ntocc-tms-api/orderDetail/getOrderDetailExpensesParamList` | Admin | | 08 | 核算试算 | PUT | `/ntocc-tms-api/orderDetail/calculateOrderDetail` | Admin | | 09 | 核算提交 | PUT | `/ntocc-tms-api/orderDetail/orderHandleEditSubmitHandle` | Admin | | 10 | 查询运单审核 | GET | `/ntocc-tms-api/orderDetail` (status=6&isSettle=1) | Admin | | 11 | 核算审核通过 | POST | `/ntocc-tms-api/orderDetail/auditOrderDetail` | Admin | | 12 | 队长分账预览 | GET | `/ntocc-tms-api/orderDetail/captainSplitAdjustPreview/{code}` | Admin | | 13 | 队长分账调整 | POST | `/ntocc-tms-api/orderDetail/adjustCaptainSplit` | Admin | | 14 | 单油卡充值 | POST | `/ntocc-tms-api/finance/singleOil` | Admin | | 15 | 垫资-财务打款 | POST | `/ntocc-tms-api/arpaTransfer/payToDriver` | Admin | | 16 | 垫资-货主打款 | POST | `/ntocc-tms-api/orderDetail/applicationForPayment` | Admin | | 17 | 查询运单上传(提取 payNo) | GET | `/ntocc-basic-api/dytBusiness/orderDetail` (status=5) | Admin | | 18 | 查询打款记录 | GET | `/ntocc-tms-api/remitDefinite` | Admin | | 19 | 查询文件名前缀 | GET | `/ntocc-tms-api/centralizedPayment/downLoadElectronicReceipt` | Admin | | 20 | 上报运单 | POST | `/ntocc-basic-api/dytBusiness/reportOrderDetail` | Admin | | 21 | 滇运通审核 | POST | `https://yndyt.cxtech.vip/ntocc-tms-api/orderDetail/updateOrderDetailExt` | 滇运通 | | — | 回单 SQL INSERT | — | `ntocc.base_gd_mft_file` | — | | 22 | ETC 开票信息写入 | SQL INSERT | `ntocc.base_etc_invoice` | — | | 23 | ETC 推送记录写入 | SQL INSERT | `ntocc.tms_order_etc_push` | — | | 24 | 运单 ETC 开票状态更新 | SQL UPDATE | `ntocc.tms_order_detail` | — | > 步骤 22 每个运单插入 `etc_invoice.count` 条发票(config.yaml 配置,默认 3),每条的 > **发票号码**(随机 20 位数字)、**金额**(随机分配,**所有发票合计 ≤ 运费×50%**,运费 > 优先取 `driverActualFreight`、缺失时取 `shipmentActualFreight`,超限或运费未知则跳过 > 发票写入)、**进站/出站**(按广东→河北路段链取相邻两站)、**时间**(交易时间在运单窗口 > 内逐条推进)各不相同;税额、开票方、发票类型、URL 等其余字段用固定值。 > 步骤 22/23 的 `order_code`/`order_no` 取步骤 03 的 `orderCode`,`push_order_no` 为其后 > 追加 `-1`,`order_detail_code` 取步骤 03 的 `code`,两个表的 `code` 按现有数据规则 > (32 位十六进制)自动生成,随 receipt 阶段执行(`--dry-run` 仅预览不写库)。 > 步骤 23 的推送记录固定写入 `invoice_pull_status=2`、`start_status=1`、`end_status=1`、 > `start_result='成功'`、`end_result='成功'`;步骤 24 将步骤 03 `orderCode` 对应运单的 > `etc_invoice_status` 置为 3。