功能开发基本完成
This commit is contained in:
parent
36f30b85cc
commit
9a3c16d155
|
|
@ -4,39 +4,132 @@ import os
|
||||||
import shutil
|
import shutil
|
||||||
import random
|
import random
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
import requests
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
class InternalApiClient:
|
class InternalApiClient:
|
||||||
"""
|
"""
|
||||||
内部接口客户端桩代码 (Mock)
|
内部接口客户端 (Real)
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.api_url = "http://internal-system.local/api"
|
# 生产环境
|
||||||
|
# self.api_base_url = "https://hyt.86698.cn/open"
|
||||||
|
# 测试环境 (默认)
|
||||||
|
self.api_base_url = "http://120.55.12.245:8109"
|
||||||
|
|
||||||
|
# 占位符 AppId,实际需替换
|
||||||
|
# self.app_id = "8ce4d435fa77492f84d2fafa241c2804"
|
||||||
|
self.app_id = "e699e6ef74504f4d86776b3d244ce602"
|
||||||
|
|
||||||
|
def _post(self, path, data):
|
||||||
|
"""发送 POST 请求"""
|
||||||
|
url = f"{self.api_base_url}{path}"
|
||||||
|
headers = {
|
||||||
|
"AppId": self.app_id,
|
||||||
|
"Content-Type": "application/json;charset=UTF-8"
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
# 不验签模式: 直接发送 data json
|
||||||
|
# 真实场景需确认: 这里的 data 是作为 json body 发送,还是作为 params?
|
||||||
|
# 根据文档 '非加密请求: 按业务正常的请求参数进行传输' -> 通常是 json body
|
||||||
|
response = requests.post(url, json=data, headers=headers, timeout=10)
|
||||||
|
return response.json()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[API Error] {url}: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
def get_internal_product_id(self, scbank_goods_name):
|
def get_internal_product_id(self, scbank_goods_name):
|
||||||
"""
|
"""
|
||||||
Mock: 根据商城商品名查询内部商品编号
|
根据商城商品名查询内部商品编号 (Product Code)
|
||||||
|
接口: /api/v1/open/cus/goods/list
|
||||||
|
逻辑: 模糊搜索 -> 必须有且仅有1个结果 -> 返回 goods_num
|
||||||
"""
|
"""
|
||||||
# 模拟延时
|
|
||||||
time.sleep(0.1)
|
|
||||||
if not scbank_goods_name: return None
|
if not scbank_goods_name: return None
|
||||||
|
|
||||||
# 简单模拟
|
payload = {
|
||||||
if "iPhone" in scbank_goods_name: return "P_APPLE_001"
|
"title": scbank_goods_name,
|
||||||
if "华为" in scbank_goods_name: return "P_HUAWEI_002"
|
"page": 1,
|
||||||
return "P_UNKNOWN_999"
|
"limit": 10
|
||||||
|
}
|
||||||
|
|
||||||
def upload_order(self, order_detail):
|
resp = self._post("/api/v1/open/cus/goods/list", payload)
|
||||||
|
|
||||||
|
# 检查响应
|
||||||
|
if resp and resp.get("code") == 200:
|
||||||
|
data = resp.get("data", {})
|
||||||
|
# 兼容 data 可能是 list 或 dict (根据文档响应报文 data 包含 list 和 total)
|
||||||
|
# 文档: data -> {list: [], total: int}
|
||||||
|
product_list = data.get("list", [])
|
||||||
|
total = data.get("total", 0)
|
||||||
|
|
||||||
|
if product_list and len(product_list) == 1:
|
||||||
|
return product_list[0].get("goods_num")
|
||||||
|
else:
|
||||||
|
print(f"[Match Fail] '{scbank_goods_name}' 匹配到 {len(product_list)} 个商品")
|
||||||
|
return None
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def upload_order(self, order_detail, internal_pid):
|
||||||
"""
|
"""
|
||||||
Mock: 上传订单
|
上传订单
|
||||||
返回: (Success: bool, Message: str)
|
接口: /api/v1/open/order/submit
|
||||||
"""
|
"""
|
||||||
time.sleep(0.2)
|
if not internal_pid:
|
||||||
# 模拟随机成功率 90%
|
return False, "商品匹配失败: 未找到或找到多个商品"
|
||||||
if random.random() < 0.9:
|
|
||||||
|
# 映射字段
|
||||||
|
# scbank detail -> internal api payload
|
||||||
|
|
||||||
|
# 收件人信息
|
||||||
|
receive_info = order_detail.get("mallOrderReceiveInfo", {})
|
||||||
|
|
||||||
|
# 构建 payload
|
||||||
|
payload = {
|
||||||
|
"orderBasic": {
|
||||||
|
"customer_order_num": order_detail.get("orderNo"),
|
||||||
|
"consignee": receive_info.get("receiverName", "未知"),
|
||||||
|
"consignee_mobile": receive_info.get("receiverMobile", "00000000000"),
|
||||||
|
|
||||||
|
# 省市区编码 (文档必填但用户说是误写,传空或默认值)
|
||||||
|
"consignee_province_code": "",
|
||||||
|
"consignee_city_code": "",
|
||||||
|
"consignee_area_code": "",
|
||||||
|
|
||||||
|
# 详细地址 (用户要求使用完整地址)
|
||||||
|
"consignee_address": receive_info.get("fullAddress", ""),
|
||||||
|
|
||||||
|
# 客户备注 - 没找到,传空
|
||||||
|
"in_remark": receive_info.get("remark", ""),
|
||||||
|
},
|
||||||
|
"goodsList": [
|
||||||
|
{
|
||||||
|
"goods_num": internal_pid,
|
||||||
|
"number": 1, # 默认为 1,需确认 scbank 数据是否有数量
|
||||||
|
"sale_price": order_detail.get("orderAmt", 0) # 暂用订单总额作为单价
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
# 修正数量与价格: 如果有 goodsInfoList,尝试获取更准确的数量
|
||||||
|
goods_info = order_detail.get("goodsInfoList", [])
|
||||||
|
if goods_info:
|
||||||
|
first_good = goods_info[0]
|
||||||
|
payload["goodsList"][0]["number"] = first_good.get("count", 1)
|
||||||
|
payload["goodsList"][0]["sale_price"] = first_good.get("price", 0)
|
||||||
|
|
||||||
|
# 查看 payload
|
||||||
|
print("=== 上传订单 Payload ===")
|
||||||
|
print(json.dumps(payload, ensure_ascii=False, indent=2))
|
||||||
|
print("=== 上传订单 Payload End ===")
|
||||||
|
|
||||||
|
resp = self._post("/api/v1/open/order/submit", payload)
|
||||||
|
|
||||||
|
if resp and resp.get("code") == 200:
|
||||||
return True, "上传成功"
|
return True, "上传成功"
|
||||||
else:
|
else:
|
||||||
return False, "模拟网络超时"
|
msg = resp.get("message") if resp else "请求失败"
|
||||||
|
return False, f"API错误: {msg}"
|
||||||
|
|
||||||
class SCBankProcessor:
|
class SCBankProcessor:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
@ -81,37 +174,49 @@ class SCBankProcessor:
|
||||||
self.log("文件内容为空,跳过")
|
self.log("文件内容为空,跳过")
|
||||||
return
|
return
|
||||||
|
|
||||||
# 3. 数据结构化
|
# 3. 数据结构化 (合并列表与详情)
|
||||||
# 提取详情数据 (以此为主)
|
|
||||||
details = []
|
|
||||||
for r in raw_records:
|
|
||||||
if r.get("type") == "detail":
|
|
||||||
payload = r.get("payload", {})
|
|
||||||
# 根据真实数据结构: payload -> body -> orderNo
|
|
||||||
body = payload.get("body", {})
|
|
||||||
if body and "orderNo" in str(body):
|
|
||||||
# 如果 body 是字符串,尝试解析
|
|
||||||
if isinstance(body, str):
|
|
||||||
try: body = json.loads(body)
|
|
||||||
except: pass
|
|
||||||
|
|
||||||
details.append(body)
|
|
||||||
|
|
||||||
# 去重 (按 orderNo)
|
|
||||||
# 注意:这里假设 payload 是 dict,如果已经是 dict 则直接用
|
|
||||||
# 如果是字符串则需要 json.loads
|
|
||||||
unique_details = {}
|
unique_details = {}
|
||||||
for d in details:
|
|
||||||
# 兼容 payload 可能是字符串的情况 (虽然 Collector 存的是 dict)
|
for r in raw_records:
|
||||||
if isinstance(d, str):
|
r_type = r.get("type")
|
||||||
try: d = json.loads(d)
|
payload = r.get("payload", {})
|
||||||
|
body = payload.get("body", {})
|
||||||
|
|
||||||
|
# 兼容 body 可能是字符串的情况
|
||||||
|
if isinstance(body, str):
|
||||||
|
try: body = json.loads(body)
|
||||||
except: continue
|
except: continue
|
||||||
|
|
||||||
order_no = d.get("orderNo") or d.get("orderId")
|
if not isinstance(body, dict): continue
|
||||||
if order_no:
|
|
||||||
unique_details[order_no] = d
|
|
||||||
|
|
||||||
self.log(f"解析出 {len(unique_details)} 条有效唯一订单详情")
|
if r_type == "list":
|
||||||
|
page_list = body.get("pageDataList", [])
|
||||||
|
if isinstance(page_list, list):
|
||||||
|
for item in page_list:
|
||||||
|
order_no = item.get("orderNo")
|
||||||
|
if not order_no: continue
|
||||||
|
|
||||||
|
if order_no not in unique_details:
|
||||||
|
unique_details[order_no] = item
|
||||||
|
else:
|
||||||
|
# 列表数据补全:仅当字段缺失或为空时填充
|
||||||
|
for k, v in item.items():
|
||||||
|
# 列表中的 goodsInfoList 通常为空,跳过
|
||||||
|
if k == "goodsInfoList" and not v: continue
|
||||||
|
if k not in unique_details[order_no] or not unique_details[order_no][k]:
|
||||||
|
unique_details[order_no][k] = v
|
||||||
|
|
||||||
|
elif r_type == "detail":
|
||||||
|
order_no = body.get("orderNo")
|
||||||
|
if not order_no: continue
|
||||||
|
|
||||||
|
if order_no not in unique_details:
|
||||||
|
unique_details[order_no] = body
|
||||||
|
else:
|
||||||
|
# 详情数据覆盖 (高优先级)
|
||||||
|
unique_details[order_no].update(body)
|
||||||
|
|
||||||
|
self.log(f"解析出 {len(unique_details)} 条唯一订单 (列表+详情合并)")
|
||||||
|
|
||||||
# 4. 业务处理与同步
|
# 4. 业务处理与同步
|
||||||
results = []
|
results = []
|
||||||
|
|
@ -127,7 +232,8 @@ class SCBankProcessor:
|
||||||
internal_pid = self.client.get_internal_product_id(goods_name)
|
internal_pid = self.client.get_internal_product_id(goods_name)
|
||||||
|
|
||||||
# Step 2: 上传
|
# Step 2: 上传
|
||||||
success, msg = self.client.upload_order(detail)
|
# 注意: 这里传入 internal_pid
|
||||||
|
success, msg = self.client.upload_order(detail, internal_pid)
|
||||||
|
|
||||||
# 时间格式化: 2026-03-10T00:50:37.000+0000 -> 2026-03-10 00:50:37
|
# 时间格式化: 2026-03-10T00:50:37.000+0000 -> 2026-03-10 00:50:37
|
||||||
order_time = detail.get("orderCreateTime")
|
order_time = detail.get("orderCreateTime")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue