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 兼容
This commit is contained in:
xst
2026-09-08 11:38:17 +08:00
parent e62e3224bf
commit 52b73f456c
26 changed files with 2147 additions and 1786 deletions
+142
View File
@@ -0,0 +1,142 @@
"""回单/上报接口 Mixin — step17-20(管理端)。
所有方法签名/返回值/默认值与旧 yun8_sync/client.py 逐字一致,
仅将原始 requests.Session 调用替换为 BaseHttpClient(self.admin_http)。
Usage:
from tests.apis.yun8.receipt_api import ReceiptApi
class Yun8ApiClient(ReceiptApi, ...): ...
"""
import re
class ReceiptApi:
"""回单/上报接口(挂载于 Yun8ApiClient,依赖 admin_http / ac 属性)。"""
# ==================================================================
# Step 17: 查询运单上传 → 提取 payNo
# ==================================================================
def step17_query_upload_for_payno(self, order_code: str,
page_size: int = 20, page_num: int = 1) -> dict:
"""
Postman Test Script:
var sendMsg = jsonData.data.records[0].sendMsg || "";
var match = sendMsg.match(/【([^】]+)】/);
var result = match ? match[1] : "";
pm.collectionVariables.set("payNo", result);
Returns: {"payNo": str, "raw_records": list}
"""
params = {
"gmtCreatedRange[]": ["", ""],
"lastLoadingTimeRange": "",
"fillTimeRange": "",
"lastUnloadingTimeRange": "",
"signTimeRange": "",
"settleTimeRange": "",
"gmtModifiedRange": "",
"pageNum": page_num,
"pageSize": page_size,
"status": "5", # <-- 注意:status=5
"payerReceiverLinkMan": self.ac.get("payer_receiver_link_man", ""),
"sortField": "",
"sortType": "",
"gmtCreatedStart": "",
"gmtCreatedEnd": "",
"orderCode": order_code,
}
data = self.admin_http.get("/ntocc-basic-api/dytBusiness/orderDetail", params)
records = data.get("data", {}).get("records", [])
pay_no = ""
if records:
send_msg = records[0].get("sendMsg", "")
match = re.search(r"【([^】]+)】", send_msg)
if match:
pay_no = match.group(1)
return {"payNo": pay_no, "raw_records": records}
# ==================================================================
# Step 18: 查询打款记录 → 提取所有 code
# ==================================================================
def step18_query_remit_records(self, order_code: str,
page_size: int = 20) -> list[dict]:
"""
Postman Test Script:
pm.collectionVariables.set("remitCode", jsonData.data.records[0].code);
分页获取全部打款记录。Returns: [{code, ...}, ...]
"""
all_records = []
page_num = 1
while True:
params = {
"pageNum": page_num,
"pageSize": page_size,
"pageForm": "arpa_2",
"orderDetailNumber": order_code,
"sortField": "",
"sortType": "",
"isPayAdvance": "",
"platPayType": "",
"gmtModifiedStart": "",
"gmtModifiedEnd": "",
}
data = self.admin_http.get("/ntocc-tms-api/remitDefinite", params)
# code 可能是 0 (成功) 或 None/null (也是成功)
resp_code = data.get("code")
if resp_code is not None and resp_code != 0:
raise RuntimeError(f"查询打款记录失败: {data.get('msg')}")
page_data = data.get("data", {})
records = page_data.get("records", [])
all_records.extend(records)
total = page_data.get("total", 0)
if page_num * page_size >= total:
break
page_num += 1
return all_records
# ==================================================================
# Step 19: 查询文件名前缀 → 提取 filePrefix
# ==================================================================
def step19_query_file_prefix(self, remit_code: str) -> str:
"""
Postman Test Script:
const msg = jsonData.msg || '';
const prefix = '文件名前缀:';
const index = msg.indexOf(prefix);
const filePrefix = index !== -1 ? msg.substring(index + prefix.length).trim() : '';
pm.collectionVariables.set('filePrefix', filePrefix);
Returns: filePrefix string
"""
params = {"code": remit_code}
data = self.admin_http.get(
"/ntocc-tms-api/centralizedPayment/downLoadElectronicReceipt",
params)
msg = data.get("msg", "")
prefix_marker = "文件名前缀:"
idx = msg.find(prefix_marker)
if idx != -1:
return msg[idx + len(prefix_marker):].strip()
return ""
# ==================================================================
# Step 20: 上报运单 (reportOrderDetail)
# ==================================================================
def step20_report_order_detail(self, codes: str, report_type: int = 1) -> dict:
"""
POST /ntocc-basic-api/dytBusiness/reportOrderDetail
Content-Type: application/json;charset=UTF-8
Body: {"codes": "...", "type": 1}
在打款完成后上报运单,完成整个流程闭环。
"""
body = {"codes": codes, "type": report_type}
return self.admin_http.post_json(
"/ntocc-basic-api/dytBusiness/reportOrderDetail", body)