"""子客服派单(独立实现,不修改商家派单接口)。""" import logging import os import random import time from decimal import Decimal from django.db import transaction from django.db.models import F from backend.utils import update_shangjia_daily from merchant_ops.constants import ACTOR_STAFF, STAT_ACTION_DISPATCH from merchant_ops.models import MerchantOrderDispatch from merchant_ops.services.wallet import check_wallet_available, confirm_dispatch_deduct from orders.models import MerchantOrderExt, Order from orders.notice_tasks import dingdan_guangbo from orders.utils import calc_shangjia_order_fencheng from products.models import ShangpinLeixing from rank.models import Chenghao, DingdanBiaoqian from users.models import UserShangjia, UserDashou from users.business_models import User logger = logging.getLogger(__name__) def _generate_dingdan_id(): ts = int(time.time() * 1000) pid = os.getpid() % 1000 rnd = random.randint(1000, 9999) return f"SJ{ts}{pid:03d}{rnd}" def staff_dispatch_order(member, staff_user, data): """ 子客服发单。返回 (success, payload_dict) payload_dict: code/msg/data 或 dingdan """ shangpin_type_id = data.get('shangpinTypeId') huiyuan_id = data.get('huiyuanId') dingdan_jieshao = str(data.get('dingdanJieshao', '')).strip() dingdan_beizhu = str(data.get('dingdanBeizhu', '')).strip() laoban_name = str(data.get('laobanName', '')).strip() zhiding_uid = str(data.get('zhidingUid', '')).strip() jiage_str = data.get('jiage') label_id = data.get('labelId') commission_enabled = data.get('commissionEnabled', False) commission_value_raw = data.get('commissionValue') commission_value_str = str(commission_value_raw).strip() if commission_value_raw is not None else '' if not all([shangpin_type_id, dingdan_jieshao, laoban_name, jiage_str]): return False, {'code': 400, 'msg': '缺少必填参数', 'data': None} try: jiage = float(jiage_str) if jiage < 1 or jiage > 10000: return False, {'code': 400, 'msg': '价格需在1-10000元之间', 'data': None} except ValueError: return False, {'code': 400, 'msg': '价格格式错误', 'data': None} try: shangpin_type = ShangpinLeixing.query.get(id=shangpin_type_id) except ShangpinLeixing.DoesNotExist: return False, {'code': 400, 'msg': '商品类型不存在', 'data': None} if commission_enabled and commission_value_str: try: cv = float(commission_value_str) if cv > 0: final_yaoqiu_type = 2 final_yongjin = Decimal(str(cv)) final_huiyuan_id = '' else: final_yaoqiu_type = shangpin_type.yaoqiuleixing or 1 final_yongjin = None final_huiyuan_id = str(huiyuan_id) if huiyuan_id else '' except ValueError: final_yaoqiu_type = shangpin_type.yaoqiuleixing or 1 final_yongjin = None final_huiyuan_id = str(huiyuan_id) if huiyuan_id else '' else: final_yaoqiu_type = shangpin_type.yaoqiuleixing or 1 final_yongjin = None final_huiyuan_id = str(huiyuan_id) if huiyuan_id else '' chenghao_obj = None label_id_str = str(label_id).strip() if label_id is not None else '' if label_id_str and label_id_str not in ('0', 'null', 'undefined'): try: lid = int(label_id_str) if lid > 0: chenghao_obj = Chenghao.query.filter(id=lid).first() except (ValueError, TypeError): pass merchant_id = member.merchant_id try: shangjia = UserShangjia.query.get(user__UserUID=merchant_id) except UserShangjia.DoesNotExist: return False, {'code': 403, 'msg': '所属商家不存在', 'data': None} if shangjia.zhuangtai != 1: return False, {'code': 403, 'msg': '商家状态异常', 'data': None} try: check_wallet_available(member, jiage) except ValueError as e: return False, {'code': 400, 'msg': str(e), 'data': None} zhiding_dashou = None if zhiding_uid: try: zhiding_user = User.query.select_related('DashouProfile').get(UserUID=zhiding_uid) zhiding_dashou = zhiding_user.DashouProfile if zhiding_dashou.zhanghaozhuangtai != 1: return False, {'code': 400, 'msg': '指定打手状态异常', 'data': None} except User.DoesNotExist: return False, {'code': 400, 'msg': '指定用户不存在', 'data': None} except UserDashou.DoesNotExist: return False, {'code': 400, 'msg': '指定用户不是打手', 'data': None} dashou_fencheng, guanshi_fencheng = calc_shangjia_order_fencheng(jiage) merchant_user = User.query.get(UserUID=merchant_id) dingdan = None try: with transaction.atomic(): check_wallet_available(member, jiage) dingdan = Order.query.create( OrderID=_generate_dingdan_id(), Status=7 if zhiding_dashou else 1, Platform=2, Amount=jiage, PlayerCommission=dashou_fencheng, ManagerCommission=guanshi_fencheng, AssignedID=zhiding_uid if zhiding_dashou else '', ProductID=0, ProductTypeID=int(shangpin_type_id), GrabRequirement=final_yaoqiu_type, CommissionReq=final_yongjin, MembershipID=final_huiyuan_id, Description=dingdan_jieshao[:2000], Remark=dingdan_beizhu[:1000], Nickname=laoban_name[:50], ImageURL=merchant_user.Avatar if merchant_user else '', User1ID=f"Sj{merchant_id}", ) MerchantOrderExt.query.create( Order=dingdan, MerchantID=merchant_id, MerchantNickname=shangjia.nicheng, ) if chenghao_obj: DingdanBiaoqian.query.create(dingdan=dingdan, chenghao=chenghao_obj) UserShangjia.query.filter(id=shangjia.id).update( fabu=F('fabu') + 1, jinridingdan=F('jinridingdan') + 1, jinriliushui=F('jinriliushui') + Decimal(str(jiage)), jinyuedingdan=F('jinyuedingdan') + 1, jinyueliushui=F('jinyueliushui') + Decimal(str(jiage)), ) MerchantOrderDispatch.objects.create( order_id=dingdan.OrderID, merchant_id=merchant_id, dispatch_actor_type=ACTOR_STAFF, dispatch_actor_id=member.staff_user_id, staff_member_id=member.id, ) confirm_dispatch_deduct(member, jiage, dingdan.OrderID, member.staff_user_id) update_shangjia_daily( merchant_id, Decimal(str(jiage)), STAT_ACTION_DISPATCH, order_id=dingdan.OrderID, ) except ValueError as e: return False, {'code': 400, 'msg': str(e), 'data': None} except Exception as e: logger.error(f'子客服派单失败: {e}', exc_info=True) return False, {'code': 500, 'msg': '订单创建失败', 'data': None} try: from orders.views import ShangjiaPaifaView view = ShangjiaPaifaView() game_type = view._get_game_type_name(dingdan.ProductTypeID) except Exception: game_type = '游戏订单' try: dingdan_guangbo.delay({ 'OrderID': dingdan.OrderID, 'game_type': game_type, 'amount': str(dingdan.Amount), 'order_desc': (dingdan.Description or '')[:50], }) except Exception as e: logger.error(f'广播任务失败: {e}') return True, { 'code': 200, 'msg': '派单成功', 'data': {'dingdan_id': dingdan.OrderID, 'jine': str(dingdan.Amount)}, }