- 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 兼容
338 lines
14 KiB
Python
338 lines
14 KiB
Python
"""运费核算接口 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)
|