from __future__ import annotations import json import logging import time from datetime import datetime from yuxi.channel.extensions.pinduoduo.types import InboundPddMessage from yuxi.channel.message.models import MessageType, PeerInfo, UnifiedMessage from yuxi.channel.routing.models import PeerKind logger = logging.getLogger(__name__) class PinduoduoMonitor: def __init__(self, mall_id: str, account_id: str): self._mall_id = mall_id self._account_id = account_id def to_unified_message(self, msg: InboundPddMessage) -> UnifiedMessage: content = msg.content or "" msg_type = MessageType.TEXT if msg.msg_type == "1": msg_type = MessageType.IMAGE elif msg.msg_type == "2": try: data = json.loads(content) goods_id = data.get("goods_id", data.get("id", "")) content = f"[商品卡片] 商品ID: {goods_id}" except json.JSONDecodeError: pass elif msg.msg_type == "3": try: data = json.loads(content) order_sn = data.get("order_sn", data.get("id", "")) content = f"[订单卡片] 订单号: {order_sn}" except json.JSONDecodeError: pass elif msg.msg_type == "4": try: data = json.loads(content) coupon_id = data.get("coupon_id", data.get("id", "")) content = f"[优惠券卡片] 优惠券ID: {coupon_id}" except json.JSONDecodeError: pass return UnifiedMessage( msg_id=msg.msg_id, channel_type="pinduoduo", account_id=self._account_id, content=content, sender=PeerInfo( kind=PeerKind.DIRECT, id=msg.buyer_id, display_name=msg.buyer_nickname or f"买家{msg.buyer_id[-6:]}", ), message_type=msg_type, group=None, body_for_agent=content, raw_payload=msg.raw_payload, metadata={ "mall_id": msg.mall_id, "session_id": msg.session_id, "pdd_msg_type": msg.msg_type, "buyer_id": msg.buyer_id, }, ) @staticmethod def parse_poll_response(data: dict, mall_id: str) -> list[InboundPddMessage]: messages = [] msg_list = data.get("logistics_cs_message_list", []) if not isinstance(msg_list, list): return messages for item in msg_list: messages.append( InboundPddMessage( msg_id=str(item.get("id", "")), mall_id=str(item.get("mall_id", mall_id)), buyer_id=str(item.get("from_user", "")), session_id=str(item.get("session_id", "")), msg_type=str(item.get("message_type", "0")), content=str(item.get("content", "")), create_time=_parse_time(item.get("send_time")), raw_payload=item, ) ) return messages @staticmethod def parse_push_event(data: dict) -> list[InboundPddMessage]: messages = [] event_type = data.get("event_type", "") event_data = data.get("data", {}) if event_type == "cs_message": messages.append( InboundPddMessage( msg_id=str(event_data.get("id", "")), mall_id=str(event_data.get("mall_id", "")), buyer_id=str(event_data.get("from_user", "")), session_id=str(event_data.get("session_id", "")), msg_type=str(event_data.get("message_type", "0")), content=str(event_data.get("content", "")), create_time=datetime.now(), raw_payload=event_data, ) ) elif event_type == "cs_session_start": buyer_id = str(event_data.get("from_user", "")) session_id = str(event_data.get("session_id", "")) logger.info( "Session started: mall_id=%s, buyer=%s, session=%s", event_data.get("mall_id"), buyer_id, session_id, ) messages.append( InboundPddMessage( msg_id=f"cs_session_start-{int(time.time())}", mall_id=str(event_data.get("mall_id", "")), buyer_id=buyer_id, session_id=session_id, msg_type="0", content="[系统通知] 买家进入客服会话", create_time=datetime.now(), raw_payload=data, ) ) elif event_type.startswith("order_") or event_type.startswith("refund_"): content = PinduoduoMonitor._format_business_event(event_type, event_data) messages.append( InboundPddMessage( msg_id=f"{event_type}-{int(time.time())}", mall_id=str(event_data.get("mall_id", "")), buyer_id=str(event_data.get("buyer_id", "")), session_id=str(event_data.get("session_id", "")), msg_type="0", content=content, create_time=datetime.now(), raw_payload=data, ) ) return messages @staticmethod def _format_business_event(event_type: str, event_data: dict) -> str: title_map = { "order_create": "订单创建", "order_paid": "订单支付成功", "order_shipped": "订单已发货", "order_delivered": "订单已签收", "order_cancel": "订单已取消", "refund_apply": "买家申请退款", "refund_agree": "退款已同意", "refund_refuse": "退款已拒绝", "refund_success": "退款成功", "refund_cancel": "退款关闭", } title = title_map.get(event_type, event_type) order_sn = event_data.get("order_sn", event_data.get("order_id", "未知")) if "order_sn" in event_data: return f"[系统通知] {title} - 订单号: {order_sn}" return f"[系统通知] {title}" def _parse_time(time_str: str | None) -> datetime | None: if not time_str: return None try: return datetime.strptime(time_str, "%Y-%m-%d %H:%M:%S") except ValueError: return None