Files
Yb-QaAutomationHub/tests/api/README.md
T
xst 52b73f456c refactor(api): yun8_sync 并入 tests 分层框架(接口层 apis/yun8 + 用例层 api + Allure)
- tests/core: 新增 BaseHttpClient 统一 HTTP 封装(直连绕行/超时/日志/自定义编码);
  db_helper 追加 Db 长连接类(事务/mogrify/自动重连),既有函数不动
- tests/apis/yun8: 21 个 step 方法按域拆分为 5 个 Mixin(driver/accounting/
  audit_payment/receipt/third_party),Yun8Pipeline 24 步编排原样迁移,
  SQL 全部参数化并集中至 sql_templates
- tests/api: 5 阶段有序 P0 E2E 用例(业务失败由 print 改为真实报错)+
  README 迁移(删除明文密码段,修正步骤编号漂移)
- yun8_sync 目录退役:配置并入 test_config.yaml 的 yun8_api 段;
  造数 CLI 保留(python -m tests.apis.yun8.cli,兼容旧 config.yaml 结构)
- pytest.ini 注册 api/yun8_sync marker;requirements.txt 补 requests>=2.28
- 静态验证: compileall / 全仓 collect 24 条 / marker 过滤 / CLI --help /
  客户端与 pipeline 离线实例化 / SQL 占位符核对 / cross_end 兼容
2026-09-08 11:38:17 +08:00

189 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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。