聊天配对群组ID与准备接口:打手商家同群、订单卡片推送
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -7,7 +7,7 @@ from .views import CreateOrderView, WechatPayNotifyView, \
|
||||
ShangjiaChexiaoView, DashouDingdanHuoquView, ShangpinLeixingHuoquView, QiangdanView, \
|
||||
DashouDingdanHuoquView1, DashouCOSZhengshuView, DashouTijiaoView, DashouDingdanXiangqingView, AdGetDingdanXiangQing, \
|
||||
AdTongYiTuiKuanPingTai, AdTongYiTuiKuanShangJia, AdQiangZhiJieDan, AdJuJueTuiKuan,\
|
||||
AdGengHuanDaShou,ShangjiaCOSZhengshuView, DashouHuoquLeixingView,AdJuJueJieSuan, AdZhuanYiDaTing, AdQuXiaoZhiDing,PartnerNotifyClaimView, PartnerSyncOrderView, PartnerCheckClaimView, PartnerRefundNotifyView,DashouXiugaiView,VirtualCreateOrderView, VirtualPayNotifyView, VirtualPaymentVerifyView,VirtualPaymentFailView,DaiLiQunLiaoXiaoXiView,\
|
||||
AdGengHuanDaShou,ShangjiaCOSZhengshuView, DashouHuoquLeixingView,AdJuJueJieSuan, AdZhuanYiDaTing, AdQuXiaoZhiDing,PartnerNotifyClaimView, PartnerSyncOrderView, PartnerCheckClaimView, PartnerRefundNotifyView,DashouXiugaiView,VirtualCreateOrderView, VirtualPayNotifyView, VirtualPaymentVerifyView,VirtualPaymentFailView,DaiLiQunLiaoXiaoXiView,DingdanLiaotianZhunbeiView,\
|
||||
ShangjiaLianjieLiuYanZhuanFaView, ZxsjghdsView, \
|
||||
ShangjiaFakuanApplyView, ShangjiaFakuaiXiugaiView
|
||||
|
||||
@@ -78,6 +78,7 @@ urlpatterns = [
|
||||
path('dsxiugaidd', DashouXiugaiView.as_view(), name='打手修改订单详情'),
|
||||
|
||||
path('kptxxfs', DaiLiQunLiaoXiaoXiView.as_view(), name='前端聊天转发'), # 群聊消息代理发送
|
||||
path('ltdhzb', DingdanLiaotianZhunbeiView.as_view(), name='订单聊天准备'),
|
||||
|
||||
|
||||
path('virtual_xiadan', VirtualCreateOrderView.as_view(),name='虚拟支付下单'),
|
||||
|
||||
@@ -4421,7 +4421,10 @@ from rest_framework import status, permissions
|
||||
from .models import Dingdan, DingdanPingtai, DingdanShangjia
|
||||
from yonghu.models import UserMain, UserDashou, UserBoss, UserShangjia
|
||||
from peizhi.models import ClubConfig
|
||||
from utils.chat_utils import _send_group_message, _subscribe_users_to_group
|
||||
from utils.chat_utils import (
|
||||
_send_group_message, _subscribe_users_to_group,
|
||||
resolve_group_id_for_order, prepare_order_group_chat,
|
||||
)
|
||||
|
||||
logger = logging.getLogger('dingdan')
|
||||
|
||||
@@ -4593,6 +4596,44 @@ def get_partner_club_config(partner_club_id):
|
||||
|
||||
# ----------------- 主视图 -----------------
|
||||
|
||||
class DingdanLiaotianZhunbeiView(APIView):
|
||||
"""订单详情进入聊天前:确保配对群订阅并返回 groupId"""
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
|
||||
def post(self, request):
|
||||
dingdan_id = request.data.get('dingdan_id') or request.data.get('orderId')
|
||||
identity_type = request.data.get('identityType')
|
||||
push_order_card = request.data.get('push_order_card', True)
|
||||
if isinstance(push_order_card, str):
|
||||
push_order_card = push_order_card.lower() in ('1', 'true', 'yes')
|
||||
|
||||
if not dingdan_id:
|
||||
return Response({'code': 400, 'msg': '缺少 dingdan_id'})
|
||||
if not identity_type:
|
||||
return Response({'code': 400, 'msg': '缺少 identityType'})
|
||||
if identity_type not in ('dashou', 'shangjia', 'boss'):
|
||||
return Response({'code': 400, 'msg': 'identityType 无效'})
|
||||
|
||||
uid = request.user.yonghuid
|
||||
try:
|
||||
order = Dingdan.objects.select_related('pingtai_kuozhan', 'shangjia_kuozhan').get(dingdan_id=dingdan_id)
|
||||
except Dingdan.DoesNotExist:
|
||||
return Response({'code': 404, 'msg': '订单不存在'})
|
||||
|
||||
valid, err_msg = check_user_permission(identity_type, uid, order)
|
||||
if not valid:
|
||||
return Response({'code': 403, 'msg': err_msg})
|
||||
|
||||
prefix_map = {'dashou': 'Ds', 'shangjia': 'Sj', 'boss': 'Boss'}
|
||||
caller_goeasy_id = prefix_map[identity_type] + uid
|
||||
|
||||
result = prepare_order_group_chat(dingdan_id, caller_goeasy_id, push_order_card=push_order_card)
|
||||
if not result:
|
||||
return Response({'code': 500, 'msg': '准备群聊失败,请稍后重试'})
|
||||
|
||||
return Response({'code': 0, 'msg': 'ok', 'data': result})
|
||||
|
||||
|
||||
class DaiLiQunLiaoXiaoXiView(APIView):
|
||||
"""
|
||||
代理发送群聊消息
|
||||
@@ -4648,7 +4689,7 @@ class DaiLiQunLiaoXiaoXiView(APIView):
|
||||
return Response({'code': 500, 'msg': '系统配置错误(APPKEY)'})
|
||||
|
||||
# ===== 6. 公共群信息 =====
|
||||
real_group_id = f"group_{order.dingdan_id}"
|
||||
real_group_id = resolve_group_id_for_order(order)
|
||||
group_name = (order.jieshao[:20] + '…') if order.jieshao and len(order.jieshao) > 20 else f"订单{order.dingdan_id}"
|
||||
sender_avatar = full_avatar(sender_avatar_raw) if sender_avatar_raw else full_avatar('')
|
||||
|
||||
|
||||
@@ -10,6 +10,65 @@ from yonghu.models import UserMain, UserDashou, UserBoss, UserShangjia
|
||||
|
||||
logger = logging.getLogger('chat_utils')
|
||||
|
||||
ORDER_CARD_PREFIX = '[ORDER_CARD]'
|
||||
|
||||
|
||||
def make_dashou_shangjia_group_id(dashou_yonghuid, shangjia_yonghuid):
|
||||
return f"group_Ds{dashou_yonghuid}_Sj{shangjia_yonghuid}"
|
||||
|
||||
|
||||
def make_dashou_boss_group_id(dashou_yonghuid, boss_yonghuid):
|
||||
return f"group_Ds{dashou_yonghuid}_Boss{boss_yonghuid}"
|
||||
|
||||
|
||||
def _get_shangjia_id_from_order(order):
|
||||
try:
|
||||
return order.shangjia_kuozhan.shangjia_id
|
||||
except Exception:
|
||||
ext = DingdanShangjia.objects.filter(dingdan__dingdan_id=order.dingdan_id).first()
|
||||
return ext.shangjia_id if ext else None
|
||||
|
||||
|
||||
def _get_boss_id_from_order(order):
|
||||
try:
|
||||
return order.pingtai_kuozhan.laoban_id
|
||||
except Exception:
|
||||
ext = DingdanPingtai.objects.filter(dingdan__dingdan_id=order.dingdan_id).first()
|
||||
return ext.laoban_id if ext else None
|
||||
|
||||
|
||||
def resolve_group_id_for_order(order, dashou_yonghuid=None):
|
||||
"""打手+商家/老板配对群 ID;跨平台或缺信息时回退订单群 ID"""
|
||||
dashou_yonghuid = dashou_yonghuid or order.jiedan_dashou_id
|
||||
if order.is_cross == 1 and order.dispatch_type == 2:
|
||||
return f"group_{order.dingdan_id}"
|
||||
if not dashou_yonghuid:
|
||||
return f"group_{order.dingdan_id}"
|
||||
if order.fadan_pingtai == 2:
|
||||
shangjia_id = _get_shangjia_id_from_order(order)
|
||||
if shangjia_id:
|
||||
return make_dashou_shangjia_group_id(dashou_yonghuid, shangjia_id)
|
||||
elif order.fadan_pingtai == 1:
|
||||
boss_id = _get_boss_id_from_order(order)
|
||||
if boss_id:
|
||||
return make_dashou_boss_group_id(dashou_yonghuid, boss_id)
|
||||
return f"group_{order.dingdan_id}"
|
||||
|
||||
|
||||
def _build_order_card_text(order):
|
||||
payload = {
|
||||
'dingdan_id': order.dingdan_id,
|
||||
'jieshao': order.jieshao or '',
|
||||
'beizhu': order.beizhu or '',
|
||||
'jine': str(order.jine),
|
||||
'zhuangtai': order.zhuangtai,
|
||||
'nicheng': order.nicheng or '',
|
||||
}
|
||||
if order.create_time:
|
||||
payload['create_time'] = order.create_time.strftime('%Y-%m-%d %H:%M:%S')
|
||||
return ORDER_CARD_PREFIX + json.dumps(payload, ensure_ascii=False)
|
||||
|
||||
|
||||
# ========== 辅助配置获取(从 ClubConfig) ==========
|
||||
def _get_self_club_config():
|
||||
if not hasattr(_get_self_club_config, '_config'):
|
||||
@@ -91,7 +150,8 @@ def _subscribe_users_to_group(user_ids, group_ids, appkey=None, secret=None):
|
||||
|
||||
# ========== 发送群消息(完整参数) ==========
|
||||
def _send_group_message(appkey, secret, group_id, sender_id, sender_name, sender_avatar,
|
||||
message_text, custom_payload=None, group_name=None, order_id=None, is_cross=0):
|
||||
message_text, custom_payload=None, group_name=None, order_id=None, is_cross=0,
|
||||
list_avatar=None, order_desc=None):
|
||||
if not appkey:
|
||||
appkey = _get_self_goeasy_appkey()
|
||||
if not secret:
|
||||
@@ -105,10 +165,12 @@ def _send_group_message(appkey, secret, group_id, sender_id, sender_name, sender
|
||||
# to.data 包含群聊展示信息及业务字段
|
||||
to_data = {
|
||||
"name": group_name or group_id,
|
||||
"avatar": sender_avatar or "",
|
||||
"avatar": list_avatar or sender_avatar or "",
|
||||
}
|
||||
if order_id:
|
||||
to_data["orderId"] = order_id
|
||||
if order_desc:
|
||||
to_data["orderDesc"] = order_desc[:300]
|
||||
to_data["isCross"] = is_cross
|
||||
|
||||
payload_str = custom_payload.get("text", message_text) if custom_payload else message_text
|
||||
@@ -305,12 +367,106 @@ def establish_order_chat_with_retry(dingdan_id, max_rounds=3):
|
||||
return False
|
||||
|
||||
# ========== 普通订单 / 我方派单 ==========
|
||||
def _push_order_card_message(appkey, secret, order, group_id, sender_id, sender_name, sender_avatar,
|
||||
group_name, list_avatar, order_desc):
|
||||
card_text = _build_order_card_text(order)
|
||||
return _send_group_message(
|
||||
appkey, secret, group_id, sender_id, sender_name, sender_avatar,
|
||||
card_text, None, group_name=group_name, order_id=order.dingdan_id,
|
||||
is_cross=order.is_cross or 0, list_avatar=list_avatar, order_desc=order_desc
|
||||
)
|
||||
|
||||
|
||||
def prepare_order_group_chat(dingdan_id, caller_goeasy_id, push_order_card=False):
|
||||
"""
|
||||
订单详情进入聊天前:确保配对群已订阅,可选推送订单卡片。
|
||||
返回前端跳转所需字段 dict,失败返回 None。
|
||||
"""
|
||||
try:
|
||||
order = Dingdan.objects.select_related('pingtai_kuozhan', 'shangjia_kuozhan').get(dingdan_id=dingdan_id)
|
||||
except Dingdan.DoesNotExist:
|
||||
logger.error(f"prepare_order_group_chat: 订单 {dingdan_id} 不存在")
|
||||
return None
|
||||
|
||||
dashou_uid = order.jiedan_dashou_id
|
||||
if not dashou_uid:
|
||||
logger.error(f"prepare_order_group_chat: 订单 {dingdan_id} 无接单打手")
|
||||
return None
|
||||
|
||||
dashou_goeasy_id = f"Ds{dashou_uid}"
|
||||
partner_goeasy_id, partner_name, partner_avatar = _get_local_partner_info(order)
|
||||
if not partner_goeasy_id:
|
||||
logger.error(f"prepare_order_group_chat: 订单 {dingdan_id} 无下单方")
|
||||
return None
|
||||
|
||||
group_id = resolve_group_id_for_order(order, dashou_uid)
|
||||
dashou_name, dashou_avatar = _resolve_goeasy_user_display(dashou_goeasy_id)
|
||||
|
||||
if caller_goeasy_id == dashou_goeasy_id:
|
||||
counterpart_id = partner_goeasy_id
|
||||
counterpart_name = partner_name
|
||||
counterpart_avatar = partner_avatar
|
||||
elif caller_goeasy_id == partner_goeasy_id:
|
||||
counterpart_id = dashou_goeasy_id
|
||||
counterpart_name = dashou_name
|
||||
counterpart_avatar = dashou_avatar
|
||||
else:
|
||||
logger.warning(f"prepare_order_group_chat: caller {caller_goeasy_id} 不属于订单 {dingdan_id}")
|
||||
return None
|
||||
|
||||
appkey = _get_self_goeasy_appkey()
|
||||
secret = _get_self_goeasy_secret()
|
||||
if not appkey:
|
||||
return None
|
||||
|
||||
order_desc = (order.jieshao or '').strip()
|
||||
if order.beizhu:
|
||||
order_desc = f"{order_desc} | 备注:{order.beizhu}" if order_desc else f"备注:{order.beizhu}"
|
||||
display_group_name = counterpart_name or '聊天'
|
||||
|
||||
user_ids = list({dashou_goeasy_id, partner_goeasy_id, caller_goeasy_id})
|
||||
subscribe_ok = _retry_call(
|
||||
_subscribe_users_to_group, 5, 0.4,
|
||||
user_ids, [group_id], appkey, secret
|
||||
)
|
||||
|
||||
card_ok = False
|
||||
if push_order_card:
|
||||
caller_name, caller_avatar = _resolve_goeasy_user_display(caller_goeasy_id)
|
||||
card_ok = _retry_call(
|
||||
_push_order_card_message, 3, 0.4,
|
||||
appkey, secret, order, group_id, caller_goeasy_id, caller_name, caller_avatar,
|
||||
display_group_name, counterpart_avatar, order_desc
|
||||
)
|
||||
|
||||
_ensure_liaotian_record(group_id, partner_goeasy_id, dashou_goeasy_id)
|
||||
|
||||
return {
|
||||
'groupId': group_id,
|
||||
'orderId': order.dingdan_id,
|
||||
'groupName': display_group_name,
|
||||
'groupAvatar': counterpart_avatar or '',
|
||||
'counterpartId': counterpart_id,
|
||||
'counterpartName': counterpart_name,
|
||||
'counterpartAvatar': counterpart_avatar or '',
|
||||
'orderDesc': order_desc,
|
||||
'orderJine': str(order.jine),
|
||||
'orderZhuangtai': order.zhuangtai,
|
||||
'isCross': 1 if order.is_cross == 1 else 0,
|
||||
'subscribeOk': subscribe_ok,
|
||||
'orderCardPushed': card_ok,
|
||||
}
|
||||
|
||||
|
||||
def _handle_local_order(order, dashou_goeasy_id, dashou_name, dashou_avatar, appkey, secret):
|
||||
group_id = f"group_{order.dingdan_id}"
|
||||
group_name = (order.jieshao[:20] + '…') if order.jieshao and len(order.jieshao) > 20 else (order.jieshao or f"订单{order.dingdan_id}")
|
||||
group_avatar = _full_local_avatar(order.tupian) if order.tupian else _full_local_avatar('')
|
||||
dashou_uid = dashou_goeasy_id[2:] if dashou_goeasy_id.startswith('Ds') else dashou_goeasy_id
|
||||
group_id = resolve_group_id_for_order(order, dashou_uid)
|
||||
|
||||
partner_goeasy_id, partner_name, partner_avatar = _get_local_partner_info(order)
|
||||
group_name = partner_name or f"用户{partner_goeasy_id[-6:] if partner_goeasy_id else ''}"
|
||||
order_desc = (order.jieshao or '').strip()
|
||||
if order.beizhu:
|
||||
order_desc = f"{order_desc} | 备注:{order.beizhu}" if order_desc else f"备注:{order.beizhu}"
|
||||
if not partner_goeasy_id:
|
||||
logger.error(f"订单 {order.dingdan_id} 无法获取下单方 GoEasy 标识")
|
||||
subscribe_ok = _retry_call(
|
||||
@@ -319,9 +475,10 @@ def _handle_local_order(order, dashou_goeasy_id, dashou_name, dashou_avatar, app
|
||||
)
|
||||
msg_ok = _retry_call(
|
||||
_send_group_message, 3, 0.4,
|
||||
appkey, secret, group_id, dashou_goeasy_id, dashou_name, group_avatar,
|
||||
appkey, secret, group_id, dashou_goeasy_id, dashou_name, dashou_avatar,
|
||||
"订单已接单,请等待对方上线。", None, group_name=group_name,
|
||||
order_id=order.dingdan_id, is_cross=order.is_cross
|
||||
order_id=order.dingdan_id, is_cross=order.is_cross,
|
||||
list_avatar=partner_avatar, order_desc=order_desc
|
||||
)
|
||||
return subscribe_ok or msg_ok
|
||||
|
||||
@@ -333,9 +490,9 @@ def _handle_local_order(order, dashou_goeasy_id, dashou_name, dashou_avatar, app
|
||||
init_msg_text = f"订单已接单,内容:{order.jieshao},备注:{order.beizhu},游戏ID:{order.nicheng}"
|
||||
success1 = _retry_call(
|
||||
_send_group_message, 3, 0.4,
|
||||
appkey, secret, group_id, dashou_goeasy_id, dashou_name, group_avatar,
|
||||
appkey, secret, group_id, dashou_goeasy_id, dashou_name, dashou_avatar,
|
||||
init_msg_text, None, group_name=group_name, order_id=order.dingdan_id,
|
||||
is_cross=order.is_cross
|
||||
is_cross=order.is_cross, list_avatar=partner_avatar, order_desc=order_desc
|
||||
)
|
||||
|
||||
partner_msg = "订单已确认,请开始服务。"
|
||||
@@ -343,16 +500,22 @@ def _handle_local_order(order, dashou_goeasy_id, dashou_name, dashou_avatar, app
|
||||
_send_group_message, 3, 0.4,
|
||||
appkey, secret, group_id, partner_goeasy_id, partner_name, partner_avatar,
|
||||
partner_msg, None, group_name=group_name, order_id=order.dingdan_id,
|
||||
is_cross=order.is_cross
|
||||
is_cross=order.is_cross, list_avatar=dashou_avatar, order_desc=order_desc
|
||||
)
|
||||
|
||||
liaotian_ok = _ensure_liaotian_record(order.dingdan_id, partner_goeasy_id, dashou_goeasy_id)
|
||||
card_ok = _retry_call(
|
||||
_push_order_card_message, 3, 0.4,
|
||||
appkey, secret, order, group_id, dashou_goeasy_id, dashou_name, dashou_avatar,
|
||||
group_name, partner_avatar, order_desc
|
||||
)
|
||||
|
||||
liaotian_ok = _ensure_liaotian_record(group_id, partner_goeasy_id, dashou_goeasy_id)
|
||||
private_ok = _establish_private_chat(
|
||||
appkey, secret, dashou_goeasy_id, dashou_name, dashou_avatar,
|
||||
partner_goeasy_id, partner_name, partner_avatar
|
||||
)
|
||||
|
||||
result = subscribe_ok or success1 or success2 or liaotian_ok or private_ok
|
||||
result = subscribe_ok or success1 or success2 or card_ok or liaotian_ok or private_ok
|
||||
if not result:
|
||||
logger.error(f"订单 {order.dingdan_id} 群聊/私聊均未建立成功")
|
||||
return result
|
||||
@@ -525,17 +688,21 @@ def _get_cross_partner_identity(order, partner_order_id):
|
||||
return f"User{uid}"
|
||||
|
||||
def _create_local_group_only(order, dashou_goeasy_id, dashou_name, dashou_avatar, appkey, secret):
|
||||
group_id = f"group_{order.dingdan_id}"
|
||||
group_name = (order.jieshao[:20] + '…') if order.jieshao and len(order.jieshao) > 20 else (order.jieshao or f"订单{order.dingdan_id}")
|
||||
group_avatar = _full_local_avatar(order.tupian) if order.tupian else _full_local_avatar('')
|
||||
dashou_uid = dashou_goeasy_id[2:] if dashou_goeasy_id.startswith('Ds') else dashou_goeasy_id
|
||||
group_id = resolve_group_id_for_order(order, dashou_uid)
|
||||
partner_goeasy_id, partner_name, partner_avatar = _get_local_partner_info(order)
|
||||
group_name = partner_name or (order.jieshao or f"订单{order.dingdan_id}")
|
||||
order_desc = (order.jieshao or '').strip()
|
||||
if order.beizhu:
|
||||
order_desc = f"{order_desc} | 备注:{order.beizhu}" if order_desc else f"备注:{order.beizhu}"
|
||||
subscribe_ok = _retry_call(
|
||||
_subscribe_users_to_group, 5, 0.4,
|
||||
[dashou_goeasy_id], [group_id], appkey, secret
|
||||
)
|
||||
msg_ok = _retry_call(
|
||||
_send_group_message, 3, 0.4,
|
||||
appkey, secret, group_id, dashou_goeasy_id, dashou_name, group_avatar,
|
||||
appkey, secret, group_id, dashou_goeasy_id, dashou_name, dashou_avatar,
|
||||
"订单已接单。", None, group_name=group_name, order_id=order.dingdan_id,
|
||||
is_cross=order.is_cross
|
||||
is_cross=order.is_cross, list_avatar=partner_avatar, order_desc=order_desc
|
||||
)
|
||||
return subscribe_ok or msg_ok
|
||||
Reference in New Issue
Block a user