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

174 lines
7.4 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 — step10-16(管理端)。
所有方法签名/返回值/默认值与旧 yun8_sync/client.py 逐字一致,
仅将原始 requests.Session 调用替换为 BaseHttpClient(self.admin_http)。
Usage:
from tests.apis.yun8.audit_payment_api import AuditPaymentApi
class Yun8ApiClient(AuditPaymentApi, ...): ...
"""
import math
class AuditPaymentApi:
"""审核 & 付款接口(挂载于 Yun8ApiClient,依赖 admin_http / ac / pm 属性)。"""
# ==================================================================
# Step 10: 查询运单审核
# ==================================================================
def step10_query_audit(self, order_code: str,
page_size: int = 20, page_num: int = 1) -> dict:
"""
GET /ntocc-tms-api/orderDetail (status=6 已结算, isSettle=1)
Admin 端查询已结算运单用于审核。
"""
params = {
"isAbnormalHelp": "",
"gmtCreatedRange": "",
"lastLoadingTimeRange": "",
"fillTimeRange": "",
"lastUnloadingTimeRange": "",
"signTimeRange": "",
"settleTimeRange": "",
"gmtModifiedRange": "",
"pageNum": page_num,
"pageSize": page_size,
"isSettle": "1",
"status": "6",
"payerReceiverLinkMan": self.ac.get("payer_receiver_link_man", ""),
"sortField": "",
"sortType": "",
"orderCode": order_code,
}
return self.admin_http.get("/ntocc-tms-api/orderDetail", params)
# ==================================================================
# Step 11: 核算审核通过
# ==================================================================
def step11_approve_audit(self, code: str) -> dict:
"""
POST /ntocc-tms-api/orderDetail/auditOrderDetail?orderDetailCodes={code}&isPass=true
"""
params = {"orderDetailCodes": code, "isPass": "true"}
return self.admin_http.request_with_encoded_query(
"POST", "/ntocc-tms-api/orderDetail/auditOrderDetail", params=params)
# ==================================================================
# Step 12: 队长分账预览 (captainSplitAdjustPreview)
# ==================================================================
def step12_captain_split_preview(self, order_detail_code: str) -> dict:
"""
GET /ntocc-tms-api/orderDetail/captainSplitAdjustPreview/{code}
仅在 payerReceiver 不为空且 captainSplitMode=2 时调用。
"""
path = f"/ntocc-tms-api/orderDetail/captainSplitAdjustPreview/{order_detail_code}"
return self.admin_http.get(path)
# Step 13: 队长分账调整 (adjustCaptainSplit)
# ==================================================================
def step13_adjust_captain_split(self, order_detail_code: str,
latest_driver_amount: float,
delivery_oil_fee: float) -> dict:
"""
POST /ntocc-tms-api/orderDetail/adjustCaptainSplit
Content-Type: application/json;charset=UTF-8
driverAmount = ceil(latestDriverAmount * 0.8 * 100) / 100
captainAmount = latestDriverAmount - driverAmount
oilFee = deliveryOilFee
"""
driver_amount = math.ceil(latest_driver_amount * 0.8 * 100) / 100.0
captain_amount = round(latest_driver_amount - driver_amount, 2)
body = {
"orderDetailCode": order_detail_code,
"driverAmount": str(driver_amount),
"captainAmount": str(captain_amount),
"oilFee": delivery_oil_fee,
}
return self.admin_http.post_json(
"/ntocc-tms-api/orderDetail/adjustCaptainSplit", body)
# Step 14: 单油卡充值 (singleOil)
# ==================================================================
def step14_single_oil(self, order_detail_code: str, amount: str = "0.03",
pay_type: str = "1", category: str = "1") -> dict:
"""
POST /ntocc-tms-api/finance/singleOil
Query params: payType, amount, orderDetailCode, category, isAdvancePayment
No body (content-length: 0)
在垫资-财务打款之前调用,处理油卡充值。
"""
params = {
"payType": pay_type,
"amount": amount,
"orderDetailCode": order_detail_code,
"category": category,
"isAdvancePayment": "1",
}
return self.admin_http.request_with_encoded_query(
"POST", "/ntocc-tms-api/finance/singleOil", params=params)
# ==================================================================
# Step 15: 垫资-财务打款
# ==================================================================
def step15_pay_to_driver(self, code: str, amount: str = None,
delivery_cash_fee: str = None,
driver_actual_freight: str = None,
plan_driver_payout: str = "0",
plan_captain_payout: str = "0") -> dict:
"""
POST /ntocc-tms-api/arpaTransfer/payToDriver
amount / deliveryCashFee / driverActualFreight 由 pipeline 从 step07 传入
planDriverPayout / planCaptainPayout 来自队长分账步骤,无分账时为 "0"
"""
if amount is None:
amount = "0.27"
if delivery_cash_fee is None:
delivery_cash_fee = "0.27"
if driver_actual_freight is None:
driver_actual_freight = "0.3"
params = {
"payTypes": self.pm.get("pay_types", "3,4,5,9,10,11"),
"amount": amount,
"orderDetailCode": code,
"infoFee": "0",
"pageNum": "1",
"pageSize": "20",
"totaltotal": "0",
"payerRole": "0",
"isAdvancePayment": "1",
"planDriverPayout": plan_driver_payout,
"planCaptainPayout": plan_captain_payout,
"allotAmount": "0",
"deliveryCashFee": delivery_cash_fee,
"driverActualFreight": driver_actual_freight,
"total": "0",
"payPlatform": self.pm.get("pay_platform", "3"),
"smsCode": self.pm.get("sms_code", "1234"),
"phone": self.pm.get("phone", "13888888888"),
}
return self.admin_http.request_with_encoded_query(
"POST", "/ntocc-tms-api/arpaTransfer/payToDriver", params=params)
# ==================================================================
# Step 16: 垫资-货主打款 (申请付款)
# ==================================================================
def step16_apply_for_payment(self, code: str, total_amount: str = None) -> dict:
"""
POST /ntocc-tms-api/orderDetail/applicationForPayment
totalAmount 应从 pipeline 传入 (step06 的 shipmentActualCash)
"""
if total_amount is None:
total_amount = "0.32"
params = {
"payType": self.pm.get("pay_type", "arpa_2"),
"totalAmount": total_amount,
"codes": code,
"payPlatform": self.pm.get("pay_platform", "3"),
"isAdvancePayment": "1",
}
return self.admin_http.request_with_encoded_query(
"POST", "/ntocc-tms-api/orderDetail/applicationForPayment", params=params)