Files
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

143 lines
5.5 KiB
Python
Raw Permalink 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.
"""回单/上报接口 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)