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:
@@ -0,0 +1,337 @@
|
||||
"""运费核算接口 Mixin — step06-09(管理端,含 ~190 字段核算提交报文)。
|
||||
|
||||
所有方法签名/返回值/默认值与旧 yun8_sync/client.py 逐字一致,
|
||||
仅将原始 requests.Session 调用替换为 BaseHttpClient(self.admin_http)。
|
||||
|
||||
Usage:
|
||||
from tests.apis.yun8.accounting_api import AccountingApi
|
||||
class Yun8ApiClient(AccountingApi, ...): ...
|
||||
"""
|
||||
|
||||
|
||||
class AccountingApi:
|
||||
"""运费核算接口(挂载于 Yun8ApiClient,依赖 admin_http / ac / dp 属性)。"""
|
||||
|
||||
# ==================================================================
|
||||
# Step 06: 运费核算查询运单
|
||||
# ==================================================================
|
||||
def step06_query_for_accounting(self, order_code: str,
|
||||
page_size: int = 20, page_num: int = 1) -> dict:
|
||||
"""
|
||||
Postman Test Script: 设置 30+ 个 collection variables
|
||||
从 data.records[0] 中提取所有字段
|
||||
|
||||
Returns: dict with all fields from records[0]
|
||||
"""
|
||||
params = {
|
||||
"status": "3",
|
||||
"lastLoadingTimeRange": "",
|
||||
"fillTimeRange": "",
|
||||
"lastUnloadingTimeRange": "",
|
||||
"signTimeRange": "",
|
||||
"gmtModifiedRange": "",
|
||||
"rangeValue_start_1": "",
|
||||
"rangeValue_end_1": "",
|
||||
"rangeValue_start_2": "",
|
||||
"rangeValue_end_2": "",
|
||||
"rangeValue_start_3": "",
|
||||
"rangeValue_end_3": "",
|
||||
"pageNum": page_num,
|
||||
"pageSize": page_size,
|
||||
"gmtCreatedStart": "",
|
||||
"gmtCreatedEnd": "",
|
||||
"lastUnloadingTimeStart": "",
|
||||
"lastUnloadingTimeEnd": "",
|
||||
"lastLoadingTimeStart": "",
|
||||
"lastLoadingTimeEnd": "",
|
||||
"gmtModifiedStart": "",
|
||||
"gmtModifiedEnd": "",
|
||||
"fillTimeStart": "",
|
||||
"fillTimeEnd": "",
|
||||
"signTimeStart": "",
|
||||
"signTimeEnd": "",
|
||||
"ordCreatedByName": "",
|
||||
"isUnloadingConfirm": "1",
|
||||
"isCannotAccounting": "0",
|
||||
"riskControlStatus": "",
|
||||
"riskControlReason": "",
|
||||
"sortField": "",
|
||||
"sortType": "",
|
||||
"orderCode": order_code,
|
||||
}
|
||||
data = self.admin_http.get("/ntocc-tms-api/orderDetail/orderDetailHandlePageList", params)
|
||||
records = data.get("data", {}).get("records", [])
|
||||
if not records:
|
||||
raise RuntimeError("运费核算查询运单: 无记录返回")
|
||||
return records[0]
|
||||
|
||||
# ==================================================================
|
||||
# Step 07: 查询运单详情
|
||||
# ==================================================================
|
||||
def step07_query_order_expenses(self, code: str) -> dict:
|
||||
"""
|
||||
Postman Test Script:
|
||||
pm.collectionVariables.set("canWastage", ...);
|
||||
pm.collectionVariables.set("deliveryCashFee", ...);
|
||||
pm.collectionVariables.set("deliveryFeeDeserved", ...);
|
||||
pm.collectionVariables.set("deliveryFeePractical", ...);
|
||||
pm.collectionVariables.set("driverActualCash", ...);
|
||||
pm.collectionVariables.set("driverActualFreight", ...);
|
||||
|
||||
Returns: {canWastage, deliveryCashFee, deliveryFeeDeserved,
|
||||
deliveryFeePractical, driverActualCash, driverActualFreight}
|
||||
"""
|
||||
params = {"codes": code}
|
||||
data = self.admin_http.post(
|
||||
"/ntocc-tms-api/orderDetail/getOrderDetailExpensesParamList",
|
||||
params=params)
|
||||
items = data.get("data", [])
|
||||
if not items:
|
||||
raise RuntimeError("查询运单详情: 无数据返回")
|
||||
r = items[0]
|
||||
return {
|
||||
"canWastage": str(r.get("canWastage", "")),
|
||||
"deliveryCashFee": str(r.get("deliveryCashFee", "")),
|
||||
"deliveryFeeDeserved": str(r.get("deliveryFeeDeserved", "")),
|
||||
"deliveryFeePractical": str(r.get("deliveryFeePractical", "")),
|
||||
"driverActualCash": str(r.get("driverActualCash", "")),
|
||||
"driverActualFreight": str(r.get("driverActualFreight", "")),
|
||||
}
|
||||
|
||||
# ==================================================================
|
||||
# Step 08: 核算试算 (calculateOrderDetail)
|
||||
# ==================================================================
|
||||
def step08_calculate_order_detail(self, code: str) -> dict:
|
||||
"""
|
||||
Postman Test Script:
|
||||
pm.collectionVariables.set("ticketImageUrls[]", jsonData.data.ticketImageUrls);
|
||||
|
||||
Returns: dict with ticketImageUrls + 其他 step08 返回的核算数据 (taxPrice 等)
|
||||
"""
|
||||
params = {"code": code, "isFirst": "1"}
|
||||
data = self.admin_http.put("/ntocc-tms-api/orderDetail/calculateOrderDetail", params=params)
|
||||
inner = data.get("data", {}) or {}
|
||||
ticket_urls = inner.get("ticketImageUrls", "")
|
||||
if isinstance(ticket_urls, list):
|
||||
ticket_urls = ticket_urls[0] if ticket_urls else ""
|
||||
# 返回所有有用字段,供 pipeline 存入 vars
|
||||
result = {"ticketImageUrls": str(ticket_urls)}
|
||||
for key in ("taxPrice", "taxFee", "taxPayFee", "taxPoint",
|
||||
"price", "realPrice", "shipmentActualCash",
|
||||
"shipmentActualFreight"):
|
||||
if key in inner:
|
||||
result[key] = str(inner[key])
|
||||
return result
|
||||
|
||||
# ==================================================================
|
||||
# Step 09: 核算提交
|
||||
# ==================================================================
|
||||
def step09_submit_accounting(self, accounting_vars: dict) -> dict:
|
||||
"""
|
||||
提交核算,参数来自前面步骤累积的所有变量。
|
||||
accounting_vars 应包含 steps 03/06/07/08 的全部字段。
|
||||
优先从 step06 返回值取值,取不到再用 config.yaml 默认值。
|
||||
"""
|
||||
av = accounting_vars
|
||||
# 便捷取值:vars 优先 → config 兜底
|
||||
def _v(key, cfg_key, default=""):
|
||||
return av.get(key) or self.ac.get(cfg_key, default)
|
||||
|
||||
# Build the massive query string
|
||||
params = {
|
||||
"abnormalFee": "0",
|
||||
"accountCheckAuthStatus": "0",
|
||||
"accountCheckInfoAuthStatus": "0",
|
||||
"accountCheckUpAuthStatus": "0",
|
||||
"accountStatus": "0",
|
||||
"allTrans": "0",
|
||||
"allotAmount": "0",
|
||||
"allotOil": "0",
|
||||
"allotTaxAmount": "0",
|
||||
"appSendLoadLocation": "0",
|
||||
"appSendUnloadLocation": "0",
|
||||
"applyStatus": "0",
|
||||
"branchCode": _v("branchCode", "branch_code"),
|
||||
"businessTypeCode": _v("businessTypeCode", "business_type_code"),
|
||||
"canWastage": av.get("canWastage", ""),
|
||||
"cancelTrans": "0",
|
||||
"cancelType": "0",
|
||||
"captainSplitCurrentVersion": "0",
|
||||
"captainSplitMode": self.ac.get("captain_split_mode") or av.get("captainSplitMode", ""),
|
||||
"cashDeposit": "0",
|
||||
"coalName": "",
|
||||
"coalPrice": av.get("coalPrice", ""),
|
||||
"coalType": av.get("coalType", ""),
|
||||
"coalTypeName": av.get("coalTypeName", ""),
|
||||
"coalUnit": "0",
|
||||
"coalUnitName": av.get("coalUnitName", ""),
|
||||
"code": av.get("code", ""),
|
||||
"contractStatus": "1",
|
||||
"createdBy": av.get("createdBy", ""),
|
||||
"createdByName": av.get("createdByName", ""),
|
||||
"deleted": "0",
|
||||
"deliveryCashFee": av.get("deliveryCashFee", ""),
|
||||
"deliveryFeeDeserved": av.get("deliveryFeeDeserved", ""),
|
||||
"deliveryFeePractical": av.get("deliveryFeePractical", ""),
|
||||
"deliveryOilFee": "0",
|
||||
"distance": av.get("distance", ""),
|
||||
"driverActualCash": av.get("driverActualCash", ""),
|
||||
"driverActualFreight": av.get("driverActualFreight", ""),
|
||||
"driverCode": av.get("driverCode", ""),
|
||||
"driverName": av.get("driverName", ""),
|
||||
"driverPhone": av.get("driverPhone", ""),
|
||||
"energyCardType": av.get("energyCardType", ""),
|
||||
"etcType": "0",
|
||||
"extraFee": "0",
|
||||
"fillTime": av.get("fillTime", ""),
|
||||
"finishedTrans": "0",
|
||||
"gmtCreated": av.get("gmtCreated", ""),
|
||||
"gmtModified": av.get("gmtModified", ""),
|
||||
"id": av.get("id", ""),
|
||||
"inFee": "0",
|
||||
"infoFee": "0",
|
||||
"insuranceAmount": "0",
|
||||
"insuranceFee": "0",
|
||||
"invoiceIsAll": "0",
|
||||
"invoiceStatus": "0",
|
||||
"invoiceStatusCaptain": "0",
|
||||
"invoiceStatusDriver": "0",
|
||||
"isAbnormal": "0",
|
||||
"isCancel": "0",
|
||||
"isCaptainOrder": "0",
|
||||
"isCash": "0",
|
||||
"isCuikuan": "0",
|
||||
"isDriverComment": "0",
|
||||
"isEqualDriver": "1",
|
||||
"isEqualTeam": "1",
|
||||
"isEqualVehicle": "1",
|
||||
"isEtcHistory": "0",
|
||||
"isFill": "1",
|
||||
"isImport": "0",
|
||||
"isInsure": "0",
|
||||
"isLoadingConfirm": "1",
|
||||
"isLoadingConfirmDate": av.get("isLoadingConfirmDate", ""),
|
||||
"isOriginalOrder": "1",
|
||||
"isPaperReturns": "0",
|
||||
"isReceiptReturn": "0",
|
||||
"isReportOrder": "0",
|
||||
"isSend": "0",
|
||||
"isSendDishonestyVehicle": "0",
|
||||
"isSendFund": "0",
|
||||
"isSendFundZhongLian": "0",
|
||||
"isSendLoadLocation": "0",
|
||||
"isSendTax": "0",
|
||||
"isSendUnloadLocation": "0",
|
||||
"isSendZhongLian": "0",
|
||||
"isSettle": "0",
|
||||
"isShipmentComment": "0",
|
||||
"isSign": "1",
|
||||
"isSplitOrder": "0",
|
||||
"isSupplementary": "0",
|
||||
"isTransfer": "0",
|
||||
"isTrunkName": av.get("isTrunkName", ""),
|
||||
"isUnloadingComfirmDate": av.get("isUnloadingComfirmDate", ""),
|
||||
"isUnloadingConfirm": "1",
|
||||
"isWsShare": "0",
|
||||
"loadImgUrls[]": av.get("ticketImageUrls", ""),
|
||||
"loadLatitude": av.get("loadLatitude", ""),
|
||||
"loadLongitude": av.get("loadLongitude", ""),
|
||||
"loadPlace": av.get("loadPlace", ""),
|
||||
"loadQuantity": av.get("loadQuantity", ""),
|
||||
"loadWeight": av.get("loadWeight", "1"),
|
||||
"mainOrderCode": av.get("mainOrderCode", ""),
|
||||
"modifiedBy": av.get("modifiedBy", ""),
|
||||
"modifiedByName": av.get("modifiedByName", ""),
|
||||
"monthlySettlementStatus": "0",
|
||||
"oilFee": av.get("oilFee", ""),
|
||||
"onTrans": "0",
|
||||
"orderCode": av.get("orderCode", ""),
|
||||
"payAmount": "0",
|
||||
"payOil": "0",
|
||||
"payStatus": "0",
|
||||
"payStep": "10",
|
||||
"payTaxAmount": "0",
|
||||
"payTotalAmount": av.get("payTotalAmount", ""),
|
||||
"payType": "0",
|
||||
"payeeCode": _v("createdBy", "payee_code"), # step06 createdBy = payeeCode
|
||||
"payeeName": av.get("payeeName", ""),
|
||||
"payerReceiver": self.ac.get("payer_receiver", ""),
|
||||
"payerReceiverLinkMan": self.ac.get("payer_receiver_link_man", ""),
|
||||
"platformPrepayment": "0",
|
||||
"prepaidStatus": "0",
|
||||
"price": av.get("price", ""),
|
||||
"proofAmount": "0",
|
||||
"proofStatus": "0",
|
||||
"realPrice": av.get("realPrice", ""),
|
||||
"receiptNum": "",
|
||||
"receiptPayAmount": "0",
|
||||
"refuelProportion": "0",
|
||||
"reportMark": "0",
|
||||
"reportStage": "0",
|
||||
"settlementCash": "0",
|
||||
"settlementOil": "0",
|
||||
"settlementType": self.ac.get("settlement_type", "2"),
|
||||
"settlementWeight": av.get("settlementWeight", "1"),
|
||||
"shipmentActualCash": av.get("shipmentActualCash", ""),
|
||||
"shipmentActualFreight": av.get("shipmentActualFreight", ""),
|
||||
"shipmentCardScale": "10",
|
||||
"shipmentDeliveryFeePractical": av.get("shipmentDeliveryFeePractical", ""),
|
||||
"shipmentName": av.get("shipmentName", ""),
|
||||
"shipmentPayStatus": "0",
|
||||
"shipmentPhone": _v("shipmentPhone", "shipment_phone"),
|
||||
"shipperDeliveryFee": av.get("shipperDeliveryFee", ""),
|
||||
"shippingNoteNumber": av.get("shippingNoteNumber", ""),
|
||||
"signTime": av.get("signTime", ""),
|
||||
"status": "3",
|
||||
"takeLatitude": av.get("takeLatitude", ""),
|
||||
"takeLongitude": av.get("takeLongitude", ""),
|
||||
"takeOrderType": "2",
|
||||
"takePlace": av.get("takePlace", ""),
|
||||
"taxFee": av.get("taxFee", ""),
|
||||
"taxPayFee": av.get("taxPayFee", ""),
|
||||
"taxPrice": av.get("taxPrice", ""),
|
||||
"ticketImageUrls[]": av.get("ticketImageUrls", ""),
|
||||
"txStatus": "0",
|
||||
"unloadLatitude": self.dp.get("latitude", ""),
|
||||
"unloadLongitude": self.dp.get("longitude", ""),
|
||||
"unloadPlace": av.get("unloadPlace", ""),
|
||||
"unloadQuantity": av.get("unloadQuantity", ""),
|
||||
"unloadWeight": av.get("unloadWeight", "1"),
|
||||
"vehicleCode": av.get("vehicleCode", ""),
|
||||
"vehicleLicense": av.get("vehicleLicense", ""),
|
||||
"waitCar": "0",
|
||||
"waitCheckTrans": "0",
|
||||
"waitDriverCheckTrans": "0",
|
||||
"waitPay": "0",
|
||||
"waitSettle": "0",
|
||||
"waitTrans": "0",
|
||||
"wastage": "0",
|
||||
"weight": av.get("weight", "1"),
|
||||
"whetherOverload": "0",
|
||||
"wsShareRatio": "0",
|
||||
"deductionFee": "0",
|
||||
"driverErase": "0",
|
||||
"driverFixedPay": "0",
|
||||
"driverSettlementWeight": av.get("driverSettlementWeight", "1"),
|
||||
"electricityCardScale": "10",
|
||||
"gasCardScale": "10",
|
||||
"isTrunk": "0",
|
||||
"limitWastageAmount": "500",
|
||||
"limitWastageType": "1",
|
||||
"shipmentErase": "0",
|
||||
"shipmentPartyCode": _v("shipmentPartyCode", "shipment_party_code"),
|
||||
"shipmentSettlementWeight": av.get("shipmentSettlementWeight", "1"),
|
||||
"shipperFixedPay": "0",
|
||||
"taxPoint": av.get("taxPoint", ""),
|
||||
"taxPriceFixedPay": "0",
|
||||
"orderExtraFeeListStr": "[]",
|
||||
"BranchCode": _v("branchCode", "branch_code"),
|
||||
"unloadImgaes": av.get("ticketImageUrls", ""),
|
||||
"truckLoadingImgaes": av.get("ticketImageUrls", ""),
|
||||
"IsTaxPoint": "0",
|
||||
"RealPrice": av.get("realPrice", ""),
|
||||
"gmtCreated2": av.get("gmtCreated", ""),
|
||||
"gmtModified2": av.get("gmtModified", ""),
|
||||
}
|
||||
return self.admin_http.request_with_encoded_query(
|
||||
"PUT", "/ntocc-tms-api/orderDetail/orderHandleEditSubmitHandle", params=params)
|
||||
Reference in New Issue
Block a user