新增京东(JD)渠道扩展,支持在 Yuxi 平台中集成京东客服渠道。 包含以下功能模块: - client: 京东 API 客户端封装 - config: 渠道配置管理 - gateway: SSE/WebSocket 网关接入 - webhook: Webhook 事件处理 - outbound: 外发消息管理 - pairing: 用户配对与绑定 - security: 安全校验 - signature: 请求签名验证 - crypto: 加解密处理 - dedupe: 消息去重 - monitor: 渠道状态监控 - status: 会话状态管理 - session: 会话管理 - business: 业务逻辑处理 - types: 类型定义
201 lines
9.0 KiB
Python
201 lines
9.0 KiB
Python
import logging
|
|
|
|
from yuxi.channel.extensions.jd.client import JOSClient
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class JDBusiness:
|
|
def __init__(self, client: JOSClient, shop_id: str):
|
|
self._client = client
|
|
self._shop_id = shop_id
|
|
|
|
async def query_order(
|
|
self,
|
|
order_id: str | None = None,
|
|
start_time: str | None = None,
|
|
end_time: str | None = None,
|
|
page: int = 1,
|
|
page_size: int = 10,
|
|
access_token: str = "",
|
|
) -> dict:
|
|
biz_params = {
|
|
"optional_fields": "orderInfo",
|
|
"page": str(page),
|
|
"page_size": str(page_size),
|
|
}
|
|
if order_id:
|
|
biz_params["order_id"] = order_id
|
|
if start_time:
|
|
biz_params["start_date"] = start_time
|
|
if end_time:
|
|
biz_params["end_date"] = end_time
|
|
|
|
try:
|
|
data = await self._client.call("jingdong.pop.order.search", biz_params, access_token)
|
|
return {"success": True, "data": self._flatten_order_result(data)}
|
|
except Exception as e:
|
|
logger.error("JD order query failed: %s", e)
|
|
return {"success": False, "error": str(e)}
|
|
|
|
async def get_order_detail(self, order_id: str, access_token: str = "") -> dict:
|
|
biz_params = {
|
|
"order_id": order_id,
|
|
"optional_fields": "orderInfo,paymentInfo,consigneeInfo",
|
|
}
|
|
try:
|
|
data = await self._client.call("jingdong.pop.order.get", biz_params, access_token)
|
|
return {"success": True, "data": self._flatten_order_detail(data)}
|
|
except Exception as e:
|
|
logger.error("JD order detail failed: %s", e)
|
|
return {"success": False, "error": str(e)}
|
|
|
|
async def query_logistics(self, order_id: str, access_token: str = "") -> dict:
|
|
biz_params = {"order_id": order_id}
|
|
|
|
try:
|
|
data = await self._client.call("jingdong.etms.trace.get", biz_params, access_token)
|
|
trace_result = data.get("jingdong_etms_trace_get_responce", {}).get("traceResult", {})
|
|
traces = trace_result.get("traceList", []) if isinstance(trace_result, dict) else []
|
|
return {
|
|
"success": True,
|
|
"data": {
|
|
"order_id": order_id,
|
|
"waybill_code": trace_result.get("waybillCode", ""),
|
|
"traces": traces,
|
|
},
|
|
}
|
|
except Exception as e:
|
|
logger.error("JD logistics query failed: %s", e)
|
|
return {"success": False, "error": str(e)}
|
|
|
|
async def query_product(self, sku_id: str, access_token: str = "") -> dict:
|
|
biz_params = {
|
|
"sku": sku_id,
|
|
"queryExts": "warebase,wareimage",
|
|
}
|
|
|
|
try:
|
|
data = await self._client.call("jingdong.ware.product.get", biz_params, access_token)
|
|
ware_result = data.get("jingdong_ware_product_get_responce", {}).get("product", {})
|
|
if isinstance(ware_result, dict):
|
|
return {
|
|
"success": True,
|
|
"data": {
|
|
"sku_id": ware_result.get("sku", ""),
|
|
"name": ware_result.get("name", ""),
|
|
"brand_name": ware_result.get("brandName", ""),
|
|
"category": ware_result.get("category", ""),
|
|
"introduction": ware_result.get("introduction", ""),
|
|
"weight": ware_result.get("weight", ""),
|
|
"sale_date": ware_result.get("saleDate", ""),
|
|
"upc": ware_result.get("upc", ""),
|
|
"image_url": ware_result.get("imageUrl", ""),
|
|
},
|
|
}
|
|
return {"success": False, "error": "未找到商品信息"}
|
|
except Exception as e:
|
|
logger.error("JD product query failed: %s", e)
|
|
return {"success": False, "error": str(e)}
|
|
|
|
async def query_product_price(self, sku_ids: list[str], access_token: str = "") -> dict:
|
|
biz_params = {"sku": ",".join(sku_ids)}
|
|
|
|
try:
|
|
data = await self._client.call("jingdong.ware.price.get", biz_params, access_token)
|
|
price_list = data.get("jingdong_ware_price_get_responce", {}).get("priceList", [])
|
|
return {"success": True, "data": price_list}
|
|
except Exception as e:
|
|
logger.error("JD product price query failed: %s", e)
|
|
return {"success": False, "error": str(e)}
|
|
|
|
async def query_refund(self, order_id: str, access_token: str = "") -> dict:
|
|
biz_params = {"order_id": order_id}
|
|
try:
|
|
data = await self._client.call("jingdong.pop.afs.soa.refundapply.get", biz_params, access_token)
|
|
result = data.get("jingdong_pop_afs_soa_refundapply_get_responce", {}).get("queryResult", {})
|
|
return {"success": True, "data": result}
|
|
except Exception as e:
|
|
logger.error("JD refund query failed: %s", e)
|
|
return {"success": False, "error": str(e)}
|
|
|
|
async def set_cs_status(self, status: str, access_token: str = "") -> dict:
|
|
biz_params = {"status": status}
|
|
try:
|
|
await self._client.call("jingdong.im.setStatus", biz_params, access_token)
|
|
return {"success": True, "status": status}
|
|
except Exception as e:
|
|
logger.error("JD set cs status failed: %s", e)
|
|
return {"success": False, "error": str(e)}
|
|
|
|
async def get_cs_status(self, access_token: str = "") -> dict:
|
|
try:
|
|
data = await self._client.call("jingdong.im.getStatus", {}, access_token)
|
|
return {"success": True, "data": data}
|
|
except Exception as e:
|
|
logger.error("JD get cs status failed: %s", e)
|
|
return {"success": False, "error": str(e)}
|
|
|
|
async def get_user_info(self, user_id: str, access_token: str = "") -> dict:
|
|
biz_params = {"user_id": user_id}
|
|
|
|
try:
|
|
data = await self._client.call("jingdong.im.getUserInfo", biz_params, access_token)
|
|
user_info = data.get("jingdong_im_getUserInfo_responce", {}).get("result", {})
|
|
return {"success": True, "data": user_info if isinstance(user_info, dict) else {}}
|
|
except Exception as e:
|
|
logger.error("JD get user info failed: %s", e)
|
|
return {"success": False, "error": str(e)}
|
|
|
|
async def query_comments(self, sku_id: str, page: int = 1, page_size: int = 10, access_token: str = "") -> dict:
|
|
biz_params = {"sku": sku_id, "page": str(page), "pageSize": str(page_size)}
|
|
|
|
try:
|
|
data = await self._client.call("jingdong.comment.products.get", biz_params, access_token)
|
|
result = data.get("jingdong_comment_products_get_responce", {}).get("result", {})
|
|
return {"success": True, "data": result}
|
|
except Exception as e:
|
|
logger.error("JD comment query failed: %s", e)
|
|
return {"success": False, "error": str(e)}
|
|
|
|
async def evaluate_cs(self, chat_id: str, score: int, access_token: str = "") -> dict:
|
|
biz_params = {"chat_id": chat_id, "score": str(score)}
|
|
try:
|
|
await self._client.call("jingdong.im.evaluate", biz_params, access_token)
|
|
return {"success": True, "score": score}
|
|
except Exception as e:
|
|
logger.error("JD evaluate cs failed: %s", e)
|
|
return {"success": False, "error": str(e)}
|
|
|
|
def _flatten_order_result(self, data: dict) -> list[dict]:
|
|
result = data.get("jingdong_pop_order_search_responce", {}).get("searchorderinforesult", {})
|
|
order_list = result.get("orderInfoList", [])
|
|
if isinstance(order_list, dict):
|
|
order_list = [order_list]
|
|
return [
|
|
{
|
|
"order_id": o.get("orderId", ""),
|
|
"order_state": o.get("orderState", ""),
|
|
"order_total_price": o.get("orderTotalPrice", ""),
|
|
"order_create_time": o.get("orderCreateTime", ""),
|
|
"order_payment_time": o.get("orderPaymentTime", ""),
|
|
}
|
|
for o in order_list
|
|
]
|
|
|
|
def _flatten_order_detail(self, data: dict) -> dict:
|
|
result = data.get("jingdong_pop_order_get_responce", {}).get("orderDetailInfo", {})
|
|
order_info = result.get("orderInfo", {}) if isinstance(result, dict) else {}
|
|
return {
|
|
"order_id": order_info.get("orderId", ""),
|
|
"order_state": order_info.get("orderState", ""),
|
|
"order_total_price": order_info.get("orderTotalPrice", ""),
|
|
"freight_price": order_info.get("freightPrice", ""),
|
|
"seller_discount": order_info.get("sellerDiscount", ""),
|
|
"order_create_time": order_info.get("orderCreateTime", ""),
|
|
"order_payment_time": order_info.get("orderPaymentTime", ""),
|
|
"consignee_name": order_info.get("consigneeInfo", {}).get("fullname", ""),
|
|
"consignee_mobile": order_info.get("consigneeInfo", {}).get("mobile", ""),
|
|
"consignee_address": order_info.get("consigneeInfo", {}).get("fullAddress", ""),
|
|
}
|