
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfile

from shangpin.models import  Huiyuangoumai
from dingdan.models import  Lilubiao, Pingfen, Chufajilu, Liaotian, Chufatupian

from yonghu.models import UserShangjia
from houtai.utils import update_dashou_daily_by_action

from decimal import Decimal
from houtai.utils import (
    update_shangjia_daily,

)

import logging
from rest_framework import permissions

from dingdan.utils import sync_order_to_partners

from django.db import transaction
from django.http import HttpResponse
from rest_framework.views import APIView

from rest_framework.throttling import AnonRateThrottle
from rest_framework.permissions import AllowAny

from peizhi.models import Szjilu

logger = logging.getLogger(__name__)

from shangdian.utils import calculate_pingtai_and_dianpu_shouyi, validate_shangpin_and_dianpu
from shangpin.utils import update_shangpin_daily_stat
from shangdian.utils import update_dianpu_daily_stat   # 注意：您之前写的店铺统计方法名是 update_dianpu_daily_stat







class CreateOrderView(APIView):
    """
    创建订单并调用微信支付接口
    """
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        try:
            # 1. 获取前端传递的字段
            shangpin_id = request.data.get('shangpin_id')
            nicheng = request.data.get('nicheng', '').strip()
            beizhu = request.data.get('beizhu', '').strip()
            zhiding = request.data.get('zhiding', '').strip()
            jine = request.data.get('jine', 0)

            # 2. 验证必填字段
            if not shangpin_id:
                return Response({'code': 1, 'msg': '商品ID不能为空', 'data': None})

            if not nicheng:
                return Response({'code': 2, 'msg': '游戏昵称不能为空', 'data': None})

            if len(nicheng) > 50:
                return Response({'code': 3, 'msg': '游戏昵称过长', 'data': None})

            # 3. 查询商品信息
            shangpin = Shangpin.objects.filter(id=shangpin_id).first()
            if not shangpin:
                return Response({'code': 4, 'msg': '商品不存在', 'data': None})

            is_valid, err_msg, _ = validate_shangpin_and_dianpu(shangpin_id)
            if not is_valid:
                return Response({'code': 5, 'msg': err_msg, 'data': None})

            # 检查库存
            if hasattr(shangpin, 'kucun') and shangpin.kucun <= 0:
                return Response({'code': 5, 'msg': '商品库存不足', 'data': None})

            # 获取商品价格
            shangpin_jiage = getattr(shangpin, 'jiage', 0)
            if not shangpin_jiage:
                return Response({'code': 6, 'msg': '商品价格异常', 'data': None})
            #获取商品图片
            shangpin_tupian = getattr(shangpin, 'tupian_url', None)

            # 4. 验证指定打手（如果存在）
            zhiding_id_value = None
            if zhiding:
                # 查询主表中是否存在该打手
                zhiding_user = UserMain.objects.filter(
                    yonghuid=zhiding,
                    #user_type='dashou'
                ).first()

                if not zhiding_user:
                    return Response({'code': 7, 'msg': '指定打手不存在', 'data': None})

                # 查询打手扩展表
                dashou_profile = UserDashou.objects.filter(user=zhiding_user).first()

                if not dashou_profile:
                    return Response({'code': 8, 'msg': '指定用户不存在或已封禁', 'data': None})

                # 检查在线状态
                if getattr(dashou_profile, 'zhanghaozhuangtai', 0) == 0:
                    return Response({'code': 8, 'msg': '指定用户不存在或已封禁', 'data': None})

                zhiding_id_value = zhiding

            # 5. 生成订单ID
            timestamp = int(time.time())
            timestamp_ns = int(time.time_ns() // 1000) % 1000000
            random_num = random.randint(0, 99)
            dingdanid = f"PT{timestamp:011d}{timestamp_ns:06d}{random_num:02d}"

            # 6. 查询利率并计算分成
            # 查询打手利率（字符'1'）
            dashou_lilu = Lilubiao.objects.filter(fadanpingtai='1').first()

            # 🔥 新增：判断是否使用商品配置的额外分成
            if shangpin.kaioi_ewai_dashou_fencheng and shangpin.ewai_dashou_fencheng is not None:
                # 使用商品指定的额外分成金额
                dashou_fencheng = shangpin.ewai_dashou_fencheng
            else:
                # 按原有逻辑计算打手分成
                dashou_fencheng = Decimal(str(shangpin_jiage)) * Decimal(str(dashou_lilu.lilu))


            # 查询管事利率（字符'2'）
            #guanshi_lilu = Lilubiao.objects.filter(fadanpingtai='2').first()

            if not dashou_lilu: #or not guanshi_lilu:
                return Response({'code': 9, 'msg': '系统利率配置不完整', 'data': None})



            # 计算打手分成
            #dashou_fencheng = Decimal(str(shangpin_jiage)) * Decimal(str(dashou_lilu.lilu))




            # 开始数据库事务
            with transaction.atomic():
                # 获取当前用户信息
                current_user = request.user
                laoban_yonghuid = getattr(current_user, 'yonghuid', '')
                user_openid = getattr(current_user, 'openid', '')

                if not user_openid:
                    return Response({'code': 10, 'msg': '用户openid不存在', 'data': None})

                # 创建订单主表数据
                order_data = {
                    'dingdan_id': dingdanid,
                    'zhuangtai': 9,  # 未付款状态
                    'jine': shangpin_jiage,
                    'fadan_pingtai':1,
                    'dashou_fencheng': dashou_fencheng,
                    'zhiding_id': zhiding_id_value,
                    'shangpin_id': shangpin_id,
                    'yaoqiuleixing': getattr(shangpin, 'yaoqiuleixing', None),
                    'huiyuan_id': getattr(shangpin, 'huiyuan_id', ''),
                    'yongjin': getattr(shangpin, 'yongjin', 0),
                    'jieshao': getattr(shangpin, 'jieshao', ''),
                    'beizhu': beizhu,
                    'nicheng': nicheng,
                    'tupian':shangpin_tupian,
                    'user1_id':f"Boss{request.user.yonghuid}",
                    'leixing_id':shangpin.leixing_id
                }

                # 创建订单记录
                dingdan = Dingdan.objects.create(**order_data)

                # CreateOrderView.post 事务内部，替换原有的扩展表创建代码

                dianpu_id, pingtai_shouyi, dianpu_shouyi, shangji_dianpu_id, shangji_fenhong = calculate_pingtai_and_dianpu_shouyi(
                    shangpin_id=shangpin_id,
                    dingdan_jiage=shangpin_jiage,
                    dashou_fencheng=dashou_fencheng
                )

                pingtaikuozhan_data = {
                    'dingdan': dingdan,
                    'laoban_id': laoban_yonghuid,
                    'pingtai_shouyi': pingtai_shouyi,
                    # ---------- 新增上级分红快照 ----------
                    'shangji_dianpu_id': shangji_dianpu_id,
                    'shangji_fenhong': shangji_fenhong if shangji_fenhong else Decimal('0.00'),
                }
                if dianpu_id:
                    pingtaikuozhan_data['dianpu_id'] = dianpu_id
                    pingtaikuozhan_data['dianpu_shouyi'] = dianpu_shouyi
                else:
                    pingtaikuozhan_data['dianpu_shouyi'] = Decimal('0.00')

                DingdanPingtai.objects.create(**pingtaikuozhan_data)


                # 计算收益
                '''dianpu_id, pingtai_shouyi, dianpu_shouyi = calculate_pingtai_and_dianpu_shouyi(
                    shangpin_id=shangpin_id,
                    dingdan_jiage=shangpin_jiage,
                    dashou_fencheng=dashou_fencheng
                )

                # 构建扩展表数据，平台收益必定保存，店铺收益和店铺ID仅当dianpu_id存在时才赋值
                pingtaikuozhan_data = {
                    'dingdan': dingdan,
                    'laoban_id': laoban_yonghuid,
                    'pingtai_shouyi': pingtai_shouyi,
                }
                if dianpu_id:
                    pingtaikuozhan_data['dianpu_id'] = dianpu_id
                    pingtaikuozhan_data['dianpu_shouyi'] = dianpu_shouyi
                else:
                    # 无店铺时，店铺收益字段保持默认（0.00），也可显式设为0
                    pingtaikuozhan_data['dianpu_shouyi'] = Decimal('0.00')

                DingdanPingtai.objects.create(**pingtaikuozhan_data)'''

                # 创建订单平台扩展表
                """pingtaikuozhan_data = {
                    'dingdan': dingdan,
                    'laoban_id': laoban_yonghuid,
                }
                DingdanPingtai.objects.create(**pingtaikuozhan_data)"""

                # 7. 生成微信支付参数（向微信官方发送请求）
                pay_params = self.generate_wechat_pay_params(
                    dingdanid=dingdanid,
                    jine=shangpin_jiage,
                    beizhu=getattr(settings, 'WEIXIN_PAY_DESCRIPTION'),
                    user_ip=self.get_client_ip(request),
                    openid=user_openid
                )

                if not pay_params:
                    # 手动抛出异常触发事务回滚
                    raise Exception('支付参数生成失败')

                # 8. 返回成功响应
                response_data = {
                    'code': 0,
                    'msg': '订单创建成功',
                    'data': {
                        'dingdanid': dingdanid,
                        'payParams': pay_params
                    }
                }

                return Response(response_data)

        except Exception as e:
            # 这里会自动回滚事务
            return Response({'code': 99, 'msg': f'系统错误: {str(e)}', 'data': None})

    def get_client_ip(self, request):
        """获取客户端真实IP地址"""
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = request.META.get('REMOTE_ADDR')
        return ip

    def generate_wechat_pay_params(self, dingdanid, jine, beizhu, user_ip, openid):
        """
        调用微信支付统一下单接口，生成支付参数
        完全按照您提供的正确示例代码编写
        """
        try:
            # 微信支付配置
            APPID = getattr(settings, 'WEIXIN_APPID', '')
            MCHID = getattr(settings, 'WEIXIN_MCHID', '')
            KEY = getattr(settings, 'WEIXIN_SHANGHUMIYAO', '')
            NOTIFY_URL = getattr(settings, 'WEIXIN_NOTIFY_URL', '')

            if not all([APPID, MCHID, KEY, NOTIFY_URL]):
                raise Exception('微信支付配置不完整')

            # 生成随机字符串
            import string
            nonce_str = ''.join(random.choices(string.ascii_letters + string.digits, k=32))

            # 金额（单位：分）
            total_fee = int(float(jine) * 100)

            # 交易类型
            trade_type = 'JSAPI'

            # 生成签名
            sign_data = {
                'appid': APPID,
                'mch_id': MCHID,
                'nonce_str': nonce_str,
                'body': beizhu,
                'out_trade_no': dingdanid,
                'total_fee': total_fee,
                'spbill_create_ip': user_ip,
                'notify_url': NOTIFY_URL,
                'trade_type': trade_type,
                'openid': openid
            }

            # 按照参数名ASCII码从小到大排序
            sorted_sign_data = sorted(sign_data.items(), key=lambda x: x[0])

            # 拼接字符串
            sign_string = '&'.join([f"{key}={value}" for key, value in sorted_sign_data if value])
            sign_string += f'&key={KEY}'

            # MD5签名
            sign = hashlib.md5(sign_string.encode('utf-8')).hexdigest().upper()

            # 构造XML数据
            xml_data = f"""<xml>
<appid>{APPID}</appid>
<body>{beizhu}</body>
<mch_id>{MCHID}</mch_id>
<nonce_str>{nonce_str}</nonce_str>
<notify_url>{NOTIFY_URL}</notify_url>
<openid>{openid}</openid>
<out_trade_no>{dingdanid}</out_trade_no>
<spbill_create_ip>{user_ip}</spbill_create_ip>
<total_fee>{total_fee}</total_fee>
<trade_type>{trade_type}</trade_type>
<sign>{sign}</sign>
</xml>"""

            # 调用微信统一下单接口
            response = requests.post(
                'https://api.mch.weixin.qq.com/pay/unifiedorder',
                data=xml_data.encode('utf-8'),
                headers={'Content-Type': 'application/xml'},
                timeout=10
            )

            # 解析返回的XML
            root = ET.fromstring(response.content)

            return_code = root.find('return_code').text
            result_code = root.find('result_code').text

            if return_code == 'SUCCESS' and result_code == 'SUCCESS':
                prepay_id = root.find('prepay_id').text

                # 生成前端支付参数
                timestamp = str(int(time.time()))
                nonce_str = ''.join(random.choices(string.ascii_letters + string.digits, k=32))
                package = f'prepay_id={prepay_id}'

                # 生成支付签名
                pay_sign_data = {
                    'appId': APPID,
                    'timeStamp': timestamp,
                    'nonceStr': nonce_str,
                    'package': package,
                    'signType': 'MD5'
                }

                sorted_pay_sign_data = sorted(pay_sign_data.items(), key=lambda x: x[0])
                pay_sign_string = '&'.join([f"{key}={value}" for key, value in sorted_pay_sign_data])
                pay_sign_string += f'&key={KEY}'
                pay_sign = hashlib.md5(pay_sign_string.encode('utf-8')).hexdigest().upper()

                # 返回支付参数（格式与前端完全匹配）
                result = {
                    'timeStamp': timestamp,
                    'nonceStr': nonce_str,
                    'package': package,
                    'signType': 'MD5',
                    'paySign': pay_sign
                }

                return result
            else:
                # 获取详细的错误信息
                err_code = root.find('err_code')
                err_code_des = root.find('err_code_des')
                return_msg = root.find('return_msg')

                error_details = f"return_code: {return_code}, "
                if err_code is not None:
                    error_details += f"err_code: {err_code.text}, "
                if err_code_des is not None:
                    error_details += f"err_code_des: {err_code_des.text}, "
                if return_msg is not None:
                    error_details += f"return_msg: {return_msg.text}"

                raise Exception(f"微信支付下单失败: {error_details}")

        except Exception as e:
            raise e






from dingdan.utils import update_daily_income
import logging
import traceback

logger = logging.getLogger(__name__)

class WechatPayNotifyView(APIView):
    """微信支付回调接口 - 接收微信官方支付结果通知（含详细调试日志）"""
    throttle_classes = [AnonRateThrottle]
    permission_classes = [AllowAny]

    def post(self, request):
        # 记录原始请求数据（调试用）
        xml_data = request.body.decode('utf-8')

        # 最外层异常捕获，确保任何错误都能被记录并返回适当响应
        try:
            # 1. 解析 XML
            try:
                root = ET.fromstring(xml_data)
            except ET.ParseError as e:
                logger.error(f"XML解析失败: {e}")
                return self._gen_response_xml('FAIL', 'XML解析失败')

            # 2. 获取关键参数
            return_code = root.find('return_code').text if root.find('return_code') is not None else ''
            result_code = root.find('result_code').text if root.find('result_code') is not None else ''
            out_trade_no = root.find('out_trade_no').text if root.find('out_trade_no') is not None else ''
            transaction_id = root.find('transaction_id').text if root.find('transaction_id') is not None else ''

            # 3. 签名验证
            if not self._verify_signature(xml_data):
                logger.warning("签名验证失败")
                return self._gen_response_xml('FAIL', '签名验证失败')

            # 4. 根据支付结果处理
            if return_code == 'SUCCESS' and result_code == 'SUCCESS':
                self._handle_success(out_trade_no, transaction_id, root)
            else:
                logger.info(f"支付失败或异常，return_code={return_code}, result_code={result_code}")
                self._handle_failure(out_trade_no)

            # 返回微信要求的成功响应（必须返回SUCCESS，即使内部处理失败也要返回，否则微信会重复通知）
            return self._gen_response_xml('SUCCESS', 'OK')

        except Exception as e:
            # 捕获任何未处理的异常，记录完整堆栈
            logger.error(f"回调处理发生未捕获异常: {str(e)}")
            logger.error(traceback.format_exc())
            return self._gen_response_xml('FAIL', f'服务器内部错误: {str(e)}')

    def _verify_signature(self, xml_data):
        """微信支付签名验证（MD5）"""
        try:
            root = ET.fromstring(xml_data)
            sign = root.find('sign').text
            # 构建待签名字符串（排除sign字段）
            data = {child.tag: child.text for child in root if child.tag != 'sign'}
            # 按key排序
            sorted_keys = sorted(data.keys())
            stringA = '&'.join([f"{k}={data[k]}" for k in sorted_keys])
            stringSignTemp = f"{stringA}&key={settings.WEIXIN_SHANGHUMIYAO}"
            calc_sign = hashlib.md5(stringSignTemp.encode('utf-8')).hexdigest().upper()
            logger.debug(f"计算签名: {calc_sign}, 微信签名: {sign}")
            return calc_sign == sign
        except Exception as e:
            logger.error(f"签名验证过程异常: {e}")
            logger.error(traceback.format_exc())
            return False

    def _gen_response_xml(self, return_code, return_msg):
        """生成返回给微信的XML响应"""
        xml = f"""<xml>
<return_code><![CDATA[{return_code}]]></return_code>
<return_msg><![CDATA[{return_msg}]]></return_msg>
</xml>"""
        logger.info(f"返回给微信的响应: {xml}")
        return HttpResponse(xml, content_type='application/xml')

    @transaction.atomic
    def _handle_success(self, out_trade_no, transaction_id, root):
        """处理支付成功"""
        logger.info(f"进入 _handle_success, out_trade_no={out_trade_no}, transaction_id={transaction_id}")

        # 锁定订单防止并发
        try:
            dingdan = Dingdan.objects.select_for_update().filter(dingdan_id=out_trade_no).first()
        except Exception as e:
            logger.error(f"查询订单异常: {e}")
            raise

        if not dingdan:
            logger.error(f"订单不存在: {out_trade_no}")
            return

        logger.info(f"订单当前状态: {dingdan.zhuangtai}")

        # 幂等处理：只有状态为9（未支付）才处理，已处理则跳过
        if dingdan.zhuangtai != 9:
            logger.info(f"订单 {out_trade_no} 已处理过，状态={dingdan.zhuangtai}，跳过")
            return

        # 保存微信交易号
        if transaction_id:
            dingdan.wechat_transaction_id = transaction_id
            logger.info(f"保存微信交易号: {transaction_id}")
        else:
            logger.warning("微信未返回transaction_id")

        # 更新订单状态
        if dingdan.zhiding_id and dingdan.zhiding_id.strip():
            dingdan.zhuangtai = 7
            logger.info("指定单，状态设为7")
        else:
            dingdan.zhuangtai = 1
            logger.info("普通单，状态设为1")

        dingdan.save()

        logger.info(f"订单状态已更新为 {dingdan.zhuangtai}")

        # 删除同一用户同一商品的其他未支付订单（改为逻辑删除，状态25）
        try:
            abandoned_count = Dingdan.objects.filter(
                user1_id=dingdan.user1_id,
                shangpin_id=dingdan.shangpin_id,
                zhuangtai=9
            ).exclude(dingdan_id=out_trade_no).update(zhuangtai=25)
            logger.info(f"将 {abandoned_count} 个未支付订单标记为已废弃(25)")
        except Exception as e:
            logger.error(f"标记其他未支付订单异常: {e}")

        # 更新老板扩展表
        try:
            laoban_id = None
            if hasattr(dingdan, 'pingtai_kuozhan'):
                laoban_id = dingdan.pingtai_kuozhan.laoban_id
            if laoban_id:
                user_main = UserMain.objects.filter(yonghuid=laoban_id).first()
                if user_main and hasattr(user_main, 'boss_profile'):
                    boss = user_main.boss_profile
                    boss.zonge = (boss.zonge or 0) + (dingdan.jine or 0)
                    boss.alldingdan = (boss.alldingdan or 0) + 1
                    boss.save()
                    logger.info(f"更新老板 {laoban_id} 数据成功")
        except Exception as e:
            logger.error(f"更新老板数据异常: {e}")

        # 更新商品库存
        try:
            if dingdan.shangpin_id:
                Shangpin.objects.filter(id=dingdan.shangpin_id).update(
                    kucun=F('kucun') - 1
                )
                logger.info(f"商品 {dingdan.shangpin_id} 库存减1")
        except Exception as e:
            logger.error(f"更新商品库存异常: {e}")




        # ========== 新增：商品和店铺每日统计 ==========
        try:
            # 商品每日统计（只要有商品ID就执行）
            if dingdan.shangpin_id:
                # 从扩展表获取已计算好的收益值（下单时已存储）
                pingtai_shouyi = Decimal('0.00')
                dianpu_shouyi = Decimal('0.00')
                if hasattr(dingdan, 'pingtai_kuozhan'):
                    pingtai_shouyi = dingdan.pingtai_kuozhan.pingtai_shouyi or Decimal('0.00')
                    dianpu_shouyi = dingdan.pingtai_kuozhan.dianpu_shouyi or Decimal('0.00')

                update_shangpin_daily_stat(
                    shangpin_id=dingdan.shangpin_id,
                    caozuo_leixing=1,  # 1 = 下单
                    dingdan_jiage=dingdan.jine,
                    pingtai_shouyi=pingtai_shouyi,
                    dianpu_zongshouyi=dianpu_shouyi
                )
                logger.info(f"商品统计更新完成，商品ID: {dingdan.shangpin_id}")

            # 店铺每日统计（仅当存在店铺ID时执行）
            dianpu_id = None
            if hasattr(dingdan, 'pingtai_kuozhan'):
                dianpu_id = dingdan.pingtai_kuozhan.dianpu_id
            if dianpu_id:
                dianpu_shouyi = dingdan.pingtai_kuozhan.dianpu_shouyi or Decimal('0.00')
                update_dianpu_daily_stat(
                    dianpu_id=dianpu_id,
                    caozuo_leixing=1,  # 1 = 下单
                    dingdan_jiage=dingdan.jine,
                    dianpu_shouyi=dianpu_shouyi
                )
                logger.info(f"店铺统计更新完成，店铺ID: {dianpu_id}")
        except Exception as e:
            logger.error(f"商品/店铺统计更新失败: {e}")
            logger.error(traceback.format_exc())
            # 统计失败不影响主流程
        # =============================================








        # 更新收支记录（总累计）
        self._update_szjilu(dingdan.jine)

        # 更新每日收入统计
        update_daily_income(dingdan.jine)

        # 跨平台同步
        sync_order_to_partners(dingdan.dingdan_id)

        #🟢【7. 新增】支付成功后的广播通知（异步，不阻塞主流程）
        from dingdan.tongzhi_tasks import dingdan_guangbo

        # 构建通知数据（你的 _get_game_type_name 方法保留在视图里直接用）
        order_info = {
            'dingdan_id': dingdan.dingdan_id,
            'game_type': self._get_game_type_name(dingdan.leixing_id),
            'amount': str(dingdan.jine),
            'order_desc': (dingdan.jieshao or '')[:50],
        }
        dingdan_guangbo.delay(order_info)   # 瞬间返回，不阻塞请求

        # 异步广播通知
        #self._broadcast_async(dingdan)

        logger.info(f"订单 {out_trade_no} 支付成功处理完成")

    @transaction.atomic
    def _handle_failure(self, out_trade_no):
        """处理支付失败"""
        logger.info(f"进入 _handle_failure, out_trade_no={out_trade_no}")

        try:
            dingdan = Dingdan.objects.select_for_update().filter(dingdan_id=out_trade_no).first()
            if not dingdan:
                logger.warning(f"订单不存在: {out_trade_no}")
                return

            logger.info(f"订单当前状态: {dingdan.zhuangtai}")

            # 仅当订单状态为9（未支付）时才标记失败，不直接删除
            if dingdan.zhuangtai == 9:
                dingdan.zhuangtai = 14  # 自定义支付失败状态
                dingdan.save()
                logger.info(f"订单 {out_trade_no} 支付失败，标记为14")
            else:
                logger.info(f"订单 {out_trade_no} 状态非9，不处理")
        except Exception as e:
            logger.error(f"处理支付失败异常: {e}")
            logger.error(traceback.format_exc())

    def _update_szjilu(self, jine):
        """更新收支记录表（ID=1的记录）"""
        try:
            jine_decimal = Decimal(str(jine))
            with transaction.atomic():
                szjilu, created = Szjilu.objects.select_for_update().get_or_create(
                    id=1,
                    defaults={
                        'zongsy': Decimal('0.00'),
                        'zongls': Decimal('0.00'),
                        'zongzc': Decimal('0.00'),
                        'jrzc': Decimal('0.00'),
                        'jrls': Decimal('0.00')
                    }
                )
                if created:
                    logger.info("创建ID=1的收支记录")
                szjilu.zongsy += jine_decimal
                szjilu.zongls += jine_decimal
                szjilu.jrls += jine_decimal
                szjilu.save()
                logger.info(f"收支记录更新成功，增加金额: {jine}")
        except Exception as e:
            logger.error(f"更新收支记录失败: {e}")

    def _broadcast_async(self, dingdan):
        """异步广播通知"""
        try:
            def task():
                try:
                    from utils.weixin_broadcast import WeixinBroadcastSender  # 请根据实际路径修改
                    order_info = {
                        'dingdan_id': dingdan.dingdan_id,
                        'game_type': self._get_game_type_name(dingdan.leixing_id),
                        'amount': str(dingdan.jine),
                        'order_desc': (dingdan.jieshao or '')[:50],
                    }
                    logger.info(f"准备广播订单: {order_info}")
                    sender = WeixinBroadcastSender()
                    result = sender.broadcast_order(order_info)
                    if result.get('success'):
                        logger.info(f"订单广播完成: {result.get('msg')}")
                    else:
                        logger.warning(f"订单广播异常: {result.get('msg')}")
                except Exception as e:
                    logger.error(f"广播任务异常: {e}")
                    logger.error(traceback.format_exc())

            thread = threading.Thread(target=task)
            thread.daemon = True
            thread.start()
            logger.info("广播线程已启动")
        except Exception as e:
            logger.error(f"启动广播线程异常: {e}")

    def _get_game_type_name(self, leixing_id):
        try:
            from shangpin.models import ShangpinLeixing
            gt = ShangpinLeixing.objects.filter(id=leixing_id).first()
            return gt.jieshao if gt else '游戏订单'
        except Exception as e:
            logger.error(f"获取游戏类型名称异常: {e}")
            return '游戏订单'

# dingdan/views.py (PaymentFailView)

class PaymentFailView(APIView):
    """
    前端支付失败接口 - 处理用户主动取消或支付失败
    只允许删除状态为9（未支付）的订单
    """
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        try:
            dingdanid = request.data.get('dingdanid')
            if not dingdanid:
                return Response({'code': 1, 'msg': '订单ID不能为空', 'data': None})

            with transaction.atomic():
                # 锁定订单防止并发
                dingdan = Dingdan.objects.select_for_update().filter(dingdan_id=dingdanid).first()
                if not dingdan:
                    return Response({'code': 2, 'msg': '订单不存在', 'data': None})

                # 只允许删除未支付订单（状态9）
                if dingdan.zhuangtai != 9:
                    return Response({'code': 3, 'msg': '只能删除未支付的订单', 'data': None})

                # 删除扩展表和主表
                DingdanPingtai.objects.filter(dingdan=dingdan).delete()
                dingdan.delete()

            return Response({'code': 0, 'msg': '订单已删除', 'data': None})

        except Exception as e:
            return Response({'code': 99, 'msg': f'删除订单失败: {str(e)}', 'data': None})






"""
虚拟支付视图（代币模式）
完全基于原有商户支付逻辑，仅替换支付参数生成和回调/查单方式
数据库字段、状态流转、业务规则 100% 保持一致
"""
import json
import hmac
import hashlib
import logging
import time
import random
from decimal import Decimal

import requests
from django.conf import settings
from django.db import transaction
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import permissions
from rest_framework.parsers import JSONParser
from django.http import HttpResponse
import xmltodict
import threading

from .models import Dingdan, DingdanPingtai, Lilubiao
from shangpin.models import Shangpin
from yonghu.models import UserMain, UserDashou, UserBoss
from peizhi.models import Szjilu
from .utils import update_daily_income, sync_order_to_partners

logger = logging.getLogger(__name__)


class VirtualCreateOrderView(APIView):
    """
    虚拟代币支付创建订单
    流程与原 CreateOrderView 完全一致，仅支付参数生成改为代币虚拟支付
    """
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        try:
            # 1. 获取前端参数
            shangpin_id = request.data.get('shangpin_id')
            nicheng = request.data.get('nicheng', '').strip()
            beizhu = request.data.get('beizhu', '').strip()
            zhiding = request.data.get('zhiding', '').strip()
            jine = request.data.get('jine', 0)
            code = request.data.get('code')   # 虚拟支付必须每单都用最新 code 换 session_key

            # 2. 临时关闭指定功能（与原逻辑一致）
            if zhiding:
                return Response({'code': 8, 'msg': '指定功能尚未开启，请不要填写指定打手ID', 'data': None})

            # 3. 验证必填字段
            if not shangpin_id:
                return Response({'code': 1, 'msg': '商品ID不能为空', 'data': None})
            if not nicheng:
                return Response({'code': 2, 'msg': '游戏昵称不能为空', 'data': None})
            if len(nicheng) > 50:
                return Response({'code': 3, 'msg': '游戏昵称过长', 'data': None})
            if not code:
                return Response({'code': 10, 'msg': '缺少登录凭证code', 'data': None})

            # 4. 查询商品信息
            shangpin = Shangpin.objects.filter(id=shangpin_id).first()
            if not shangpin:
                return Response({'code': 4, 'msg': '商品不存在', 'data': None})
            if hasattr(shangpin, 'kucun') and shangpin.kucun <= 0:
                return Response({'code': 5, 'msg': '商品库存不足', 'data': None})

            shangpin_jiage = getattr(shangpin, 'jiage', 0)
            if not shangpin_jiage:
                return Response({'code': 6, 'msg': '商品价格异常', 'data': None})
            shangpin_tupian = getattr(shangpin, 'tupian_url', None)

            # 5. 验证指定打手（如果存在）---- 虽然前面已禁止，保留原逻辑以备后续开启
            zhiding_id_value = None
            if zhiding:
                zhiding_user = UserMain.objects.filter(yonghuid=zhiding).first()
                if not zhiding_user:
                    return Response({'code': 7, 'msg': '指定打手不存在', 'data': None})
                dashou_profile = UserDashou.objects.filter(user=zhiding_user).first()
                if not dashou_profile:
                    return Response({'code': 8, 'msg': '指定用户不存在或已封禁', 'data': None})
                if getattr(dashou_profile, 'zhanghaozhuangtai', 0) == 0:
                    return Response({'code': 8, 'msg': '指定用户不存在或已封禁', 'data': None})
                zhiding_id_value = zhiding

            # 6. 生成订单ID（格式不变）
            timestamp = int(time.time())
            timestamp_ns = int(time.time_ns() // 1000) % 1000000
            random_num = random.randint(0, 99)
            dingdanid = f"PT{timestamp:011d}{timestamp_ns:06d}{random_num:02d}"

            # 7. 查询利率并计算分成（完全复用原代码）
            dashou_lilu = Lilubiao.objects.filter(fadanpingtai='1').first()
            if not dashou_lilu:
                return Response({'code': 9, 'msg': '系统利率配置不完整', 'data': None})

            if shangpin.kaioi_ewai_dashou_fencheng and shangpin.ewai_dashou_fencheng is not None:
                dashou_fencheng = shangpin.ewai_dashou_fencheng
            else:
                dashou_fencheng = Decimal(str(shangpin_jiage)) * Decimal(str(dashou_lilu.lilu))

            # 8. 强制刷新 session_key（虚拟支付签名所必需）
            wx_resp = self._exchange_code_for_session_key(code)
            if wx_resp is None:
                return Response({'code': 11, 'msg': '微信认证失败', 'data': None})

            session_key = wx_resp['session_key']
            user_openid = wx_resp['openid']
            logger.info(f"[VirtualCreate] session_key刷新成功，openid={user_openid}")

            # 更新用户 openid 和 session_key（保持数据库最新）
            current_user = request.user
            current_user.openid = user_openid
            current_user.session_key = session_key
            current_user.save(update_fields=['openid', 'session_key'])

            # 9. 数据库事务（与原代码完全一致）
            with transaction.atomic():
                laoban_yonghuid = getattr(current_user, 'yonghuid', '')

                # 创建订单主表
                order_data = {
                    'dingdan_id': dingdanid,
                    'zhuangtai': 9,
                    'jine': shangpin_jiage,
                    'fadan_pingtai': 1,
                    'dashou_fencheng': dashou_fencheng,
                    'zhiding_id': zhiding_id_value,
                    'shangpin_id': shangpin_id,
                    'yaoqiuleixing': getattr(shangpin, 'yaoqiuleixing', None),
                    'huiyuan_id': getattr(shangpin, 'huiyuan_id', ''),
                    'yongjin': getattr(shangpin, 'yongjin', 0),
                    'jieshao': getattr(shangpin, 'jieshao', ''),
                    'beizhu': beizhu,
                    'nicheng': nicheng,
                    'tupian': shangpin_tupian,
                    'user1_id': f"Boss{current_user.yonghuid}",
                    'leixing_id': shangpin.leixing_id
                }
                dingdan = Dingdan.objects.create(**order_data)

                # 创建订单平台扩展表
                DingdanPingtai.objects.create(
                    dingdan=dingdan,
                    laoban_id=laoban_yonghuid,
                )

                # 生成代币虚拟支付参数
                pay_params = self.generate_virtual_pay_params(
                    dingdanid=dingdanid,
                    jine=shangpin_jiage,
                    openid=user_openid,
                    session_key=session_key,
                    beizhu=beizhu
                )

                if not pay_params:
                    raise Exception('虚拟支付参数生成失败')

                return Response({
                    'code': 0,
                    'msg': '订单创建成功',
                    'data': {
                        'dingdanid': dingdanid,
                        'payParams': pay_params
                    }
                })

        except Exception as e:
            logger.error(f"虚拟支付下单失败: {e}", exc_info=True)
            return Response({'code': 99, 'msg': '系统错误', 'data': None})

    def _exchange_code_for_session_key(self, code):
        """通过 jscode2session 换取 openid 和 session_key"""
        url = 'https://api.weixin.qq.com/sns/jscode2session'
        params = {
            'appid': settings.WEIXIN_APPID,
            'secret': settings.WEIXIN_SECRET,
            'js_code': code,
            'grant_type': 'authorization_code'
        }
        try:
            resp = requests.get(url, params=params, timeout=5)
            data = resp.json()
            if 'openid' in data and 'session_key' in data:
                return data
            else:
                logger.error(f"jscode2session 失败: {data}")
        except Exception as e:
            logger.error(f"换取 session_key 异常: {e}")
        return None

    def generate_virtual_pay_params(self, dingdanid, jine, openid, session_key, beizhu=''):
        """生成代币虚拟支付参数"""
        env = settings.VP_ENV
        appkey = settings.VP_APPKEY_SANDBOX if env == 1 else settings.VP_APPKEY
        offer_id = settings.VP_OFFER_ID
        product_id = 'coin_1'  # 代币道具ID，已配置

        # 代币购买数量 = 总价（分）
        buy_quantity = int(float(jine) * 100)

        # 构建 signData（驼峰字段，代币模式不含 goodsPrice）
        sign_data = {
            "offerId": offer_id,
            "env": env,
            "openid": openid,
            "outTradeNo": dingdanid,
            "productId": product_id,
            "buyQuantity": buy_quantity,
            "attach": beizhu or '游戏陪玩订单',
            "currencyType": "CNY",
            "zoneId": "1"
        }
        sign_data_str = json.dumps(sign_data, separators=(',', ':'), ensure_ascii=False)

        # 签名计算
        uri = "requestVirtualPayment"
        msg = uri + "&" + sign_data_str
        pay_sig = hmac.new(appkey.encode('utf-8'), msg.encode('utf-8'), hashlib.sha256).hexdigest()
        signature = hmac.new(session_key.encode('utf-8'), sign_data_str.encode('utf-8'), hashlib.sha256).hexdigest()

        return {
            "signData": sign_data_str,
            "paySig": pay_sig,
            "signature": signature,
            "mode": "short_series_coin"
        }


class VirtualPayNotifyView(APIView):
    """
    虚拟支付回调接口
    业务处理逻辑与原 WechatPayNotifyView 完全一致，
    仅 XML 解析和签名验证方式不同
    """
    permission_classes = [permissions.AllowAny]

    def post(self, request):
        try:
            # 1. 验证签名（虚拟支付回调使用 HMAC-SHA256）
            body = request.body
            signature = request.headers.get('Wechatpay-Signature')
            if not self._verify_virtual_signature(body, signature):
                logger.warning("虚拟支付回调签名验证失败")
                return HttpResponse('FAIL', status=401)

            # 2. 解析 XML 通知
            data = xmltodict.parse(body.decode('utf-8')).get('xml', {})
            event = data.get('Event')
            if event != 'xpay_goods_deliver_notify':
                return HttpResponse('success')

            out_trade_no = data.get('OutTradeNo')
            transaction_id = ''
            wechat_pay_info = data.get('WeChatPayInfo', {})
            if isinstance(wechat_pay_info, dict):
                transaction_id = wechat_pay_info.get('TransactionId', '')

            # 3. 执行支付成功处理（复用原 _handle_success 逻辑）
            self._handle_success(out_trade_no, transaction_id)
            return HttpResponse('success')

        except Exception as e:
            logger.error(f"虚拟支付回调异常: {e}", exc_info=True)
            return HttpResponse('success')

    def _verify_virtual_signature(self, body, signature):
        """验证虚拟支付回调签名"""
        if not signature:
            return False
        appkey = settings.VP_APPKEY_SANDBOX if settings.VP_ENV == 1 else settings.VP_APPKEY
        calc_sign = hmac.new(appkey.encode('utf-8'), body, hashlib.sha256).hexdigest()
        return hmac.compare_digest(calc_sign, signature)

    @transaction.atomic
    def _handle_success(self, out_trade_no, transaction_id):
        """支付成功处理（与原 WechatPayNotifyView._handle_success 完全相同）"""
        logger.info(f"虚拟支付回调成功, out_trade_no={out_trade_no}, transaction_id={transaction_id}")

        try:
            dingdan = Dingdan.objects.select_for_update().filter(dingdan_id=out_trade_no).first()
        except Exception as e:
            logger.error(f"查询订单异常: {e}")
            raise

        if not dingdan:
            logger.error(f"订单不存在: {out_trade_no}")
            return

        # 幂等处理
        if dingdan.zhuangtai != 9:
            logger.info(f"订单 {out_trade_no} 已处理过，状态={dingdan.zhuangtai}，跳过")
            return

        # 保存交易号
        dingdan.wechat_transaction_id = transaction_id or 'virtual_' + out_trade_no

        # 更新状态
        if dingdan.zhiding_id and dingdan.zhiding_id.strip():
            dingdan.zhuangtai = 7
        else:
            dingdan.zhuangtai = 1
        dingdan.save()

        # 废弃同商品其他未支付订单
        Dingdan.objects.filter(
            user1_id=dingdan.user1_id,
            shangpin_id=dingdan.shangpin_id,
            zhuangtai=9
        ).exclude(dingdan_id=out_trade_no).update(zhuangtai=25)

        # 更新老板数据
        try:
            laoban_id = dingdan.pingtai_kuozhan.laoban_id if hasattr(dingdan, 'pingtai_kuozhan') else None
            if laoban_id:
                user_main = UserMain.objects.filter(yonghuid=laoban_id).first()
                if user_main and hasattr(user_main, 'boss_profile'):
                    boss = user_main.boss_profile
                    boss.zonge = (boss.zonge or 0) + (dingdan.jine or 0)
                    boss.alldingdan = (boss.alldingdan or 0) + 1
                    boss.save()
        except Exception as e:
            logger.error(f"更新老板数据异常: {e}")

        # 更新商品库存
        if dingdan.shangpin_id:
            Shangpin.objects.filter(id=dingdan.shangpin_id).update(kucun=F('kucun') - 1)

        # 更新收支记录
        self._update_szjilu(dingdan.jine)
        update_daily_income(dingdan.jine)
        sync_order_to_partners(dingdan.dingdan_id)

        # 异步广播
        self._broadcast_async(dingdan)

        logger.info(f"订单 {out_trade_no} 支付成功处理完成")

    def _update_szjilu(self, jine):
        """更新收支记录表（与原逻辑一致）"""
        try:
            jine_decimal = Decimal(str(jine))
            with transaction.atomic():
                szjilu, created = Szjilu.objects.select_for_update().get_or_create(
                    id=1,
                    defaults={
                        'zongsy': Decimal('0.00'), 'zongls': Decimal('0.00'),
                        'zongzc': Decimal('0.00'), 'jrzc': Decimal('0.00'),
                        'jrls': Decimal('0.00')
                    }
                )
                szjilu.zongsy += jine_decimal
                szjilu.zongls += jine_decimal
                szjilu.jrls += jine_decimal
                szjilu.save()
        except Exception as e:
            logger.error(f"更新收支记录失败: {e}")

    def _broadcast_async(self, dingdan):
        """异步广播（与原一致）"""
        try:
            def task():
                try:
                    from . import WeixinBroadcastSender
                    order_info = {
                        'dingdan_id': dingdan.dingdan_id,
                        'game_type': self._get_game_type_name(dingdan.leixing_id),
                        'amount': str(dingdan.jine),
                        'order_desc': (dingdan.jieshao or '')[:50],
                    }
                    sender = WeixinBroadcastSender()
                    sender.broadcast_order(order_info)
                except Exception as e:
                    logger.error(f"广播任务异常: {e}")

            thread = threading.Thread(target=task)
            thread.daemon = True
            thread.start()
        except Exception as e:
            logger.error(f"启动广播线程异常: {e}")

    def _get_game_type_name(self, leixing_id):
        try:
            from shangpin.models import ShangpinLeixing
            gt = ShangpinLeixing.objects.filter(id=leixing_id).first()
            return gt.jieshao if gt else '游戏订单'
        except Exception:
            return '游戏订单'


class VirtualPaymentVerifyView(APIView):
    """
    虚拟支付复查接口
    逻辑与原 PaymentVerifyView 完全一致，仅查单方式改为虚拟支付查单 API
    """
    permission_classes = [permissions.IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        try:
            dingdanid = request.data.get('dingdanid')
            if not dingdanid:
                return Response({'code': 1, 'msg': '订单ID不能为空'})

            dingdan = Dingdan.objects.filter(dingdan_id=dingdanid).first()
            if not dingdan:
                return Response({'code': 2, 'msg': '订单不存在'})

            current_user = request.user
            user_identifier = f"Boss{current_user.yonghuid}"
            if dingdan.user1_id != user_identifier:
                return Response({'code': 403, 'msg': '无权访问'})

            # 状态已是成功则直接返回
            if dingdan.zhuangtai in [1, 7]:
                return Response({
                    'code': 0,
                    'msg': '订单状态正常',
                    'data': {'dingdanid': dingdanid, 'zhuangtai': dingdan.zhuangtai}
                })

            # 状态为未支付，主动查单
            if dingdan.zhuangtai == 9:
                from django.core.cache import cache
                lock_key = f"virtual_verify_lock_{dingdanid}"
                if not cache.add(lock_key, "locked", timeout=10):
                    return Response({'code': 1, 'msg': '订单正在处理中，请稍后'})

                try:
                    trade_state, transaction_id = self._query_virtual_payment(dingdanid)
                    if trade_state == 'SUCCESS':
                        self._process_payment_success(dingdan, transaction_id, current_user.yonghuid)
                        dingdan.refresh_from_db()
                        return Response({
                            'code': 0,
                            'msg': '支付成功',
                            'data': {'dingdanid': dingdanid, 'zhuangtai': dingdan.zhuangtai}
                        })
                    elif trade_state in ['NOTPAY', 'USERPAYING']:
                        return Response({'code': 1, 'msg': '支付中', 'data': {'zhuangtai': 9}})
                    else:
                        return Response({'code': 2, 'msg': '支付失败'})
                except Exception as e:
                    logger.error(f"查询虚拟支付异常: {e}")
                    return Response({'code': 1, 'msg': '查询失败，请稍后重试'})
                finally:
                    cache.delete(lock_key)

            # 其他异常状态
            status_msg = {
                2: '订单已取消', 3: '订单已完成', 4: '退款审核中',
                5: '已退款', 6: '退款失败', 8: '结算中', 0: '订单已作废'
            }
            return Response({'code': 3, 'msg': status_msg.get(dingdan.zhuangtai, '订单状态异常'),
                             'data': {'zhuangtai': dingdan.zhuangtai}})

        except Exception as e:
            logger.error(f"复查接口异常: {e}", exc_info=True)
            return Response({'code': 99, 'msg': '系统错误'})

    @transaction.atomic
    def _process_payment_success(self, dingdan, transaction_id, operator_id):
        """支付成功原子操作，与旧流程完全一致"""
        dingdan = Dingdan.objects.select_for_update().get(pk=dingdan.pk)
        if dingdan.zhuangtai != 9:
            return

        dingdan.zhuangtai = 7 if (dingdan.zhiding_id and dingdan.zhiding_id.strip()) else 1
        dingdan.wechat_transaction_id = transaction_id
        dingdan.clkf = operator_id
        dingdan.save()

        Dingdan.objects.filter(
            user1_id=dingdan.user1_id,
            shangpin_id=dingdan.shangpin_id,
            zhuangtai=9
        ).exclude(dingdan_id=dingdan.dingdan_id).update(zhuangtai=25)

        laoban_id = dingdan.pingtai_kuozhan.laoban_id if hasattr(dingdan, 'pingtai_kuozhan') else None
        if laoban_id:
            user_main = UserMain.objects.filter(yonghuid=laoban_id).first()
            if user_main and hasattr(user_main, 'boss_profile'):
                boss = user_main.boss_profile
                boss.zonge = (boss.zonge or 0) + (dingdan.jine or 0)
                boss.alldingdan = (boss.alldingdan or 0) + 1
                boss.save()

        if dingdan.shangpin_id:
            Shangpin.objects.filter(id=dingdan.shangpin_id).update(kucun=F('kucun') - 1)

        self._update_szjilu(dingdan.jine)
        update_daily_income(dingdan.jine)
        sync_order_to_partners(dingdan.dingdan_id)

    def _query_virtual_payment(self, out_trade_no):
        """调用虚拟支付查单接口"""
        uri = "/xpay/query_order"
        appkey = settings.VP_APPKEY_SANDBOX if settings.VP_ENV == 1 else settings.VP_APPKEY
        offer_id = settings.VP_OFFER_ID
        openid = self.request.user.openid

        post_data = {
            "offer_id": offer_id,
            "openid": openid,
            "out_trade_no": out_trade_no,
            "env": settings.VP_ENV,
        }
        body = json.dumps(post_data, separators=(',', ':'))
        msg = uri + "&" + body
        pay_sig = hmac.new(appkey.encode(), msg.encode(), hashlib.sha256).hexdigest()

        headers = {'Content-Type': 'application/json'}
        url = f"https://api.weixin.qq.com{uri}?pay_sig={pay_sig}"
        resp = requests.post(url, data=body, headers=headers, timeout=10)
        result = resp.json()

        if result.get('errcode') == 0:
            order = result.get('order', {})
            state = order.get('state', 1)      # 1=未支付, 2=已支付
            if state == 2:
                return 'SUCCESS', order.get('transaction_id', '')
            elif state == 1:
                return 'USERPAYING', ''
            else:
                return 'CLOSED', ''
        else:
            raise Exception(f"虚拟支付查单失败: {result.get('errmsg')}")

    def _update_szjilu(self, jine):
        """更新收支记录（同原）"""
        try:
            jine_decimal = Decimal(str(jine))
            with transaction.atomic():
                szjilu, created = Szjilu.objects.select_for_update().get_or_create(
                    id=1,
                    defaults={
                        'zongsy': Decimal('0.00'), 'zongls': Decimal('0.00'),
                        'zongzc': Decimal('0.00'), 'jrzc': Decimal('0.00'),
                        'jrls': Decimal('0.00')
                    }
                )
                szjilu.zongsy += jine_decimal
                szjilu.zongls += jine_decimal
                szjilu.jrls += jine_decimal
                szjilu.save()
        except Exception as e:
            logger.error(f"更新收支记录失败: {e}")


# 保留原有支付失败处理接口（若需要，可直接复用原 PaymentFailView）
# 这里提供一份与旧版一致的实现，确保前端调用 /dingdan/shibai 依旧可用
class VirtualPaymentFailView(APIView):
    """
    支付失败处理（与旧 PaymentFailView 逻辑一致）
    仅删除状态为9的订单
    """
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        try:
            dingdanid = request.data.get('dingdanid')
            if not dingdanid:
                return Response({'code': 1, 'msg': '订单ID不能为空'})

            with transaction.atomic():
                dingdan = Dingdan.objects.select_for_update().filter(dingdan_id=dingdanid).first()
                if not dingdan:
                    return Response({'code': 2, 'msg': '订单不存在'})
                if dingdan.zhuangtai != 9:
                    return Response({'code': 3, 'msg': '只能删除未支付的订单'})

                DingdanPingtai.objects.filter(dingdan=dingdan).delete()
                dingdan.delete()

            return Response({'code': 0, 'msg': '订单已删除'})
        except Exception as e:
            return Response({'code': 99, 'msg': f'删除订单失败: {str(e)}'})








import json
import hmac
import hashlib
import logging
import time
import random
from decimal import Decimal

import requests
from django.conf import settings
from django.db import transaction
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import permissions
from rest_framework.parsers import JSONParser
from django.http import HttpResponse
import xmltodict
import threading

from .models import Dingdan, DingdanPingtai, Lilubiao
from shangpin.models import Shangpin
from yonghu.models import UserMain, UserDashou
from peizhi.models import Szjilu
from .utils import update_daily_income, sync_order_to_partners

logger = logging.getLogger(__name__)


class VirtualCreateOrderView(APIView):
    """
    虚拟支付创建订单
    """
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        try:
            # 1. 获取参数
            shangpin_id = request.data.get('shangpin_id')
            nicheng = request.data.get('nicheng', '').strip()
            beizhu = request.data.get('beizhu', '').strip()
            zhiding = request.data.get('zhiding', '').strip()
            jine = request.data.get('jine', 0)

            if zhiding:
                return Response({'code': 8, 'msg': '指定功能尚未开启', 'data': None})

            if not shangpin_id:
                return Response({'code': 1, 'msg': '商品ID不能为空', 'data': None})
            if not nicheng:
                return Response({'code': 2, 'msg': '游戏昵称不能为空', 'data': None})

            # 2. 查商品
            shangpin = Shangpin.objects.filter(id=shangpin_id).first()
            if not shangpin:
                return Response({'code': 4, 'msg': '商品不存在', 'data': None})
            if hasattr(shangpin, 'kucun') and shangpin.kucun <= 0:
                return Response({'code': 5, 'msg': '商品库存不足', 'data': None})

            shangpin_jiage = getattr(shangpin, 'jiage', 0)
            if not shangpin_jiage:
                return Response({'code': 6, 'msg': '商品价格异常', 'data': None})
            shangpin_tupian = getattr(shangpin, 'tupian_url', None)

            # 3. 生成订单ID
            timestamp = int(time.time())
            timestamp_ns = int(time.time_ns() // 1000) % 1000000
            random_num = random.randint(0, 99)
            dingdanid = f"PT{timestamp:011d}{timestamp_ns:06d}{random_num:02d}"

            # 4. 计算分成（保留原有逻辑）
            dashou_lilu = Lilubiao.objects.filter(fadanpingtai='1').first()
            if not dashou_lilu:
                return Response({'code': 9, 'msg': '系统利率配置不完整', 'data': None})
            if shangpin.kaioi_ewai_dashou_fencheng and shangpin.ewai_dashou_fencheng is not None:
                dashou_fencheng = shangpin.ewai_dashou_fencheng
            else:
                dashou_fencheng = Decimal(str(shangpin_jiage)) * Decimal(str(dashou_lilu.lilu))

            with transaction.atomic():
                current_user = request.user
                user_openid = getattr(current_user, 'openid', '')
                if not user_openid:
                    return Response({'code': 10, 'msg': '用户openid不存在', 'data': None})

                # 创建订单
                order_data = {
                    'dingdan_id': dingdanid,
                    'zhuangtai': 9,
                    'jine': shangpin_jiage,
                    'fadan_pingtai': 1,
                    'dashou_fencheng': dashou_fencheng,
                    'zhiding_id': None,
                    'shangpin_id': shangpin_id,
                    'yaoqiuleixing': getattr(shangpin, 'yaoqiuleixing', None),
                    'huiyuan_id': getattr(shangpin, 'huiyuan_id', ''),
                    'yongjin': getattr(shangpin, 'yongjin', 0),
                    'jieshao': getattr(shangpin, 'jieshao', ''),
                    'beizhu': beizhu,
                    'nicheng': nicheng,
                    'tupian': shangpin_tupian,
                    'user1_id': f"Boss{current_user.yonghuid}",
                    'leixing_id': shangpin.leixing_id
                }
                dingdan = Dingdan.objects.create(**order_data)
                DingdanPingtai.objects.create(
                    dingdan=dingdan,
                    laoban_id=current_user.yonghuid,
                )

                # 获取或刷新 session_key
                session_key = getattr(current_user, 'session_key', None)
                if not session_key:
                    code = request.data.get('code')
                    if not code:
                        raise Exception('缺少登录凭证code')
                    wx_resp = self._exchange_code_for_session_key(code)
                    if wx_resp is None or wx_resp.get('openid') != user_openid:
                        raise Exception('微信认证失败')
                    session_key = wx_resp['session_key']
                    current_user.session_key = session_key
                    current_user.save(update_fields=['session_key'])

                # 生成支付参数
                pay_params = self.generate_virtual_pay_params(
                    dingdanid=dingdanid,
                    jine=shangpin_jiage,
                    openid=user_openid,
                    session_key=session_key,
                    beizhu=beizhu
                )

                return Response({
                    'code': 0,
                    'msg': '订单创建成功',
                    'data': {
                        'dingdanid': dingdanid,
                        'payParams': pay_params
                    }
                })

        except Exception as e:
            logger.error(f"虚拟支付下单失败: {e}", exc_info=True)
            return Response({'code': 99, 'msg': f'系统错误', 'data': None})

    def _exchange_code_for_session_key(self, code):
        url = 'https://api.weixin.qq.com/sns/jscode2session'
        params = {
            'appid': settings.WEIXIN_APPID,
            'secret': settings.WEIXIN_SECRET,
            'js_code': code,
            'grant_type': 'authorization_code'
        }
        try:
            resp = requests.get(url, params=params, timeout=5)
            data = resp.json()
            if 'openid' in data and 'session_key' in data:
                return data
        except Exception as e:
            logger.error(f"换取 session_key 失败: {e}")
        return None

    def generate_virtual_pay_params(self, dingdanid, jine, openid, session_key, beizhu=''):
        """生成虚拟支付签名参数"""
        env = settings.VP_ENV
        appkey = settings.VP_APPKEY_SANDBOX if env == 1 else settings.VP_APPKEY
        offer_id = settings.VP_OFFER_ID
        product_id = settings.VP_PRODUCT_ID

        # 金额转换：元 → 分
        goods_price_fen = int(float(jine) * 100)

        # signData —— 必须用驼峰字段 ！！！
        sign_data = {
            "offerId": offer_id,
            "env": env,
            "openid": openid,
            "outTradeNo": dingdanid,
            "productId": product_id,
            "buyQuantity": 1,              # 数量固定为 1
            "goodsPrice": goods_price_fen, # 道具真实价格（分）
            "attach": beizhu or '游戏陪玩订单',
            "currencyType": "CNY",
            "zoneId": "1"
        }
        sign_data_str = json.dumps(sign_data, separators=(',', ':'), ensure_ascii=False)

        # 签名
        uri = "requestVirtualPayment"
        msg = uri + "&" + sign_data_str
        pay_sig = hmac.new(appkey.encode('utf-8'), msg.encode('utf-8'), hashlib.sha256).hexdigest()
        signature = hmac.new(session_key.encode('utf-8'), sign_data_str.encode('utf-8'), hashlib.sha256).hexdigest()

        # 返回给前端，这三个字段必须存在：signData、paySig、signature
        return {
            "signData": sign_data_str,
            "paySig": pay_sig,
            "signature": signature,
        }
































import string

import xmltodict
import logging

from django.db import transaction, models

from rest_framework import permissions, status
from rest_framework.parsers import JSONParser

from shangpin.models import Shangpin


logger = logging.getLogger(__name__)



from django.core.cache import cache

import json
import hmac
import hashlib
import logging
import time
import traceback
from decimal import Decimal

import requests
from django.conf import settings
from django.db import transaction, models
from rest_framework import permissions
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.parsers import JSONParser



logger = logging.getLogger(__name__)


class VirtualCreateOrderView(APIView):
    """虚拟支付 - 创建订单（逻辑与旧下单 100% 相同）"""
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        try:
            # 1. 获取参数
            shangpin_id = request.data.get('shangpin_id')
            nicheng = request.data.get('nicheng', '').strip()
            beizhu = request.data.get('beizhu', '').strip()
            zhiding = request.data.get('zhiding', '').strip()
            jine = request.data.get('jine', 0)

            # 2. 参数校验
            if not shangpin_id:
                return Response({'code': 1, 'msg': '商品ID不能为空', 'data': None})
            if not nicheng:
                return Response({'code': 2, 'msg': '游戏昵称不能为空', 'data': None})
            if len(nicheng) > 50:
                return Response({'code': 3, 'msg': '游戏昵称过长', 'data': None})

            # 3. 商品校验
            shangpin = Shangpin.objects.filter(id=shangpin_id).first()
            if not shangpin:
                return Response({'code': 4, 'msg': '商品不存在', 'data': None})

            is_valid, err_msg, _ = validate_shangpin_and_dianpu(shangpin_id)
            if not is_valid:
                return Response({'code': 5, 'msg': err_msg, 'data': None})

            if hasattr(shangpin, 'kucun') and shangpin.kucun <= 0:
                return Response({'code': 5, 'msg': '商品库存不足', 'data': None})

            shangpin_jiage = getattr(shangpin, 'jiage', 0)
            if not shangpin_jiage:
                return Response({'code': 6, 'msg': '商品价格异常', 'data': None})
            shangpin_tupian = getattr(shangpin, 'tupian_url', None)

            # 4. 指定打手校验（与你原有逻辑完全一致）
            zhiding_id_value = None
            if zhiding:
                zhiding_user = UserMain.objects.filter(yonghuid=zhiding).first()
                if not zhiding_user:
                    return Response({'code': 7, 'msg': '指定打手不存在', 'data': None})
                dashou_profile = UserDashou.objects.filter(user=zhiding_user).first()
                if not dashou_profile:
                    return Response({'code': 8, 'msg': '指定用户不存在或已封禁', 'data': None})
                if getattr(dashou_profile, 'zhanghaozhuangtai', 0) == 0:
                    return Response({'code': 8, 'msg': '指定用户不存在或已封禁', 'data': None})
                zhiding_id_value = zhiding

            # 5. 生成订单ID（复用原格式）
            timestamp = int(time.time())
            timestamp_ns = int(time.time_ns() // 1000) % 1000000
            random_num = random.randint(0, 99)
            dingdanid = f"PT{timestamp:011d}{timestamp_ns:06d}{random_num:02d}"

            # 6. 分成计算（与原逻辑完全相同）
            dashou_lilu = Lilubiao.objects.filter(fadanpingtai='1').first()
            if not dashou_lilu:
                return Response({'code': 9, 'msg': '系统利率配置不完整', 'data': None})

            if shangpin.kaioi_ewai_dashou_fencheng and shangpin.ewai_dashou_fencheng is not None:
                dashou_fencheng = shangpin.ewai_dashou_fencheng
            else:
                dashou_fencheng = Decimal(str(shangpin_jiage)) * Decimal(str(dashou_lilu.lilu))

            # 7. 数据库事务（创建订单 + 扩展表 + 生成虚拟支付参数）
            with transaction.atomic():
                current_user = request.user
                laoban_yonghuid = getattr(current_user, 'yonghuid', '')
                user_openid = getattr(current_user, 'openid', '')

                if not user_openid:
                    return Response({'code': 10, 'msg': '用户openid不存在', 'data': None})

                # 订单主表数据（字段与原订单 100% 一致）
                order_data = {
                    'dingdan_id': dingdanid,
                    'zhuangtai': 9,  # 未支付
                    'jine': shangpin_jiage,
                    'fadan_pingtai': 1,
                    'dashou_fencheng': dashou_fencheng,
                    'zhiding_id': zhiding_id_value,
                    'shangpin_id': shangpin_id,
                    'yaoqiuleixing': getattr(shangpin, 'yaoqiuleixing', None),
                    'huiyuan_id': getattr(shangpin, 'huiyuan_id', ''),
                    'yongjin': getattr(shangpin, 'yongjin', 0),
                    'jieshao': getattr(shangpin, 'jieshao', ''),
                    'beizhu': beizhu,
                    'nicheng': nicheng,
                    'tupian': shangpin_tupian,
                    'user1_id': f"Boss{request.user.yonghuid}",
                    'leixing_id': shangpin.leixing_id,
                }
                dingdan = Dingdan.objects.create(**order_data)

                # 扩展表（与原逻辑完全相同）
                dianpu_id, pingtai_shouyi, dianpu_shouyi = calculate_pingtai_and_dianpu_shouyi(
                    shangpin_id=shangpin_id,
                    dingdan_jiage=shangpin_jiage,
                    dashou_fencheng=dashou_fencheng,
                )
                pingtaikuozhan_data = {
                    'dingdan': dingdan,
                    'laoban_id': laoban_yonghuid,
                    'pingtai_shouyi': pingtai_shouyi,
                }
                if dianpu_id:
                    pingtaikuozhan_data['dianpu_id'] = dianpu_id
                    pingtaikuozhan_data['dianpu_shouyi'] = dianpu_shouyi
                else:
                    pingtaikuozhan_data['dianpu_shouyi'] = Decimal('0.00')
                DingdanPingtai.objects.create(**pingtaikuozhan_data)

                # ★ 唯一改动：生成虚拟支付签名
                pay_params = self.generate_virtual_pay_params(
                    dingdanid=dingdanid,
                    jine=shangpin_jiage,
                    user_ip=self.get_client_ip(request),
                    openid=user_openid,
                    request=request,
                    beizhu=beizhu,
                )

                if not pay_params:
                    raise Exception('虚拟支付参数生成失败')

                return Response({
                    'code': 0,
                    'msg': '订单创建成功',
                    'data': {
                        'dingdanid': dingdanid,
                        'payParams': pay_params,  # 结构适配 wx.requestVirtualPayment
                    }
                })

        except Exception as e:
            logger.error(f"虚拟支付下单失败: {e}", exc_info=True)
            return Response({'code': 99, 'msg': f'系统错误: {str(e)}', 'data': None})

    def get_client_ip(self, request):
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            return x_forwarded_for.split(',')[0]
        return request.META.get('REMOTE_ADDR', '127.0.0.1')

    def generate_virtual_pay_params(self, dingdanid, jine, user_ip, openid, request, beizhu=''):
        """生成虚拟支付所需签名和参数（完全符合微信官方规范）"""
        import random, string

        env = settings.VP_ENV
        appkey = settings.VP_APPKEY_SANDBOX if env == 1 else settings.VP_APPKEY
        offer_id = settings.VP_OFFER_ID

        # 获取 session_key（必须，请在 UserMain 模型中添加 session_key 字段，登录时存储）
        current_user = request.user
        session_key = getattr(current_user, 'session_key', None)
        if not session_key:
            raise Exception('用户session_key缺失，请确保登录时存储了session_key')

        total_fee = int(float(jine) * 100)  # 金额：分

        # 构建 signData（决定签名内容，字段顺序、JSON格式必须一致）
        sign_data = {
            "offer_id": offer_id,
            "env": env,
            "openid": openid,
            "out_trade_no": dingdanid,
            "product_id": "1",  # 默认道具ID，可后续按商品配置
            "amount": total_fee,
            "attach": beizhu or '游戏陪玩订单',
            "user_ip": user_ip,
            "currency_type": "CNY",
            "zone_id": "1",
        }
        sign_data_str = json.dumps(sign_data, separators=(',', ':'), ensure_ascii=False)

        # 计算 pay_sig（支付签名）
        uri = "requestVirtualPayment"
        msg = uri + "&" + sign_data_str
        pay_sig = hmac.new(appkey.encode('utf-8'), msg.encode('utf-8'), hashlib.sha256).hexdigest()

        # 计算 signature（用户态签名）
        signature = hmac.new(
            session_key.encode('utf-8'),
            sign_data_str.encode('utf-8'),
            hashlib.sha256
        ).hexdigest()

        return {
            "offerId": offer_id,
            "env": env,
            "zoneId": "1",
            "outTradeNo": dingdanid,
            "productId": "1",
            "amount": total_fee,  # 单位：分
            "signData": sign_data_str,  # JSON字符串
            "paySig": pay_sig,
            "signature": signature,
        }


class VirtualPayNotifyView(APIView):
    """虚拟支付 - 支付成功推送处理（替代原 WechatPayNotifyView）"""
    permission_classes = [permissions.AllowAny]

    def post(self, request):
        try:
            body = request.body.decode('utf-8')
            # 微信推送可能是 XML，也可能是 JSON，这里按 XML 解析（兼容主流情况）
            import xmltodict
            data = xmltodict.parse(body)['xml']

            event = data.get('Event')
            if event != 'xpay_goods_deliver_notify':
                return HttpResponse('success')

            out_trade_no = data.get('OutTradeNo')
            wechat_pay_info = data.get('WeChatPayInfo', {})
            transaction_id = ''
            if isinstance(wechat_pay_info, dict):
                transaction_id = wechat_pay_info.get('TransactionId', '')

            self._handle_payment_success(out_trade_no, transaction_id)
            return HttpResponse('success')

        except Exception as e:
            logger.error(f"虚拟支付回调异常: {e}", exc_info=True)
            # 即使出错也返回 success，防止微信重复推送
            return HttpResponse('success')

    @transaction.atomic
    def _handle_payment_success(self, out_trade_no, transaction_id):
        """支付成功处理，与原 WechatPayNotifyView._handle_success 完全相同"""
        dingdan = Dingdan.objects.select_for_update().filter(dingdan_id=out_trade_no).first()
        if not dingdan or dingdan.zhuangtai != 9:
            logger.info(f"订单 {out_trade_no} 已处理或不存在，状态: {getattr(dingdan, 'zhuangtai', 'N/A')}")
            return

        # 保存交易号
        dingdan.wechat_transaction_id = transaction_id or ('virtual_' + out_trade_no)

        # 状态更新
        if dingdan.zhiding_id and dingdan.zhiding_id.strip():
            dingdan.zhuangtai = 7
        else:
            dingdan.zhuangtai = 1
        dingdan.save()

        # 废弃同一用户同一商品下其他未支付订单
        Dingdan.objects.filter(
            user1_id=dingdan.user1_id,
            shangpin_id=dingdan.shangpin_id,
            zhuangtai=9,
        ).exclude(dingdan_id=out_trade_no).update(zhuangtai=25)

        # 更新老板消费数据
        try:
            laoban_id = dingdan.pingtai_kuozhan.laoban_id if hasattr(dingdan, 'pingtai_kuozhan') else None
            if laoban_id:
                user_main = UserMain.objects.filter(yonghuid=laoban_id).first()
                if user_main and hasattr(user_main, 'boss_profile'):
                    boss = user_main.boss_profile
                    boss.zonge = (boss.zonge or 0) + (dingdan.jine or 0)
                    boss.alldingdan = (boss.alldingdan or 0) + 1
                    boss.save()
        except Exception as e:
            logger.error(f"更新老板数据失败: {e}")

        # 更新商品库存
        if dingdan.shangpin_id:
            Shangpin.objects.filter(id=dingdan.shangpin_id).update(kucun=F('kucun') - 1)

        # 商品/店铺每日统计
        try:
            if dingdan.shangpin_id:
                pingtai_shouyi = Decimal('0.00')
                dianpu_shouyi = Decimal('0.00')
                if hasattr(dingdan, 'pingtai_kuozhan'):
                    pingtai_shouyi = dingdan.pingtai_kuozhan.pingtai_shouyi or Decimal('0.00')
                    dianpu_shouyi = dingdan.pingtai_kuozhan.dianpu_shouyi or Decimal('0.00')

                update_shangpin_daily_stat(
                    shangpin_id=dingdan.shangpin_id,
                    caozuo_leixing=1,
                    dingdan_jiage=dingdan.jine,
                    pingtai_shouyi=pingtai_shouyi,
                    dianpu_zongshouyi=dianpu_shouyi,
                )
            dianpu_id = dingdan.pingtai_kuozhan.dianpu_id if hasattr(dingdan, 'pingtai_kuozhan') else None
            if dianpu_id:
                dianpu_shouyi = dingdan.pingtai_kuozhan.dianpu_shouyi or Decimal('0.00')
                update_dianpu_daily_stat(
                    dianpu_id=dianpu_id,
                    caozuo_leixing=1,
                    dingdan_jiage=dingdan.jine,
                    dianpu_shouyi=dianpu_shouyi,
                )
        except Exception as e:
            logger.error(f"统计更新失败: {e}")

        # 收支记录
        self._update_szjilu(dingdan.jine)
        update_daily_income(dingdan.jine)
        sync_order_to_partners(dingdan.dingdan_id)

    def _update_szjilu(self, jine):
        try:
            jine_decimal = Decimal(str(jine))
            with transaction.atomic():
                szjilu, created = Szjilu.objects.select_for_update().get_or_create(
                    id=1,
                    defaults={
                        'zongsy': Decimal('0.00'),
                        'zongls': Decimal('0.00'),
                        'zongzc': Decimal('0.00'),
                        'jrzc': Decimal('0.00'),
                        'jrls': Decimal('0.00'),
                    }
                )
                szjilu.zongsy += jine_decimal
                szjilu.zongls += jine_decimal
                szjilu.jrls += jine_decimal
                szjilu.save()
        except Exception as e:
            logger.error(f"收支记录更新失败: {e}")


class VirtualPaymentVerifyView(APIView):
    """
    虚拟支付 - 复查接口（支付成功后前端调用确认订单状态）
    与原 PaymentVerifyView 逻辑完全相同，仅查询支付状态的接口改为虚拟支付
    """
    permission_classes = [permissions.IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        try:
            dingdanid = request.data.get('dingdanid')
            if not dingdanid:
                return Response({'code': 1, 'msg': '订单ID不能为空'})

            dingdan = Dingdan.objects.filter(dingdan_id=dingdanid).first()
            if not dingdan:
                return Response({'code': 2, 'msg': '订单不存在'})

            current_user = request.user
            if dingdan.user1_id != f"Boss{current_user.yonghuid}":
                return Response({'code': 403, 'msg': '无权访问'})

            # 若状态已是已支付，直接返回
            if dingdan.zhuangtai in [1, 7]:
                return Response({
                    'code': 0,
                    'msg': '订单状态正常',
                    'data': {'dingdanid': dingdanid, 'zhuangtai': dingdan.zhuangtai},
                })

            if dingdan.zhuangtai == 9:
                # 主动查询虚拟支付订单状态
                trade_state, transaction_id = self._query_virtual_payment(dingdanid)
                if trade_state == 'SUCCESS':
                    self._process_payment_success(dingdan, transaction_id, current_user.yonghuid)
                    dingdan.refresh_from_db()
                    return Response({
                        'code': 0,
                        'msg': '支付成功',
                        'data': {'dingdanid': dingdanid, 'zhuangtai': dingdan.zhuangtai},
                    })
                elif trade_state in ['NOTPAY', 'USERPAYING']:
                    return Response({'code': 1, 'msg': '支付中', 'data': {'zhuangtai': 9}})
                else:
                    return Response({'code': 2, 'msg': '支付失败'})
            else:
                status_msg = {
                    2: '订单已取消', 3: '订单已完成', 4: '退款审核中',
                    5: '已退款', 6: '退款失败', 8: '结算中', 0: '订单已作废',
                }
                return Response({'code': 3, 'msg': status_msg.get(dingdan.zhuangtai, '订单状态异常')})

        except Exception as e:
            logger.error(f"复查异常: {e}", exc_info=True)
            return Response({'code': 99, 'msg': f'系统错误: {str(e)}'})

    def _query_virtual_payment(self, out_trade_no):
        """调用 /xpay/query_order 查询虚拟支付订单状态"""
        uri = "/xpay/query_order"
        appkey = settings.VP_APPKEY_SANDBOX if settings.VP_ENV == 1 else settings.VP_APPKEY
        offer_id = settings.VP_OFFER_ID
        openid = self.request.user.openid

        post_data = {
            "offer_id": offer_id,
            "openid": openid,
            "out_trade_no": out_trade_no,
            "env": settings.VP_ENV,
        }
        body = json.dumps(post_data, separators=(',', ':'))

        # 计算签名
        msg = uri + "&" + body
        pay_sig = hmac.new(appkey.encode(), msg.encode(), hashlib.sha256).hexdigest()

        headers = {'Content-Type': 'application/json'}
        url = f"https://api.weixin.qq.com{uri}"
        resp = requests.post(url, data=body, headers=headers, timeout=10)
        result = resp.json()

        if result.get('errcode') == 0:
            order = result.get('order', {})
            state = order.get('state', 1)
            if state == 2:
                return 'SUCCESS', order.get('transaction_id', '')
            elif state == 1:
                return 'USERPAYING', ''
            else:
                return 'CLOSED', ''
        raise Exception(f"查单失败: {result.get('errmsg', '未知错误')}")

    @transaction.atomic
    def _process_payment_success(self, dingdan, transaction_id, operator_id):
        """与回调中的处理逻辑 100% 一致，保证事务原子性"""
        dingdan = Dingdan.objects.select_for_update().get(pk=dingdan.pk)
        if dingdan.zhuangtai != 9:
            return

        dingdan.zhuangtai = 7 if (dingdan.zhiding_id and dingdan.zhiding_id.strip()) else 1
        dingdan.wechat_transaction_id = transaction_id or ('virtual_' + dingdan.dingdan_id)
        dingdan.clkf = operator_id
        dingdan.save()

        Dingdan.objects.filter(
            user1_id=dingdan.user1_id,
            shangpin_id=dingdan.shangpin_id,
            zhuangtai=9,
        ).exclude(dingdan_id=dingdan.dingdan_id).update(zhuangtai=25)

        laoban_id = dingdan.pingtai_kuozhan.laoban_id if hasattr(dingdan, 'pingtai_kuozhan') else None
        if laoban_id:
            user_main = UserMain.objects.filter(yonghuid=laoban_id).first()
            if user_main and hasattr(user_main, 'boss_profile'):
                boss = user_main.boss_profile
                boss.zonge = (boss.zonge or 0) + (dingdan.jine or 0)
                boss.alldingdan = (boss.alldingdan or 0) + 1
                boss.save()

        if dingdan.shangpin_id:
            Shangpin.objects.filter(id=dingdan.shangpin_id).update(kucun=F('kucun') - 1)

        # 统计（完整移植原有逻辑）
        try:
            if dingdan.shangpin_id:
                pingtai_shouyi = dingdan.pingtai_kuozhan.pingtai_shouyi or Decimal('0.00')
                dianpu_shouyi = dingdan.pingtai_kuozhan.dianpu_shouyi or Decimal('0.00')
                update_shangpin_daily_stat(
                    shangpin_id=dingdan.shangpin_id, caozuo_leixing=1,
                    dingdan_jiage=dingdan.jine, pingtai_shouyi=pingtai_shouyi,
                    dianpu_zongshouyi=dianpu_shouyi,
                )
            dianpu_id = dingdan.pingtai_kuozhan.dianpu_id if hasattr(dingdan, 'pingtai_kuozhan') else None
            if dianpu_id:
                dianpu_shouyi = dingdan.pingtai_kuozhan.dianpu_shouyi or Decimal('0.00')
                update_dianpu_daily_stat(
                    dianpu_id=dianpu_id, caozuo_leixing=1,
                    dingdan_jiage=dingdan.jine, dianpu_shouyi=dianpu_shouyi,
                )
        except Exception as e:
            logger.error(f"复查统计失败: {e}")

        self._update_szjilu(dingdan.jine)
        update_daily_income(dingdan.jine)
        sync_order_to_partners(dingdan.dingdan_id)

    def _update_szjilu(self, jine):
        try:
            jine_decimal = Decimal(str(jine))
            with transaction.atomic():
                szjilu, created = Szjilu.objects.select_for_update().get_or_create(
                    id=1,
                    defaults={
                        'zongsy': Decimal('0.00'), 'zongls': Decimal('0.00'),
                        'zongzc': Decimal('0.00'), 'jrzc': Decimal('0.00'),
                        'jrls': Decimal('0.00'),
                    }
                )
                szjilu.zongsy += jine_decimal
                szjilu.zongls += jine_decimal
                szjilu.jrls += jine_decimal
                szjilu.save()
        except Exception as e:
            logger.error(f"复查收支更新失败: {e}")
















class PaymentVerifyView(APIView):
    """
    订单支付成功复查接口 - 前端支付成功后调用，确认订单状态
    当订单状态为9时，主动查询微信支付状态，若已支付则更新本地状态
    需要token认证
    """
    permission_classes = [permissions.IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        try:
            # ---------- 1. 获取参数 ----------
            dingdanid = request.data.get('dingdanid')
            if not dingdanid:
                return Response({'code': 1, 'msg': '订单ID不能为空'})

            # ---------- 2. 查询订单 ----------
            dingdan = Dingdan.objects.filter(dingdan_id=dingdanid).first()
            if not dingdan:
                return Response({'code': 2, 'msg': '订单不存在'})

            # ---------- 3. 验证订单归属（安全） ----------
            current_user = request.user
            user_identifier = f"Boss{current_user.yonghuid}"
            if dingdan.user1_id != user_identifier:
                logger.warning(f"用户 {current_user.yonghuid} 尝试复查他人订单 {dingdanid}")
                return Response({'code': 403, 'msg': '无权访问'})

            # ---------- 4. 如果订单状态已是1/7，直接返回成功 ----------
            if dingdan.zhuangtai in [1, 7]:
                return Response({
                    'code': 0,
                    'msg': '订单状态正常',
                    'data': {'dingdanid': dingdanid, 'zhuangtai': dingdan.zhuangtai}
                })

            # ---------- 5. 如果状态为9，则主动查询微信支付状态 ----------
            if dingdan.zhuangtai == 9:
                # 使用分布式锁防止并发处理同一订单
                lock_key = f"payment_verify_lock_{dingdanid}"
                if not cache.add(lock_key, "locked", timeout=10):
                    # 已有其他进程在处理，让前端稍后重试
                    return Response({'code': 1, 'msg': '订单正在处理中，请稍后'})

                try:
                    # 调用微信订单查询接口
                    trade_state, transaction_id = self._query_wechat_payment(dingdanid)

                    if trade_state == 'SUCCESS':
                        # 支付成功，执行本地更新
                        self._process_payment_success(dingdan, transaction_id, current_user.yonghuid)
                        # 重新获取订单以获取最新状态
                        dingdan.refresh_from_db()
                        return Response({
                            'code': 0,
                            'msg': '支付成功',
                            'data': {'dingdanid': dingdanid, 'zhuangtai': dingdan.zhuangtai}
                        })
                    elif trade_state in ['NOTPAY', 'USERPAYING']:
                        # 用户尚未支付或支付中
                        return Response({'code': 1, 'msg': '支付中', 'data': {'zhuangtai': 9}})
                    else:
                        # 其他状态：CLOSED, REVOKED, PAYERROR 等，视为支付失败
                        return Response({'code': 2, 'msg': '支付失败'})

                except Exception as e:
                    logger.error(f"查询微信支付异常: {e}", exc_info=True)
                    return Response({'code': 1, 'msg': '查询失败，请稍后重试'})
                finally:
                    cache.delete(lock_key)
            else:
                # ---------- 6. 其他异常状态 ----------
                status_msg = {
                    2: '订单已取消',
                    3: '订单已完成',
                    4: '退款审核中',
                    5: '已退款',
                    6: '退款失败',
                    8: '结算中',
                    0: '订单已作废',
                }.get(dingdan.zhuangtai, '订单状态异常')
                return Response({'code': 3, 'msg': status_msg, 'data': {'zhuangtai': dingdan.zhuangtai}})

        except Exception as e:
            logger.error(f"订单复查接口异常: {e}", exc_info=True)
            return Response({'code': 99, 'msg': f'系统错误: {str(e)}'})

    def _process_payment_success(self, dingdan, transaction_id, operator_id):
        """
        支付成功后的原子操作（与微信回调逻辑完全一致）
        在事务内完成所有状态更新和数据一致性操作
        """
        with transaction.atomic():
            # 重新锁定订单，防止并发更新
            dingdan = Dingdan.objects.select_for_update().get(pk=dingdan.pk)
            if dingdan.zhuangtai != 9:
                # 订单状态已被其他进程更新，直接返回（幂等）
                return

            # 更新订单状态
            dingdan.zhuangtai = 7 if dingdan.zhiding_id and dingdan.zhiding_id.strip() else 1
            dingdan.wechat_transaction_id = transaction_id
            dingdan.clkf = operator_id   # 可选：记录操作人ID
            dingdan.save()

            # 删除同一用户同一商品的其他未支付订单（逻辑删除，状态25）
            Dingdan.objects.filter(
                user1_id=dingdan.user1_id,
                shangpin_id=dingdan.shangpin_id,
                zhuangtai=9
            ).exclude(dingdan_id=dingdan.dingdan_id).update(zhuangtai=25)

            # 更新老板扩展表
            laoban_id = dingdan.pingtai_kuozhan.laoban_id if hasattr(dingdan, 'pingtai_kuozhan') else None
            if laoban_id:
                user_main = UserMain.objects.filter(yonghuid=laoban_id).first()
                if user_main and hasattr(user_main, 'boss_profile'):
                    boss = user_main.boss_profile
                    boss.zonge = (boss.zonge or 0) + (dingdan.jine or 0)
                    boss.alldingdan = (boss.alldingdan or 0) + 1
                    boss.save()

            # 更新商品库存
            if dingdan.shangpin_id:
                Shangpin.objects.filter(id=dingdan.shangpin_id).update(
                    kucun=F('kucun') - 1
                )

            # ========== 新增：商品和店铺每日统计 ==========
            try:
                # 商品每日统计（只要有商品ID就执行）
                if dingdan.shangpin_id:
                    # 从扩展表获取已计算好的收益值（下单时已存储）
                    pingtai_shouyi = Decimal('0.00')
                    dianpu_shouyi = Decimal('0.00')
                    if hasattr(dingdan, 'pingtai_kuozhan'):
                        pingtai_shouyi = dingdan.pingtai_kuozhan.pingtai_shouyi or Decimal('0.00')
                        dianpu_shouyi = dingdan.pingtai_kuozhan.dianpu_shouyi or Decimal('0.00')

                    update_shangpin_daily_stat(
                        shangpin_id=dingdan.shangpin_id,
                        caozuo_leixing=1,  # 1 = 下单
                        dingdan_jiage=dingdan.jine,
                        pingtai_shouyi=pingtai_shouyi,
                        dianpu_zongshouyi=dianpu_shouyi
                    )
                    logger.info(f"商品统计更新完成，商品ID: {dingdan.shangpin_id}")

                # 店铺每日统计（仅当存在店铺ID时执行）
                dianpu_id = None
                if hasattr(dingdan, 'pingtai_kuozhan'):
                    dianpu_id = dingdan.pingtai_kuozhan.dianpu_id
                if dianpu_id:
                    dianpu_shouyi = dingdan.pingtai_kuozhan.dianpu_shouyi or Decimal('0.00')
                    update_dianpu_daily_stat(
                        dianpu_id=dianpu_id,
                        caozuo_leixing=1,  # 1 = 下单
                        dingdan_jiage=dingdan.jine,
                        dianpu_shouyi=dianpu_shouyi
                    )
                    logger.info(f"店铺统计更新完成，店铺ID: {dianpu_id}")
            except Exception as e:
                logger.error(f"商品/店铺统计更新失败: {e}")
                logger.error(traceback.format_exc())
                # 统计失败不影响主流程
            # =============================================




            # 更新收支记录
            self._update_szjilu(dingdan.jine)

            # 更新每日收入统计
            update_daily_income(dingdan.jine)

            # 跨平台同步（复查成功也需要通知）
            sync_order_to_partners(dingdan.dingdan_id)

    def _query_wechat_payment(self, out_trade_no):
        """
        调用微信支付订单查询接口，返回 (trade_state, transaction_id)
        若查询失败，抛出异常
        """
        appid = settings.WEIXIN_APPID
        mch_id = settings.WEIXIN_MCHID
        key = settings.WEIXIN_SHANGHUMIYAO
        nonce_str = self._generate_nonce_str()

        params = {
            'appid': appid,
            'mch_id': mch_id,
            'out_trade_no': out_trade_no,
            'nonce_str': nonce_str,
        }

        # 生成签名
        sorted_keys = sorted(params.keys())
        stringA = '&'.join([f"{k}={params[k]}" for k in sorted_keys])
        stringSignTemp = f"{stringA}&key={key}"
        sign = hashlib.md5(stringSignTemp.encode('utf-8')).hexdigest().upper()
        params['sign'] = sign

        xml_data = self._dict_to_xml(params)
        url = 'https://api.mch.weixin.qq.com/pay/orderquery'
        response = requests.post(url, data=xml_data, timeout=10)
        result = xmltodict.parse(response.content)['xml']

        if result.get('return_code') == 'SUCCESS' and result.get('result_code') == 'SUCCESS':
            return result.get('trade_state'), result.get('transaction_id')
        else:
            err_msg = result.get('return_msg', '未知错误')
            raise Exception(f"微信订单查询失败: {err_msg}")

    def _update_szjilu(self, jine):
        """更新收支记录表（ID=1的记录）"""
        try:
            jine_decimal = Decimal(str(jine))
            with transaction.atomic():
                szjilu, created = Szjilu.objects.select_for_update().get_or_create(
                    id=1,
                    defaults={
                        'zongsy': Decimal('0.00'),
                        'zongls': Decimal('0.00'),
                        'zongzc': Decimal('0.00'),
                        'jrzc': Decimal('0.00'),
                        'jrls': Decimal('0.00')
                    }
                )
                if created:
                    logger.info("创建ID=1的收支记录")
                szjilu.zongsy += jine_decimal
                szjilu.zongls += jine_decimal
                szjilu.jrls += jine_decimal
                szjilu.save()
                logger.info(f"收支记录更新成功，增加金额: {jine}")
        except Exception as e:
            logger.error(f"更新收支记录失败: {e}")
            # 不抛出异常，因为收支记录不是核心流程，但记录错误供排查

    def _generate_nonce_str(self):
        """生成随机字符串，长度32"""
        return ''.join(random.choices(string.ascii_letters + string.digits, k=32))

    def _dict_to_xml(self, data):
        """将字典转换为XML字符串"""
        xml = ['<xml>']
        for k, v in data.items():
            xml.append(f'<{k}>{v}</{k}>')
        xml.append('</xml>')
        return ''.join(xml)


'''class PaymentVerifyView(APIView):
    """
    订单支付成功复查接口 - 前端支付成功后调用，确认订单状态
    当订单状态为9时，主动查询微信支付状态，若已支付则更新本地状态
    需要token认证
    """
    permission_classes = [permissions.IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        try:
            # ---------- 1. 获取参数 ----------
            dingdanid = request.data.get('dingdanid')
            if not dingdanid:
                return Response({'code': 1, 'msg': '订单ID不能为空'})

            # ---------- 2. 查询订单 ----------
            dingdan = Dingdan.objects.filter(dingdan_id=dingdanid).first()
            if not dingdan:
                return Response({'code': 2, 'msg': '订单不存在'})

            # ---------- 3. 验证订单归属（安全） ----------
            current_user = request.user
            user_identifier = f"Boss{current_user.yonghuid}"
            if dingdan.user1_id != user_identifier:
                logger.warning(f"用户 {current_user.yonghuid} 尝试复查他人订单 {dingdanid}")
                return Response({'code': 403, 'msg': '无权访问'})

            # ---------- 4. 如果订单状态已是1/7，直接返回成功 ----------
            if dingdan.zhuangtai in [1, 7]:
                return Response({
                    'code': 0,
                    'msg': '订单状态正常',
                    'data': {'dingdanid': dingdanid, 'zhuangtai': dingdan.zhuangtai}
                })

            # ---------- 5. 如果状态为9，则主动查询微信支付状态 ----------
            if dingdan.zhuangtai == 9:
                # 使用分布式锁防止并发处理同一订单
                lock_key = f"payment_verify_lock_{dingdanid}"
                if not cache.add(lock_key, "locked", timeout=10):
                    # 已有其他进程在处理，让前端稍后重试
                    return Response({'code': 1, 'msg': '订单正在处理中，请稍后'})

                try:
                    # 调用微信订单查询接口
                    trade_state, transaction_id = self._query_wechat_payment(dingdanid)

                    if trade_state == 'SUCCESS':
                        # 支付成功，执行本地更新
                        self._process_payment_success(dingdan, transaction_id, current_user.yonghuid)
                        # 重新获取订单以获取最新状态（因为_process_payment_success可能修改了dingdan）
                        dingdan.refresh_from_db()
                        return Response({
                            'code': 0,
                            'msg': '支付成功',
                            'data': {'dingdanid': dingdanid, 'zhuangtai': dingdan.zhuangtai}
                        })
                    elif trade_state in ['NOTPAY', 'USERPAYING']:
                        # 用户尚未支付或支付中
                        return Response({'code': 1, 'msg': '支付中', 'data': {'zhuangtai': 9}})
                    else:
                        # 其他状态：CLOSED, REVOKED, PAYERROR 等，视为支付失败
                        return Response({'code': 2, 'msg': '支付失败'})

                except Exception as e:
                    logger.error(f"查询微信支付异常: {e}", exc_info=True)
                    return Response({'code': 1, 'msg': '查询失败，请稍后重试'})
                finally:
                    cache.delete(lock_key)
            else:
                # ---------- 6. 其他异常状态 ----------
                status_msg = {
                    2: '订单已取消',
                    3: '订单已完成',
                    4: '退款审核中',
                    5: '已退款',
                    6: '退款失败',
                    8: '结算中',
                    0: '订单已作废',
                }.get(dingdan.zhuangtai, '订单状态异常')
                return Response({'code': 3, 'msg': status_msg, 'data': {'zhuangtai': dingdan.zhuangtai}})

        except Exception as e:
            logger.error(f"订单复查接口异常: {e}", exc_info=True)
            return Response({'code': 99, 'msg': f'系统错误: {str(e)}'})

    def _query_wechat_payment(self, out_trade_no):
        """
        调用微信支付订单查询接口，返回 (trade_state, transaction_id)
        若查询失败，抛出异常
        """
        appid = settings.WEIXIN_APPID
        mch_id = settings.WEIXIN_MCHID
        key = settings.WEIXIN_SHANGHUMIYAO
        nonce_str = self._generate_nonce_str()

        params = {
            'appid': appid,
            'mch_id': mch_id,
            'out_trade_no': out_trade_no,
            'nonce_str': nonce_str,
        }

        # 生成签名
        sorted_keys = sorted(params.keys())
        stringA = '&'.join([f"{k}={params[k]}" for k in sorted_keys])
        stringSignTemp = f"{stringA}&key={key}"
        sign = hashlib.md5(stringSignTemp.encode('utf-8')).hexdigest().upper()
        params['sign'] = sign

        xml_data = self._dict_to_xml(params)
        url = 'https://api.mch.weixin.qq.com/pay/orderquery'
        response = requests.post(url, data=xml_data, timeout=10)
        result = xmltodict.parse(response.content)['xml']

        if result.get('return_code') == 'SUCCESS' and result.get('result_code') == 'SUCCESS':
            return result.get('trade_state'), result.get('transaction_id')
        else:
            err_msg = result.get('return_msg', '未知错误')
            raise Exception(f"微信订单查询失败: {err_msg}")

    def _process_payment_success(self, dingdan, transaction_id, operator_id):
        """
        支付成功后的原子操作（与微信回调逻辑完全一致）
        在事务内完成所有状态更新和数据一致性操作
        """
        with transaction.atomic():
            # 重新锁定订单，防止并发更新
            dingdan = Dingdan.objects.select_for_update().get(pk=dingdan.pk)
            if dingdan.zhuangtai != 9:
                # 订单状态已被其他进程更新，直接返回（幂等）
                return

            # 更新订单状态
            dingdan.zhuangtai = 7 if dingdan.zhiding_id and dingdan.zhiding_id.strip() else 1
            dingdan.wechat_transaction_id = transaction_id
            dingdan.clkf = operator_id   # 可选：记录操作人ID
            dingdan.save()

            # 删除同一用户同一商品的其他未支付订单（避免僵尸订单）
            Dingdan.objects.filter(
                user1_id=dingdan.user1_id,
                shangpin_id=dingdan.shangpin_id,
                zhuangtai=9
            ).exclude(dingdan_id=dingdan.dingdan_id).delete()

            # 更新老板扩展表
            laoban_id = dingdan.pingtai_kuozhan.laoban_id
            user_main = UserMain.objects.filter(yonghuid=laoban_id).first()
            if user_main and hasattr(user_main, 'boss_profile'):
                boss = user_main.boss_profile
                boss.zonge = (boss.zonge or 0) + (dingdan.jine or 0)
                boss.alldingdan = (boss.alldingdan or 0) + 1
                boss.save()

            # 更新商品库存
            Shangpin.objects.filter(id=dingdan.shangpin_id).update(
                kucun=models.F('kucun') - 1
            )

            # 更新收支记录
            self._update_szjilu(dingdan.jine)

    def _update_szjilu(self, jine):
        """更新收支记录表（ID=1的记录）"""
        try:
            jine_decimal = Decimal(str(jine))
            with transaction.atomic():
                szjilu, created = Szjilu.objects.select_for_update().get_or_create(
                    id=1,
                    defaults={
                        'zongsy': Decimal('0.00'),
                        'zongls': Decimal('0.00'),
                        'zongzc': Decimal('0.00'),
                        'jrzc': Decimal('0.00'),
                        'jrls': Decimal('0.00')
                    }
                )
                if created:
                    logger.info("创建ID=1的收支记录")
                szjilu.zongsy += jine_decimal
                szjilu.zongls += jine_decimal
                szjilu.jrls += jine_decimal
                szjilu.save()
                logger.info(f"收支记录更新成功，增加金额: {jine}")
        except Exception as e:
            logger.error(f"更新收支记录失败: {e}")
            # 这里不抛出异常，因为收支记录不是核心流程，但记录错误供排查

    def _generate_nonce_str(self):
        """生成随机字符串，长度32"""
        return ''.join(random.choices(string.ascii_letters + string.digits, k=32))

    def _dict_to_xml(self, data):
        """将字典转换为XML字符串"""
        xml = ['<xml>']
        for k, v in data.items():
            xml.append(f'<{k}>{v}</{k}>')
        xml.append('</xml>')
        return ''.join(xml)'''





from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated


class DingdanHuoquView(APIView):
    """订单获取接口"""
    permission_classes = [IsAuthenticated]

    def post(self, request):
        # 获取当前登录用户
        try:
            current_user = request.user
            yonghuid = current_user.yonghuid
        except Exception as e:
            return Response({
                'code': 1,
                'msg': '用户认证失败',
                'data': None
            })

        # 获取前端参数
        try:
            data = request.data
            zhuangtai_list = data.get('zhuangtai_list', [])
            page = int(data.get('page', 1))
            page_size = int(data.get('page_size', 10))
        except Exception as e:
            return Response({
                'code': 2,
                'msg': '参数格式错误',
                'data': None
            })

        # 参数验证
        if not isinstance(zhuangtai_list, list) or len(zhuangtai_list) == 0:
            return Response({
                'code': 3,
                'msg': '状态列表不能为空',
                'data': None
            })

        if page < 1:
            page = 1
        if page_size <= 0:
            page_size = 10

        try:
            # 查询扩展表，获取用户的所有订单ID
            pingtai_orders = DingdanPingtai.objects.filter(laoban_id=yonghuid)
            pingtai_order_ids = list(pingtai_orders.values_list('dingdan__dingdan_id', flat=True))

            if not pingtai_order_ids:
                return Response({
                    'code': 0,
                    'msg': '成功',
                    'data': {
                        'list': [],
                        'has_more': False,
                        'total': 0
                    }
                })

            # 查询主表
            status_query = Q()
            if zhuangtai_list != [1, 2, 3, 4, 5, 6, 7, 8]:
                status_query = Q(zhuangtai__in=zhuangtai_list)

            query = Q(dingdan_id__in=pingtai_order_ids) & status_query
            orders = Dingdan.objects.filter(query).order_by('-create_time')
            #total_orders = orders.count()

            # 手动分页逻辑
            start_index = (page - 1) * page_size
            end_index = start_index + page_size

            # 获取当前页的数据
            current_page_orders = orders[start_index:end_index]

            # 构建返回数据
            order_list = []
            for order in current_page_orders:
                order_data = {
                    'dingdanId': order.dingdan_id,
                    'zhuangtai': order.zhuangtai,
                    'jine': float(order.jine) if order.jine else 0.0,
                    'tupian': order.tupian or '',
                    'jieshao': order.jieshao or '',
                    'beizhu': order.beizhu or '',
                    'nicheng': order.nicheng or '',
                    'chuangjianshijian': order.create_time.strftime('%Y-%m-%d %H:%M:%S')
                }
                order_list.append(order_data)


            # 判断是否还有更多数据
            current_page_count = len(current_page_orders)
            has_more = current_page_count == page_size

            return Response({
                'code': 0,
                'msg': '成功',
                'data': {
                    'list': order_list,
                    'has_more': has_more,
                    #'total': total_orders
                }
            })

        except Exception as e:
            return Response({
                'code': 4,
                'msg': '服务器内部错误',
                'data': None
            })


# dingdan/views.py

from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from django.db.models import Q
import json

from .models import Dingdan, DingdanPingtai, Dashoutupian


class DingdanXiangqingView(APIView):
    """订单详情接口"""
    permission_classes = [IsAuthenticated]

    def post(self, request):
        # 获取当前登录用户
        try:
            current_user = request.user
            yonghuid = current_user.yonghuid
        except Exception as e:
            return Response({
                'code': 1,
                'msg': '用户认证失败',
                'data': None
            })

        # 获取前端参数
        try:
            data = request.data
            dingdan_id = data.get('dingdanId', '')
        except Exception as e:
            return Response({
                'code': 2,
                'msg': '参数格式错误',
                'data': None
            })

        # 参数验证
        if not dingdan_id:
            return Response({
                'code': 3,
                'msg': '订单ID不能为空',
                'data': None
            })

        try:
            # 1. 验证订单是否属于当前用户
            # 查询平台订单扩展表，检查laoban_id是否等于当前用户
            pingtai_kuozhan = DingdanPingtai.objects.filter(
                laoban_id=yonghuid,
                dingdan__dingdan_id=dingdan_id
            ).first()

            if not pingtai_kuozhan:
                # 如果不是平台订单，检查商家订单
                from .models import DingdanShangjia
                shangjia_kuozhan = DingdanShangjia.objects.filter(
                    shangjia_id=yonghuid,
                    dingdan__dingdan_id=dingdan_id
                ).first()

                if not shangjia_kuozhan:
                    return Response({
                        'code': 4,
                        'msg': '订单不存在或无权限查看',
                        'data': None
                    })

            # 2. 查询订单主表
            dingdan = Dingdan.objects.filter(dingdan_id=dingdan_id).first()

            if not dingdan:
                return Response({
                    'code': 5,
                    'msg': '订单不存在',
                    'data': None
                })

            # 3. 获取订单信息
            zhuangtai = dingdan.zhuangtai or 0
            zhiding_id = dingdan.zhiding_id or ''
            jiedan_dashou_id = dingdan.jiedan_dashou_id or ''
            dashou_liuyan = dingdan.dashou_liuyan or ''

            # 4. 查询打手交付图片
            dashoutupian_records = Dashoutupian.objects.filter(
                dingdan_id=dingdan_id
            ).order_by('create_time')[:9]  # 最多取9条

            dashoujiaofu_list = []
            for record in dashoutupian_records:
                if record.tupian:
                    dashoujiaofu_list.append(record.tupian)

            # 5. 构建返回数据（字段名与前端对应）
            response_data = {
                'zhuangtai': zhuangtai,  # 订单状态
                'zhiding': zhiding_id,  # 指定打手ID
                'dashou': jiedan_dashou_id,  # 服务打手ID
                'dashouliuyan': dashou_liuyan,  # 打手留言
                'dashoujiaofu': dashoujiaofu_list  # 打手交付图片列表
            }

            # 6. 返回成功响应
            return Response({
                'code': 0,
                'msg': '成功',
                'data': response_data
            })

        except Exception as e:

            return Response({
                'code': 6,
                'msg': '服务器内部错误',
                'data': None
            })






class JiedanView(APIView):
    """结单接口"""
    permission_classes = [IsAuthenticated]

    def post(self, request):
        # 获取当前登录用户
        try:
            current_user = request.user
            yonghuid = current_user.yonghuid
        except Exception as e:
            return Response({
                'code': 1,
                'msg': '用户认证失败',
                'data': None
            })

        # 获取前端参数
        try:
            data = request.data
            dingdan_id = data.get('dingdanId', '')
            pingfen = int(data.get('pingfen', 0))  # 评分，默认0
            liuyan = data.get('liuyan', '')  # 留言，默认空
        except Exception as e:
            return Response({
                'code': 2,
                'msg': '参数格式错误',
                'data': None
            })

        # 参数验证
        if not dingdan_id:
            return Response({
                'code': 3,
                'msg': '订单ID不能为空',
                'data': None
            })

        # 验证评分范围
        if pingfen < 0 or pingfen > 5:
            return Response({
                'code': 4,
                'msg': '评分必须在0-5分之间',
                'data': None
            })

        # 使用事务确保数据一致性
        try:
            with transaction.atomic():
                # 1. 验证订单是否存在且属于当前用户
                pingtai_kuozhan = DingdanPingtai.objects.filter(
                    laoban_id=yonghuid,
                    dingdan__dingdan_id=dingdan_id
                ).select_related('dingdan').first()

                if not pingtai_kuozhan:
                    return Response({
                        'code': 5,
                        'msg': '订单不存在或无权限操作',
                        'data': None
                    })

                dingdan = pingtai_kuozhan.dingdan

                # 2. 验证订单状态（必须是结算中 - 状态8）
                if dingdan.zhuangtai != 8:
                    return Response({
                        'code': 6,
                        'msg': '订单不在结算状态，无法结单',
                        'data': None
                    })

                # 3. 获取订单相关数据
                dashou_fencheng = dingdan.dashou_fencheng or Decimal('0.00')  # 打手分成
                jiedan_dashou_id = dingdan.jiedan_dashou_id or ''  # 接单打手ID
                shangpin_id = dingdan.shangpin_id  # 商品ID

                # 4. 更新平台扩展表的老板评价（如果有留言）
                if liuyan:
                    pingtai_kuozhan.laoban_pingjia = liuyan
                    pingtai_kuozhan.save()

                # 5. 如果有评分，更新评分表
                if pingfen > 0 and jiedan_dashou_id:
                    # 使用filter查询，更健壮
                    pingfen_records = Pingfen.objects.filter(dashou=jiedan_dashou_id)

                    if pingfen_records.exists():
                        # 已有记录，更新
                        pingfen_record = pingfen_records.first()
                        pingfen_record.zongfen += Decimal(str(pingfen))
                        pingfen_record.cishu += 1
                        pingfen_record.save()
                    else:
                        # 新记录，创建
                        Pingfen.objects.create(
                            dashou=jiedan_dashou_id,
                            zongfen=Decimal(str(pingfen)),
                            cishu=1
                        )

                # 6. 更新商品真实销量（如果有商品ID）
                if shangpin_id:
                    shangpin_records = Shangpin.objects.filter(id=shangpin_id)

                    if shangpin_records.exists():
                        shangpin = shangpin_records.first()
                        # 检查字段是否存在
                        if hasattr(shangpin, 'zhenshi_xiaoliang'):
                            shangpin.zhenshi_xiaoliang = (shangpin.zhenshi_xiaoliang or 0) + 1
                            shangpin.save()

                # ========== 新增：跨平台我方派单且有对方信息，直接通知对方并跳过本地结算 ==========
                if (dingdan.is_cross == 1
                        and dingdan.partner_order_id
                        and dingdan.partner_club_id):
                    # 更新订单状态为已完成
                    dingdan.zhuangtai = 3
                    dingdan.clkf = current_user.phone if hasattr(current_user, 'phone') else yonghuid
                    dingdan.save()

                    # 事务提交后异步通知对方平台
                    transaction.on_commit(
                        lambda: self._notify_partner_jiedan(
                            my_dingdan_id=dingdan.dingdan_id,
                            partner_club_id=dingdan.partner_club_id,
                            partner_order_id=dingdan.partner_order_id,
                            new_status=3,
                            current_user=current_user
                        )
                    )

                    # 直接返回，跳过后续所有本地打手结算、评价、统计等
                    return Response({
                        'code': 0,
                        'msg': '结单成功（已通知对方平台）',
                        'data': None
                    })
                # ====================================================================

                # 7. 更新打手扩展表（如果有打手ID和分成）
                if jiedan_dashou_id and dashou_fencheng > 0:
                    # 查询打手用户
                    dashou_user = UserMain.objects.filter(yonghuid=jiedan_dashou_id).first()

                    if dashou_user:
                        # 查询打手扩展表
                        dashou_kuozhan = UserDashou.objects.filter(user=dashou_user).first()

                        if dashou_kuozhan:
                            # 更新四个金额字段
                            dashou_kuozhan.zonge = (dashou_kuozhan.zonge or Decimal('0.00')) + dashou_fencheng
                            dashou_kuozhan.yue = (dashou_kuozhan.yue or Decimal('0.00')) + dashou_fencheng
                            dashou_kuozhan.jinrishouyi = (dashou_kuozhan.jinrishouyi or Decimal(
                                '0.00')) + dashou_fencheng
                            dashou_kuozhan.jinyueshouyi = (dashou_kuozhan.jinyueshouyi or Decimal(
                                '0.00')) + dashou_fencheng

                            # 成交总量加1
                            dashou_kuozhan.chengjiaozongliang = (dashou_kuozhan.chengjiaozongliang or 0) + 1

                            # 状态改为数字1
                            dashou_kuozhan.zhuangtai = 1

                            dashou_kuozhan.save()

                # 8. 更新订单状态为已完成（状态3）
                dingdan.zhuangtai = 3
                dingdan.save()

                # 🔥 新增：调用打手每日统计（成交）
                try:
                    update_dashou_daily_by_action(
                        yonghuid=jiedan_dashou_id,
                        amount=dashou_fencheng,
                        action=2  # 2 表示成交（结算）
                    )
                    logger.info(f"打手 {jiedan_dashou_id} 每日统计更新成功")
                except Exception as e:
                    logger.error(f"打手每日统计更新失败: {e}")
                    # 不影响主流程

                # ========== 新增：商品和店铺每日统计 ==========
                try:
                    # 商品每日统计（只要有商品ID就执行）
                    if dingdan.shangpin_id:
                        # 从扩展表获取已计算好的收益值（下单时已存储）
                        pingtai_shouyi = Decimal('0.00')
                        dianpu_shouyi = Decimal('0.00')
                        if hasattr(dingdan, 'pingtai_kuozhan'):
                            pingtai_shouyi = dingdan.pingtai_kuozhan.pingtai_shouyi or Decimal('0.00')
                            dianpu_shouyi = dingdan.pingtai_kuozhan.dianpu_shouyi or Decimal('0.00')

                        update_shangpin_daily_stat(
                            shangpin_id=dingdan.shangpin_id,
                            caozuo_leixing=2,  # 2 = 结单
                            dingdan_jiage=dingdan.jine,
                            pingtai_shouyi=pingtai_shouyi,
                            dianpu_zongshouyi=dianpu_shouyi
                        )
                        logger.info(f"商品统计更新完成，商品ID: {dingdan.shangpin_id}")

                    # 店铺每日统计（仅当存在店铺ID时执行）

                    # ========== 修改为 ==========
                    # 店铺每日统计（包含上级分红）
                    dianpu_id = None
                    shangji_id = None
                    shangji_fen = Decimal('0.00')
                    if hasattr(dingdan, 'pingtai_kuozhan'):
                        dianpu_id = dingdan.pingtai_kuozhan.dianpu_id
                        shangji_id = dingdan.pingtai_kuozhan.shangji_dianpu_id
                        shangji_fen = dingdan.pingtai_kuozhan.shangji_fenhong or Decimal('0.00')
                    if dianpu_id:
                        dianpu_shouyi = dingdan.pingtai_kuozhan.dianpu_shouyi or Decimal('0.00')
                        update_dianpu_daily_stat(
                            dianpu_id=dianpu_id,
                            caozuo_leixing=2,  # 结算
                            dingdan_jiage=dingdan.jine,
                            dianpu_shouyi=dianpu_shouyi,
                            shangji_dianpu_id=shangji_id,  # 新增：上级店铺ID
                            shangji_fenhong=shangji_fen  # 新增：该单给上级的分红
                        )
                        logger.info(
                            f"店铺统计更新完成，店铺ID: {dianpu_id}, 上级ID: {shangji_id}, 上级分红: {shangji_fen}")



                    '''dianpu_id = None
                    if hasattr(dingdan, 'pingtai_kuozhan'):
                        dianpu_id = dingdan.pingtai_kuozhan.dianpu_id
                    if dianpu_id:
                        dianpu_shouyi = dingdan.pingtai_kuozhan.dianpu_shouyi or Decimal('0.00')
                        update_dianpu_daily_stat(
                            dianpu_id=dianpu_id,
                            caozuo_leixing=2,  # 2 = 结单
                            dingdan_jiage=dingdan.jine,
                            dianpu_shouyi=dianpu_shouyi
                        )
                        logger.info(f"店铺统计更新完成，店铺ID: {dianpu_id}")'''
                except Exception as e:
                    logger.error(f"商品/店铺统计更新失败: {e}")
                    logger.error(traceback.format_exc())
                    # 统计失败不影响主流程
                # =============================================




                # 12. 更新平台收益流水（仅在平台发单时）
                if dingdan.fadan_pingtai == 1:
                    try:
                        from dingdan.utils import update_platform_profit  # 导入函数
                        update_platform_profit(dingdan_id)
                    except Exception as e:
                        # 平台收益更新失败不影响主流程，但记录日志
                        logger.error(f"强制结单后更新平台收益失败: {str(e)}")

                # 9. 返回成功响应
                return Response({
                    'code': 0,
                    'msg': '结单成功',
                    'data': None
                })

        except Exception as e:

            # 事务会自动回滚
            return Response({
                'code': 7,
                'msg': '结单失败，服务器内部错误',
                'data': None
            })

    def _notify_partner_jiedan(self, my_dingdan_id, partner_club_id, partner_order_id, new_status, current_user):
        """
        通知对方俱乐部我方订单已完成
        参照 CrossPlatformForceCompleteView._notify_partner_order_status 实现
        """
        try:
            # 1. 获取我方俱乐部ID
            from .models import  CrossPlatformOrderData
            my_club_config = ClubConfig.objects.filter(is_self=1).first()
            if not my_club_config:
                logger.error("未配置我方俱乐部信息，无法通知对方")
                return
            self_club_id = my_club_config.club_id

            # 2. 查询对方服务器域名
            club_rel = Club.objects.get(club_id=self_club_id, partner_club_id=partner_club_id)
            partner_domain = club_rel.partner_domain
            if not partner_domain:
                logger.error(f"对方俱乐部 {partner_club_id} 未配置域名")
                return

            # 3. 构造通知请求
            url = partner_domain.rstrip('/') + '/houtai/dfddtk'
            payload = {
                'order_id': partner_order_id,  # 在对方看来这是他们的订单ID
                'club_id': self_club_id,
                'status': new_status
            }
            resp = requests.post(url, json=payload, timeout=3)
            if resp.status_code == 200:
                resp_json = resp.json()
                if resp_json.get('code') == 0:
                    # 4. 更新跨平台订单扩展表（记录对方状态）
                    CrossPlatformOrderData.objects.update_or_create(
                        dingdan_id=my_dingdan_id,  # 我方订单ID
                        defaults={
                            'partner_order_id': partner_order_id,
                            'partner_club_id': partner_club_id,
                            'partner_order_status': new_status,
                            'partner_dashou_id': '',
                            'partner_amount': Decimal('0')
                        }
                    )
                    logger.info(f"老板结单通知对方成功: {partner_order_id} -> {new_status}")
                else:
                    logger.warning(f"对方接口返回错误: {resp_json.get('msg')}")
            else:
                logger.warning(f"对方接口HTTP错误: {resp.status_code}")
        except requests.exceptions.Timeout:
            logger.error(f"通知对方平台超时: {partner_club_id}")
        except Exception as e:
            logger.error(f"通知对方平台异常: {str(e)}")









from dengji.models import DashouBiaoxian
from dengji.services import record_dashou_biaoxian






# dingdan/views.py


class DingdanXiangqingView2(APIView):
    """订单详情接口（老板端）- 返回完整评价信息"""
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            yonghuid = request.user.yonghuid
        except Exception:
            return Response({'code': 1, 'msg': '用户认证失败', 'data': None})

        dingdan_id = request.data.get('dingdanId', '')
        if not dingdan_id:
            return Response({'code': 2, 'msg': '订单ID不能为空', 'data': None})

        try:
            # 权限验证
            pingtai_ext = DingdanPingtai.objects.filter(
                laoban_id=yonghuid,
                dingdan__dingdan_id=dingdan_id
            ).select_related('dingdan').first()

            if not pingtai_ext:
                return Response({'code': 3, 'msg': '订单不存在或无权限查看', 'data': None})

            order = pingtai_ext.dingdan
            zhuangtai = order.zhuangtai or 0
            jiedan_dashou_id = order.jiedan_dashou_id or ''
            dashou_liuyan = order.dashou_liuyan or ''
            update_time = order.update_time.strftime('%Y-%m-%d %H:%M:%S') if order.update_time else ''

            # 交付图片
            dashoujiaofu_list = list(
                Dashoutupian.objects.filter(dingdan_id=dingdan_id)
                .order_by('create_time')[:9]
                .values_list('tupian', flat=True)
            )

            # 打手信息
            dashou_nicheng = ''
            dashou_touxiang = ''
            jiedan_time = ''
            tijiao_time = ''
            if jiedan_dashou_id:
                dashou_user = UserMain.objects.filter(yonghuid=jiedan_dashou_id).first()
                if dashou_user:
                    dashou_touxiang = dashou_user.avatar or ''
                    try:
                        dashou_nicheng = dashou_user.dashou_profile.nicheng or ''
                    except UserDashou.DoesNotExist:
                        pass
                biaoxian = DashouBiaoxian.objects.filter(
                    dingdan_id=dingdan_id,
                    dashou_id=jiedan_dashou_id
                ).first()
                if biaoxian:
                    if biaoxian.jiedan_time:
                        jiedan_time = biaoxian.jiedan_time.strftime('%Y-%m-%d %H:%M:%S')
                    if biaoxian.tijiao_time:
                        tijiao_time = biaoxian.tijiao_time.strftime('%Y-%m-%d %H:%M:%S')

            # 老板自己的评价（如果已经结算过，可能已有评价）
            laoban_pingjia = pingtai_ext.laoban_pingjia or ''
            shangxian_sudu = None
            fuwu_taidu = None
            fanche_cishu = None
            if jiedan_dashou_id and zhuangtai in [3, 4, 5, 6]:  # 已完成或退款相关状态才可能有评价
                biaoxian = DashouBiaoxian.objects.filter(
                    dingdan_id=dingdan_id,
                    dashou_id=jiedan_dashou_id
                ).first()
                if biaoxian:
                    shangxian_sudu = biaoxian.shangxian_sudu
                    fuwu_taidu = biaoxian.fuwu_taidu
                    fanche_cishu = biaoxian.fanche_cishu

            data = {
                'zhuangtai': zhuangtai,
                'dashou': jiedan_dashou_id,
                'dashou_nicheng': dashou_nicheng,
                'dashou_touxiang': dashou_touxiang,
                'dashouliuyan': dashou_liuyan,
                'dashoujiaofu': dashoujiaofu_list,
                'update_time': update_time,
                'jiedan_time': jiedan_time,
                'tijiao_time': tijiao_time,
                'laoban_pingjia': laoban_pingjia,
                'shangxian_sudu': shangxian_sudu,      # 1-5 或 null
                'fuwu_taidu': fuwu_taidu,              # 1-5 或 null
                'fanche_cishu': fanche_cishu           # int 或 null
            }

            return Response({'code': 0, 'msg': '成功', 'data': data})

        except Exception as e:
            logger.error(f"订单详情查询异常: {e}", exc_info=True)
            return Response({'code': 4, 'msg': '服务器内部错误', 'data': None})


class JiedanView2(APIView):
    """结单接口（老板端）- 接收全新评价字段并写入表现表"""
    permission_classes = [IsAuthenticated]

    def post(self, request):
        # 1. 用户认证
        try:
            current_user = request.user
            yonghuid = current_user.yonghuid
        except Exception:
            return Response({'code': 1, 'msg': '用户认证失败', 'data': None})

        # 2. 获取参数（字段名与前端完全一致）
        try:
            data = request.data
            dingdan_id = data.get('dingdanId', '')
            fanche_cishu = data.get('fanche_cishu')          # 前端传的字符串或数字，后端转为整数
            shangxian_sudu = data.get('shangxian_sudu')
            fuwu_taidu = data.get('fuwu_taidu')
            liuyan = data.get('liuyan', '')
        except Exception:
            return Response({'code': 2, 'msg': '参数格式错误', 'data': None})

        # 参数校验
        if not dingdan_id:
            return Response({'code': 3, 'msg': '订单ID不能为空', 'data': None})

        # 转换并校验必填评价字段
        try:
            fanche_cishu = int(fanche_cishu) if fanche_cishu is not None else None
            shangxian_sudu = int(shangxian_sudu) if shangxian_sudu is not None else None
            fuwu_taidu = int(fuwu_taidu) if fuwu_taidu is not None else None
        except (ValueError, TypeError):
            return Response({'code': 4, 'msg': '评价参数必须为整数', 'data': None})

        if fanche_cishu is None:
            return Response({'code': 5, 'msg': '翻车次数不能为空', 'data': None})
        if not (1 <= shangxian_sudu <= 5 and 1 <= fuwu_taidu <= 5):
            return Response({'code': 6, 'msg': '评价分数必须在1-5之间', 'data': None})

        # 使用事务保证数据一致性
        try:
            with transaction.atomic():
                # 3. 权限验证：订单属于当前老板
                pingtai_ext = DingdanPingtai.objects.filter(
                    laoban_id=yonghuid,
                    dingdan__dingdan_id=dingdan_id
                ).select_related('dingdan').first()

                if not pingtai_ext:
                    return Response({'code': 7, 'msg': '订单不存在或无权限操作', 'data': None})

                order = pingtai_ext.dingdan

                # 4. 状态校验：必须是结算中（状态8）
                if order.zhuangtai != 8:
                    return Response({'code': 8, 'msg': '订单不在结算状态', 'data': None})

                # 5. 提取订单关键数据
                dashou_fencheng = order.dashou_fencheng or Decimal('0.00')
                jiedan_dashou_id = order.jiedan_dashou_id or ''
                shangpin_id = order.shangpin_id

                # 6. 保存老板评价（兼容旧逻辑）
                if liuyan:
                    pingtai_ext.laoban_pingjia = liuyan
                    pingtai_ext.save()

                # 7. 更新评分表（用服务态度分作为综合评分，保留原有统计）
                if jiedan_dashou_id and fuwu_taidu:
                    pingfen_records = Pingfen.objects.filter(dashou=jiedan_dashou_id)
                    if pingfen_records.exists():
                        pf = pingfen_records.first()
                        pf.zongfen += Decimal(str(fuwu_taidu))
                        pf.cishu += 1
                        pf.save()
                    else:
                        Pingfen.objects.create(
                            dashou=jiedan_dashou_id,
                            zongfen=Decimal(str(fuwu_taidu)),
                            cishu=1
                        )

                # 8. 更新商品真实销量
                if shangpin_id:
                    shangpin_qs = Shangpin.objects.filter(id=shangpin_id)
                    if shangpin_qs.exists():
                        sp = shangpin_qs.first()
                        if hasattr(sp, 'zhenshi_xiaoliang'):
                            sp.zhenshi_xiaoliang = (sp.zhenshi_xiaoliang or 0) + 1
                            sp.save()

                # 9. 更新打手收益与状态
                if jiedan_dashou_id and dashou_fencheng > 0:
                    dashou_user = UserMain.objects.filter(yonghuid=jiedan_dashou_id).first()
                    if dashou_user:
                        try:
                            dashou_ext = dashou_user.dashou_profile
                            dashou_ext.zonge = (dashou_ext.zonge or Decimal('0.00')) + dashou_fencheng
                            dashou_ext.yue = (dashou_ext.yue or Decimal('0.00')) + dashou_fencheng
                            dashou_ext.jinrishouyi = (dashou_ext.jinrishouyi or Decimal('0.00')) + dashou_fencheng
                            dashou_ext.jinyueshouyi = (dashou_ext.jinyueshouyi or Decimal('0.00')) + dashou_fencheng
                            dashou_ext.chengjiaozongliang = (dashou_ext.chengjiaozongliang or 0) + 1
                            dashou_ext.zhuangtai = 1
                            dashou_ext.save()
                        except UserDashou.DoesNotExist:
                            pass

                # 10. 更新订单状态为已完成
                order.zhuangtai = 3
                order.save()

                # 11. 打手每日统计（成交）
                try:
                    update_dashou_daily_by_action(
                        yonghuid=jiedan_dashou_id,
                        amount=dashou_fencheng,
                        action=2   # 2=结算/成交
                    )
                except Exception as e:
                    logger.error(f"打手每日统计失败: {e}")

                # 12. 商品/店铺每日统计
                try:
                    if shangpin_id:
                        # 从扩展表取已计算收益
                        pingtai_shouyi = Decimal('0.00')
                        dianpu_shouyi = Decimal('0.00')
                        if hasattr(order, 'pingtai_kuozhan'):
                            pingtai_shouyi = order.pingtai_kuozhan.pingtai_shouyi or Decimal('0.00')
                            dianpu_shouyi = order.pingtai_kuozhan.dianpu_shouyi or Decimal('0.00')

                        update_shangpin_daily_stat(
                            shangpin_id=shangpin_id,
                            caozuo_leixing=2,
                            dingdan_jiage=order.jine,
                            pingtai_shouyi=pingtai_shouyi,
                            dianpu_zongshouyi=dianpu_shouyi
                        )

                        # 店铺统计（含上级分红）
                        if hasattr(order, 'pingtai_kuozhan'):
                            dianpu_id = order.pingtai_kuozhan.dianpu_id
                            shangji_id = order.pingtai_kuozhan.shangji_dianpu_id
                            shangji_fen = order.pingtai_kuozhan.shangji_fenhong or Decimal('0.00')
                            if dianpu_id:
                                update_dianpu_daily_stat(
                                    dianpu_id=dianpu_id,
                                    caozuo_leixing=2,
                                    dingdan_jiage=order.jine,
                                    dianpu_shouyi=dianpu_shouyi,
                                    shangji_dianpu_id=shangji_id,
                                    shangji_fenhong=shangji_fen
                                )
                except Exception as e:
                    logger.error(f"商品/店铺统计失败: {e}")

                # 13. 平台收益流水（仅平台发单）
                if order.fadan_pingtai == 1:
                    try:
                        from dingdan.utils import update_platform_profit  # 导入函数
                        update_platform_profit(dingdan_id)
                    except Exception as e:
                        logger.error(f"平台收益更新失败: {e}")

                # 14. 🆕 写入打手表现表（结算评价）
                if jiedan_dashou_id:
                    record_dashou_biaoxian(
                        dingdan_id=dingdan_id,
                        dashou_id=jiedan_dashou_id,
                        xingwei=3,                     # 3=结算
                        fanche_cishu=fanche_cishu,
                        shangxian_sudu=shangxian_sudu,
                        fuwu_taidu=fuwu_taidu
                        # bankuai 暂不传入，后续可从订单商品关联
                    )

                # 15. 返回成功
                return Response({'code': 0, 'msg': '结单成功', 'data': None})

        except Exception as e:
            logger.error(f"结单事务异常: {e}", exc_info=True)
            return Response({'code': 9, 'msg': '服务器内部错误，结单失败', 'data': None})














from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from django.db.models import Prefetch
from dengji.models import  Chenghao

class ShangpinLeixingView(APIView):
    """
    获取商家可用的商品类型列表（含关联板块的称号）
    POST /dingdan/sjspleixing
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # 1. 查询审核通过且抢单要求类型为1的商品类型，按排序权重升序
            shangpin_queryset = ShangpinLeixing.objects.filter(
                yaoqiuleixing=1,
                shenhezhuangtai=1
            ).select_related('bankuai').order_by('paixu')

            # 2. 收集所有涉及到的板块ID
            bankuai_ids = shangpin_queryset.values_list('bankuai_id', flat=True).distinct()

            # 3. 查询这些板块下的所有称号（每个称号绑定到一个板块）
            chenghao_list = Chenghao.objects.filter(
                bankuai_id__in=bankuai_ids
            ).values('id', 'mingcheng', 'texiao_miaoshu', 'bankuai_id')

            # 4. 构建 板块ID -> 称号列表 的映射（确保准确关联）
            bankuai_chenghao_map = {}
            for ch in chenghao_list:
                bid = ch['bankuai_id']
                if bid not in bankuai_chenghao_map:
                    bankuai_chenghao_map[bid] = []
                bankuai_chenghao_map[bid].append({
                    'id': ch['id'],
                    'mingcheng': ch['mingcheng'],
                    'texiao_json': ch['texiao_miaoshu']   # 前端 chenghao-tag 组件需要
                })

            # 5. 组装最终数据
            data_list = []
            for sp in shangpin_queryset:
                item = {
                    'id': sp.id,
                    'yaoqiuleixing': sp.yaoqiuleixing,
                    'huiyuan_id': sp.huiyuan_id,
                    'jieshao': sp.jieshao,
                    # 当前类型所属板块的称号列表（无板块则为空数组）
                    'chenghaoList': bankuai_chenghao_map.get(sp.bankuai_id, [])
                }
                data_list.append(item)

            return Response({
                'code': 200,
                'msg': '获取成功',
                'data': data_list
            })

        except Exception as e:
            logger.error(f"获取商品类型失败: {str(e)}", exc_info=True)
            return Response({'code': 500, 'msg': '服务器内部错误', 'data': {}}, status=500)


# views/order_views.py - ShangjiaPaifaView完整代码
import os
import logging
from shangpin.models import ShangpinLeixing
import threading
from utils.weixin_broadcast import WeixinBroadcastSender


logger = logging.getLogger(__name__)






'''class ShangjiaPaifaView(APIView):
    """商家派单接口"""
    permission_classes = [IsAuthenticated]

    def post(self, request):
        # 记录请求日志
        logger.info(f"商家派单请求: user_id={request.user.yonghuid}, data={request.data}")

        # 1. 获取前端参数
        data = request.data
        shangpin_type_id = data.get('shangpinTypeId')
        huiyuan_id = data.get('huiyuanId')
        yaoqiuleixing = data.get('yaoqiuleixing')
        dingdan_jieshao = data.get('dingdanJieshao', '').strip()
        dingdan_beizhu = data.get('dingdanBeizhu', '').strip()
        laoban_name = data.get('laobanName', '').strip()
        zhiding_uid = data.get('zhidingUid', '').strip()
        jiage_str = data.get('jiage')

        # 2. 基本参数验证
        if not all([shangpin_type_id, huiyuan_id, dingdan_jieshao, laoban_name, jiage_str]):
            logger.warning(f"参数缺失: {request.data}")
            return Response({'code': 400, 'msg': '缺少必填参数', 'data': None}, status=status.HTTP_400_BAD_REQUEST)

        try:
            jiage = float(jiage_str)
            if jiage < 1 or jiage > 10000:
                return Response({'code': 400, 'msg': '价格需在1-10000元之间', 'data': None},
                                status=status.HTTP_400_BAD_REQUEST)
            if '.' in jiage_str and len(jiage_str.split('.')[1]) > 2:
                return Response({'code': 400, 'msg': '最多支持两位小数', 'data': None},
                                status=status.HTTP_400_BAD_REQUEST)
        except ValueError:
            return Response({'code': 400, 'msg': '价格格式错误', 'data': None}, status=status.HTTP_400_BAD_REQUEST)

        # 3. 获取商家扩展信息
        try:
            shangjia = request.user.shop_profile
        except UserShangjia.DoesNotExist:
            logger.warning(f"用户不是商家: user_id={request.user.yonghuid}")
            return Response({'code': 403, 'msg': '您不是商家或商家信息未完善', 'data': None},
                            status=status.HTTP_403_FORBIDDEN)

        # 4. 验证商家状态
        if shangjia.zhuangtai != 1:
            logger.warning(f"商家状态异常: user_id={request.user.yonghuid}, status={shangjia.zhuangtai}")
            return Response({'code': 403, 'msg': '商家账号状态异常，请联系管理员', 'data': None},
                            status=status.HTTP_403_FORBIDDEN)

        # 5. 验证商家余额
        if jiage > shangjia.yue:
            logger.warning(f"余额不足: user_id={request.user.yonghuid}, 余额={shangjia.yue}, 需要={jiage}")
            return Response({'code': 400, 'msg': f'余额不足，当前余额{shangjia.yue}元', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST)

        # 6. 验证指定打手
        zhiding_dashou = None
        dashou_user_main = None
        if zhiding_uid:
            try:
                zhiding_user = UserMain.objects.get(yonghuid=zhiding_uid)
                dashou_user_main = zhiding_user

                try:
                    zhiding_dashou = zhiding_user.dashou_profile
                except UserDashou.DoesNotExist:
                    logger.warning(f"指定用户不是打手: zhiding_uid={zhiding_uid}")
                    return Response({'code': 400, 'msg': '指定用户不是打手', 'data': None},
                                    status=status.HTTP_400_BAD_REQUEST)

                if zhiding_dashou.zhanghaozhuangtai != 1:
                    logger.warning(
                        f"指定打手状态异常: zhiding_uid={zhiding_uid}, status={zhiding_dashou.zhanghaozhuangtai}")
                    return Response({'code': 400, 'msg': '指定打手账号状态异常', 'data': None},
                                    status=status.HTTP_400_BAD_REQUEST)

            except UserMain.DoesNotExist:
                logger.warning(f"指定用户不存在: zhiding_uid={zhiding_uid}")
                return Response({'code': 400, 'msg': '指定用户不存在', 'data': None},
                                status=status.HTTP_400_BAD_REQUEST)

        # 7. 查询利率
        try:
            lilu_obj = Lilubiao.objects.get(fadanpingtai='3')
            lilu = float(lilu_obj.lilu)
            if lilu <= 0:
                lilu = 1
        except Lilubiao.DoesNotExist:
            logger.warning("利率表不存在，使用默认值1")
            lilu = 1

        dashou_fencheng = round(jiage * lilu, 2)

        # 8. 生成订单ID
        def generate_dingdan_id():
            import time
            import random
            timestamp = int(time.time() * 1000)
            process_id = os.getpid() % 1000
            random_num = random.randint(1000, 9999)
            return f"SJ{timestamp}{process_id:03d}{random_num}"

        # 9. 使用事务
        try:
            with transaction.atomic():
                # 创建订单主表
                dingdan = Dingdan.objects.create(
                    dingdan_id=generate_dingdan_id(),
                    zhuangtai=7 if zhiding_dashou else 1,
                    fadan_pingtai=2,
                    jine=jiage,
                    dashou_fencheng=dashou_fencheng,
                    zhiding_id=zhiding_uid if zhiding_dashou else '',
                    shangpin_id=0,
                    leixing_id=int(shangpin_type_id),
                    yaoqiuleixing=int(yaoqiuleixing) if yaoqiuleixing else 1,
                    huiyuan_id=str(huiyuan_id),
                    jieshao=dingdan_jieshao[:2000],
                    beizhu=dingdan_beizhu[:1000],
                    nicheng=laoban_name[:50],
                    tupian=request.user.avatar,
                    user1_id=f"Sj{request.user.yonghuid}"
                )

                # 创建商家订单扩展表
                DingdanShangjia.objects.create(
                    dingdan=dingdan,
                    shangjia_id=request.user.yonghuid,
                    sjnicheng=request.user.boss_profile.nickname,
                )

                # 更新商家统计信息
                from django.db.models import F
                UserShangjia.objects.filter(id=shangjia.id).update(
                    fabu=F('fabu') + 1,
                    yue=F('yue') - jiage,
                    jinridingdan=F('jinridingdan') + 1,
                    jinriliushui=F('jinriliushui') + jiage,
                    jinyuedingdan=F('jinyuedingdan') + 1,
                    jinyueliushui=F('jinyueliushui') + jiage,
                )

                # 🟢【10. 修改】发送模板消息 - 现在改为广播给所有用户
                from houtai.utils import update_shangjia_daily

                # ✅ 新方法（行为驱动，更安全）
                update_shangjia_daily(
                    yonghuid=request.user.yonghuid,
                    amount=Decimal(str(jiage)),
                    action=1  # 1 = 派发
                )


                self.broadcast_order_notification_async(dingdan)

                # ========== 🆕 新增：判断是否需要跨平台同步 ==========

                sync_order_to_partners(dingdan.dingdan_id)


                # 记录成功日志
                logger.info(f"商家派单成功: order_id={dingdan.dingdan_id}, amount={jiage}, zhiding={zhiding_uid}")

                return Response({'code': 200, 'msg': '派单成功', 'data': {'jine': str(dingdan.jine)}},
                                status=status.HTTP_200_OK)

        except Exception as e:
            logger.error(f"商家派单异常: {str(e)}", exc_info=True)
            return Response({'code': 500, 'msg': '系统错误，派单失败', 'data': None},
                            status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def broadcast_order_notification_async(self, dingdan):
        """异步广播订单通知给所有关注用户"""
        try:
            def broadcast_task():
                try:
                    # 构建订单信息
                    order_info = {
                        'dingdan_id': dingdan.dingdan_id,
                        'game_type': self.get_game_type_name(dingdan.leixing_id),
                        'amount': str(dingdan.jine),
                        'order_desc': dingdan.jieshao[:50] if dingdan.jieshao else '新订单'
                    }

                    # 调用广播器
                    sender = WeixinBroadcastSender()
                    result = sender.broadcast_order(order_info)

                    if result['success']:
                        logger.info(f"【商家派单】订单广播完成: {result['msg']}")
                    else:
                        logger.warning(f"【商家派单】订单广播异常: {result['msg']}")

                except Exception as e:
                    logger.error(f"【商家派单】广播任务异常: {str(e)}")

            # 启动异步线程
            thread = threading.Thread(target=broadcast_task)
            thread.daemon = True
            thread.start()

        except Exception as e:
            logger.error(f"启动广播线程异常: {str(e)}")

    # 🗑️【重要】原 send_template_notification_async 方法不再需要
    # 可以注释掉或删除，因为现在统一用 broadcast_order_notification_async

    def get_game_type_name(self, leixing_id):
        """获取游戏类型名称（保持不变）"""
        try:
            game_type = ShangpinLeixing.objects.filter(id=leixing_id).first()
            return game_type.jieshao if game_type else '游戏订单'
        except Exception:
            return '游戏订单'''''


# ==================== 导入部分（确保已有） ====================

from dengji.models import  DingdanBiaoqian,Chenghao


import os
import threading
import logging
from decimal import Decimal
from django.db import transaction
from django.db.models import F
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from rest_framework import status

from yonghu.models import UserMain, UserShangjia, UserDashou

from houtai.utils import update_shangjia_daily

# 导入 Celery 广播任务
from dingdan.tongzhi_tasks import dingdan_guangbo

logger = logging.getLogger(__name__)


class ShangjiaPaifaView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request):
        logger.info(f"商家派单请求: user_id={request.user.yonghuid}, data={request.data}")

        try:
            data = request.data

            # ----- 1. 获取原始参数（保持原类型）-----
            shangpin_type_id = data.get('shangpinTypeId')
            huiyuan_id = data.get('huiyuanId')
            yaoqiuleixing = data.get('yaoqiuleixing')
            dingdan_jieshao_raw = data.get('dingdanJieshao', '')
            dingdan_beizhu_raw = data.get('dingdanBeizhu', '')
            laoban_name_raw = data.get('laobanName', '')
            zhiding_uid_raw = data.get('zhidingUid', '')
            jiage_str = data.get('jiage')

            label_id = data.get('labelId')            # 整数或 None
            commission_enabled = data.get('commissionEnabled', False)
            commission_value_raw = data.get('commissionValue')

            # ----- 2. 字符串字段安全处理 -----
            dingdan_jieshao = str(dingdan_jieshao_raw).strip()
            dingdan_beizhu = str(dingdan_beizhu_raw).strip()
            laoban_name = str(laoban_name_raw).strip()
            zhiding_uid = str(zhiding_uid_raw).strip()
            commission_value_str = str(commission_value_raw).strip() if commission_value_raw is not None else ''

            # ----- 3. 必填校验 -----
            if not all([shangpin_type_id, huiyuan_id, dingdan_jieshao, laoban_name, jiage_str]):
                logger.warning(f"参数缺失: {request.data}")
                return Response({'code': 400, 'msg': '缺少必填参数'})

            # ----- 4. 价格验证 -----
            try:
                jiage = float(jiage_str)
                if jiage < 1 or jiage > 10000:
                    return Response({'code': 400, 'msg': '价格需在1-10000元之间'})
                if '.' in str(jiage_str) and len(str(jiage_str).split('.')[1]) > 2:
                    return Response({'code': 400, 'msg': '最多支持两位小数'})
            except ValueError:
                return Response({'code': 400, 'msg': '价格格式错误'})

            # ----- 5. 商品类型 -----
            try:
                shangpin_type = ShangpinLeixing.objects.get(id=shangpin_type_id)
            except ShangpinLeixing.DoesNotExist:
                logger.error(f"商品类型不存在: {shangpin_type_id}")
                return Response({'code': 400, 'msg': '商品类型不存在'})

            # ----- 6. 押金 / 会员模式决定 -----
            final_yongjin = 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 = ''
                        logger.info(f"押金模式: 佣金={cv}")
                    else:
                        final_yaoqiu_type = shangpin_type.yaoqiuleixing or 1
                        final_huiyuan_id = str(huiyuan_id) if huiyuan_id else ''
                        logger.warning("佣金为0，降级为会员模式")
                except ValueError:
                    final_yaoqiu_type = shangpin_type.yaoqiuleixing or 1
                    final_huiyuan_id = str(huiyuan_id) if huiyuan_id else ''
                    logger.warning("佣金格式错误，降级为会员模式")
            else:
                final_yaoqiu_type = shangpin_type.yaoqiuleixing or 1
                final_huiyuan_id = str(huiyuan_id) if huiyuan_id else ''
                logger.info(f"会员模式: 类型={final_yaoqiu_type}")

            # ----- 7. 称号（可选：不传/空值/无效/不存在均视为无标签）-----
            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.objects.filter(id=lid).first()
                        if chenghao_obj:
                            logger.info(f"订单将关联称号: {chenghao_obj.mingcheng}")
                        else:
                            logger.info(f"标签不存在，按无标签派单: {label_id}")
                except (ValueError, TypeError):
                    logger.info(f"标签ID无效，按无标签派单: {label_id}")

            # ----- 8. 商家信息 -----
            try:
                shangjia = request.user.shop_profile
            except UserShangjia.DoesNotExist:
                logger.warning(f"用户不是商家: {request.user.yonghuid}")
                return Response({'code': 403, 'msg': '您不是商家'})

            if shangjia.zhuangtai != 1:
                logger.warning(f"商家状态异常: {shangjia.zhuangtai}")
                return Response({'code': 403, 'msg': '商家状态异常'})

            if jiage > shangjia.yue:
                logger.warning(f"余额不足: {shangjia.yue} < {jiage}")
                return Response({'code': 400, 'msg': f'余额不足，当前余额{shangjia.yue}元'})

            # ----- 9. 指定打手 -----
            zhiding_dashou = None
            if zhiding_uid:
                try:
                    zhiding_user = UserMain.objects.get(yonghuid=zhiding_uid)
                    zhiding_dashou = zhiding_user.dashou_profile
                    if zhiding_dashou.zhanghaozhuangtai != 1:
                        return Response({'code': 400, 'msg': '指定打手状态异常'})
                except UserMain.DoesNotExist:
                    return Response({'code': 400, 'msg': '指定用户不存在'})
                except UserDashou.DoesNotExist:
                    return Response({'code': 400, 'msg': '指定用户不是打手'})

            # ----- 10. 利率（打手+管事分成，打手优先） -----
            from dingdan.utils import calc_shangjia_order_fencheng
            dashou_fencheng, guanshi_fencheng = calc_shangjia_order_fencheng(jiage)

            # ----- 11. 生成订单ID -----
            def generate_dingdan_id():
                import time, random
                ts = int(time.time() * 1000)
                pid = os.getpid() % 1000
                rnd = random.randint(1000, 9999)
                return f"SJ{ts}{pid:03d}{rnd}"

            # ----- 12. 事务：创建订单、更新商家统计 -----
            dingdan = None
            try:
                with transaction.atomic():
                    dingdan = Dingdan.objects.create(
                        dingdan_id=generate_dingdan_id(),
                        zhuangtai=7 if zhiding_dashou else 1,
                        fadan_pingtai=2,
                        jine=jiage,
                        dashou_fencheng=dashou_fencheng,
                        guanshi_fencheng=guanshi_fencheng,
                        zhiding_id=zhiding_uid if zhiding_dashou else '',
                        shangpin_id=0,
                        leixing_id=int(shangpin_type_id),
                        yaoqiuleixing=final_yaoqiu_type,
                        yongjin=final_yongjin,
                        huiyuan_id=final_huiyuan_id,
                        jieshao=dingdan_jieshao[:2000],
                        beizhu=dingdan_beizhu[:1000],
                        nicheng=laoban_name[:50],
                        tupian=request.user.avatar,
                        user1_id=f"Sj{request.user.yonghuid}"
                    )
                    logger.info(f"订单主表创建: {dingdan.dingdan_id}")

                    DingdanShangjia.objects.create(
                        dingdan=dingdan,
                        shangjia_id=request.user.yonghuid,
                        sjnicheng=shangjia.nicheng,
                    )

                    if chenghao_obj:
                        DingdanBiaoqian.objects.create(dingdan=dingdan, chenghao=chenghao_obj)
                        logger.info(f"订单关联称号: {chenghao_obj.mingcheng}")

                    # 更新商家统计
                    UserShangjia.objects.filter(id=shangjia.id).update(
                        fabu=F('fabu') + 1,
                        yue=F('yue') - jiage,
                        jinridingdan=F('jinridingdan') + 1,
                        jinriliushui=F('jinriliushui') + jiage,
                        jinyuedingdan=F('jinyuedingdan') + 1,
                        jinyueliushui=F('jinyueliushui') + jiage,
                    )

                    update_shangjia_daily(
                        yonghuid=request.user.yonghuid,
                        amount=Decimal(str(jiage)),
                        action=1
                    )
                # 事务提交，订单已持久化
            except Exception as e:
                logger.error(f"订单创建事务失败: {str(e)}", exc_info=True)
                return Response({'code': 500, 'msg': '订单创建失败，请稍后重试'})

            # ========== 以下操作均在事务外，避免异步任务查不到订单 ==========
            # 跨平台同步（内部可能是异步任务，但函数本身是同步调用，现在订单已存在）
            try:
                sync_order_to_partners(dingdan.dingdan_id)
            except Exception as e:
                logger.error(f"跨平台同步失败: {e}", exc_info=True)

            # Celery 广播任务（异步）
            try:
                order_info = {
                    'dingdan_id': dingdan.dingdan_id,
                    'game_type': self._get_game_type_name(dingdan.leixing_id),
                    'amount': str(dingdan.jine),
                    'order_desc': (dingdan.jieshao or '')[:50],
                }
                dingdan_guangbo.delay(order_info)
                logger.info(f"已提交广播任务: {dingdan.dingdan_id}")
            except Exception as e:
                logger.error(f"广播任务提交失败: {e}", exc_info=True)

            logger.info(f"商家派单成功: {dingdan.dingdan_id}, 金额={jiage}")
            return Response({'code': 200, 'msg': '派单成功', 'data': {'jine': str(dingdan.jine)}})

        except Exception as e:
            logger.error(f"商家派单接口未捕获异常: {str(e)}", exc_info=True)
            return Response({'code': 500, 'msg': '系统内部错误'})

    def _get_game_type_name(self, leixing_id):
        try:
            gt = ShangpinLeixing.objects.filter(id=leixing_id).first()
            return gt.jieshao if gt else '游戏订单'
        except Exception:
            return '游戏订单'
# apps/dingdan/views.py
from django.db.models import Q, Count
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from .models import Dingdan, DingdanShangjia
import logging

logger = logging.getLogger(__name__)


'''class ShangjiaDingdanHuoquView(APIView):
    """
    商家订单获取接口
    POST /dingdan/shangjia/dingdan
    需要JWT认证
    支持分页、状态筛选、精确搜索（订单ID或游戏昵称）
    返回待处理订单数量（pending_count）
    """

    permission_classes = [IsAuthenticated]

    def post(self, request):
        # 1. 获取当前登录用户的yonghuid
        try:
            current_user = request.user
            yonghuid = current_user.yonghuid
        except AttributeError:
            return Response({
                'code': 1,
                'msg': '用户认证失败',
                'data': None
            }, status=status.HTTP_401_UNAUTHORIZED)

        # 2. 解析参数
        try:
            data = request.data
            zhuangtai_list = data.get('zhuangtai_list', [])
            page = max(1, int(data.get('page', 1)))
            page_size = min(100, max(1, int(data.get('page_size', 10))))

            # 搜索参数（精确匹配）
            search_type = data.get('search_type')  # 可能的值：'order_id' 或 'nicheng'
            search_value = data.get('search_value', '').strip()
        except (ValueError, TypeError):
            return Response({
                'code': 2,
                'msg': '参数格式错误',
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)

        # 3. 验证状态列表
        if not isinstance(zhuangtai_list, list) or len(zhuangtai_list) == 0:
            return Response({
                'code': 3,
                'msg': '状态列表不能为空',
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)

        try:
            # 4. 构建基础查询（该商家的所有订单）
            base_qs = DingdanShangjia.objects.filter(
                shangjia_id=yonghuid
            ).select_related('dingdan')

            # 5. 状态过滤（始终使用传入的zhuangtai_list）
            if zhuangtai_list:
                base_qs = base_qs.filter(dingdan__zhuangtai__in=zhuangtai_list)

            # 6. 搜索过滤（精确匹配）
            if search_type and search_value:
                if search_type == 'order_id':
                    # 订单ID精确匹配（dingdan_id有唯一索引）
                    base_qs = base_qs.filter(dingdan__dingdan_id=search_value)
                elif search_type == 'nicheng':
                    # 游戏昵称精确匹配（建议为nicheng字段添加索引）
                    base_qs = base_qs.filter(dingdan__nicheng=search_value)
                # 其他类型忽略

            # 7. 计算待处理订单数量（可抢订单：状态为1或7）
            pending_count = DingdanShangjia.objects.filter(
                shangjia_id=yonghuid,
                dingdan__zhuangtai__in=[1, 7]
            ).count()

            # 8. 排序、分页
            total_count = base_qs.count()
            start_index = (page - 1) * page_size
            end_index = start_index + page_size
            # 注意：这里使用切片会触发数据库LIMIT，性能良好
            current_page_orders = base_qs.order_by('-dingdan__create_time')[start_index:end_index]

            # 9. 构建返回数据
            order_list = []
            for shangjia_order in current_page_orders:
                order = shangjia_order.dingdan
                order_data = {
                    'dingdan_id': order.dingdan_id,
                    'zhuangtai': order.zhuangtai,
                    'jine': float(order.jine) if order.jine else 0.0,
                    'jieshao': order.jieshao or '',
                    'beizhu': order.beizhu or '',
                    'nicheng': order.nicheng or '',
                    'create_time': order.create_time.strftime('%Y-%m-%d %H:%M:%S') if order.create_time else ''
                }
                order_list.append(order_data)

            # 10. 判断是否还有更多
            current_page_count = len(current_page_orders)
            has_more = current_page_count == page_size and end_index < total_count

            return Response({
                'code': 0,
                'msg': '成功',
                'data': {
                    'list': order_list,
                    'has_more': has_more,
                    'total': total_count,
                    'pending_count': pending_count  # 新增待处理数量
                }
            }, status=status.HTTP_200_OK)

        except Exception as e:
            logger.error(f"商家订单获取失败: {str(e)}", exc_info=True)
            return Response({
                'code': 4,
                'msg': '服务器内部错误',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)'''







# views.py 中 ShangjiaDingdanHuoquView 完整改造

class ShangjiaDingdanHuoquView(APIView):
    """
    商家订单获取接口
    POST /dingdan/sjdingdanhq
    需要JWT认证
    支持分页、状态筛选、商品类型筛选、模糊搜索（订单ID/订单介绍/游戏昵称/打手ID）
    返回待结算订单数量（pending_count）
    """

    permission_classes = [IsAuthenticated]

    def post(self, request):
        # 1. 获取当前登录用户的yonghuid
        try:
            current_user = request.user
            yonghuid = current_user.yonghuid
        except AttributeError:
            return Response({
                'code': 1,
                'msg': '用户认证失败',
                'data': None
            }, status=status.HTTP_401_UNAUTHORIZED)

        # 2. 解析参数
        try:
            data = request.data
            zhuangtai_list = data.get('zhuangtai_list', [])
            page = max(1, int(data.get('page', 1)))
            page_size = min(100, max(1, int(data.get('page_size', 10))))

            # 🆕 商品类型筛选
            leixing_id = data.get('leixing_id', None)

            # 🆕 模糊搜索关键字（支持订单ID、订单介绍、游戏昵称、打手ID）
            keyword = data.get('keyword', '').strip()
        except (ValueError, TypeError):
            return Response({
                'code': 2,
                'msg': '参数格式错误',
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)

        # 3. 验证状态列表
        if not isinstance(zhuangtai_list, list) or len(zhuangtai_list) == 0:
            return Response({
                'code': 3,
                'msg': '状态列表不能为空',
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)

        try:
            # 4. 构建基础查询（该商家的所有订单）
            base_qs = DingdanShangjia.objects.filter(
                shangjia_id=yonghuid
            ).select_related('dingdan')

            # 5. 状态过滤
            base_qs = base_qs.filter(dingdan__zhuangtai__in=zhuangtai_list)

            # 🆕 6. 商品类型筛选
            if leixing_id is not None:
                try:
                    leixing_id_int = int(leixing_id)
                    base_qs = base_qs.filter(dingdan__leixing_id=leixing_id_int)
                except (ValueError, TypeError):
                    # 如果leixing_id不是有效整数，忽略该筛选
                    pass

            # 🆕 7. 模糊搜索（支持订单ID、订单介绍、游戏昵称、打手ID）
            if keyword:
                from django.db.models import Q
                # 订单ID精确匹配（dingdan_id有唯一索引，先用精确匹配）
                dingdan_id_match = Q(dingdan__dingdan_id__exact=keyword)
                # 订单介绍模糊匹配
                jieshao_match = Q(dingdan__jieshao__icontains=keyword)
                # 游戏昵称模糊匹配
                nicheng_match = Q(dingdan__nicheng__icontains=keyword)
                # 打手ID精确匹配
                dashou_match = Q(dingdan__jiedan_dashou_id__exact=keyword)

                base_qs = base_qs.filter(
                    dingdan_id_match | jieshao_match | nicheng_match | dashou_match
                )

            # 8. 计算待结算订单数量（状态为8）
            pending_count = DingdanShangjia.objects.filter(
                shangjia_id=yonghuid,
                dingdan__zhuangtai=8
            ).count()

            # 9. 排序、分页
            total_count = base_qs.count()
            start_index = (page - 1) * page_size
            end_index = start_index + page_size
            current_page_orders = base_qs.order_by('-dingdan__create_time')[start_index:end_index]

            # 10. 构建返回数据
            order_list = []
            for shangjia_order in current_page_orders:
                order = shangjia_order.dingdan
                order_data = {
                    'dingdan_id': order.dingdan_id,
                    'zhuangtai': order.zhuangtai,
                    'jine': float(order.jine) if order.jine else 0.0,
                    'jieshao': order.jieshao or '',
                    'beizhu': order.beizhu or '',
                    'nicheng': order.nicheng or '',
                    'leixing_id': order.leixing_id,  # 🆕 返回商品类型ID
                    'tupian': order.tupian or '',    # 🆕 返回商品图片
                    'jiedan_dashou_id': order.jiedan_dashou_id or '',  # 🆕 返回打手ID
                    'create_time': order.create_time.strftime('%Y-%m-%d %H:%M:%S') if order.create_time else ''
                }
                order_list.append(order_data)

            # 11. 判断是否还有更多
            current_page_count = len(current_page_orders)
            has_more = current_page_count == page_size and end_index < total_count

            return Response({
                'code': 0,
                'msg': '成功',
                'data': {
                    'list': order_list,
                    'has_more': has_more,
                    'total': total_count,
                    'pending_count': pending_count
                }
            }, status=status.HTTP_200_OK)

        except Exception as e:
            logger.error(f"商家订单获取失败: {str(e)}", exc_info=True)
            return Response({
                'code': 4,
                'msg': '服务器内部错误',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)




'''class ShangjiaDingdanXiangqingView(APIView):
    """商家订单详情接口 - 高性能实现"""
    permission_classes = [IsAuthenticated]  # JWT认证

    def post(self, request):
        # 1. 获取当前登录用户的yonghuid
        try:
            current_user = request.user
            yonghuid = current_user.yonghuid
        except AttributeError:
            return Response({
                'code': 1,
                'msg': '用户认证失败',
                'data': None
            }, status=status.HTTP_401_UNAUTHORIZED)

        # 2. 获取前端参数
        try:
            data = request.data
            dingdan_id = data.get('dingdan_id', '').strip()
        except Exception:
            return Response({
                'code': 2,
                'msg': '参数格式错误',
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)

        # 3. 参数验证
        if not dingdan_id:
            return Response({
                'code': 3,
                'msg': '订单ID不能为空',
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)

        try:
            # 4. 高性能查询：一次性获取所有关联数据
            # 使用select_related和prefetch_related避免N+1查询

            # 先查询商家订单扩展表，验证订单权限
            shangjia_kuozhan = DingdanShangjia.objects.filter(
                shangjia_id=yonghuid,
                dingdan__dingdan_id=dingdan_id
            ).select_related('dingdan').first()

            if not shangjia_kuozhan:
                return Response({
                    'code': 4,
                    'msg': '订单不存在或您无权限查看',
                    'data': None
                }, status=status.HTTP_403_FORBIDDEN)

            # 5. 查询打手交付图片（使用prefetch_related可以一次性获取所有相关图片）
            # 这里我们单独查询，因为是多对一关系
            dashou_tupian_list = Dashoutupian.objects.filter(
                dingdan_id=dingdan_id
            ).order_by('create_time').values_list('tupian', flat=True)

            # 转换为列表，确保即使为空也返回列表
            dashou_jiaofu = list(dashou_tupian_list)

            # 6. 构建返回数据 - 字段名必须与前端完全匹配
            # 注意：所有字段即使为空也要返回，前端会处理空值
            order = shangjia_kuozhan.dingdan

            response_data = {
                # 基础字段
                'dingdan_id': order.dingdan_id,
                'zhuangtai': order.zhuangtai or 0,

                # 服务相关信息
                'fuwudashou_id': order.jiedan_dashou_id or '',  # 服务打手ID
                'dashou_liuyan': order.dashou_liuyan or '',  # 打手留言
                'dashou_jiaofu': dashou_jiaofu,  # 打手交付图片列表

                # 商家订单扩展表字段
                'shangjia_liuyan': shangjia_kuozhan.shangjia_pingjia or '',  # 商家留言
                'tkliyou': order.tkly or '',  # 退款理由（暂时没有字段）
                'cfliyou': shangjia_kuozhan.cfliyou or '',  # 处罚申请原因
                'sqzhuangtai': shangjia_kuozhan.sqzhuangtai or 0,  # 申请状态
                'bhliyou': shangjia_kuozhan.bhliyou or '',  # 驳回理由
                'chufa_jieguo': '',  # 处罚结果（暂时没有字段）

                # 其他可能需要的基础信息
                'jine': float(order.jine) if order.jine else 0.0,
                'jieshao': order.jieshao or '',
                'beizhu': order.beizhu or '',
                'nicheng': order.nicheng or '',
                'create_time': order.create_time.strftime('%Y-%m-%d %H:%M:%S'),


            }

            return Response({
                'code': 0,
                'msg': '成功',
                'data': response_data
            }, status=status.HTTP_200_OK)

        except Exception as e:
            # 记录异常日志
            import logging
            logger = logging.getLogger(__name__)
            logger.error(f"商家订单详情查询失败: {str(e)}", exc_info=True)

            return Response({
                'code': 5,
                'msg': '服务器内部错误',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)'''




# views.py 中的 ShangjiaDingdanXiangqingView 完整改造



from dingdan.models import Dingdan, DingdanShangjia, Dashoutupian, Fadan

from .models import FadanFenhong  # 注意：fadan_fenhong 可能在其他 app 中，根据实际路径调整

logger = logging.getLogger(__name__)


class ShangjiaDingdanXiangqingView(APIView):
    """
    商家订单详情接口
    返回订单基础信息、打手信息、交付图片、罚款数据、分红利率、更换打手产生的新订单ID等
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        # 1. 获取当前登录用户的 yonghuid
        try:
            current_user = request.user
            yonghuid = current_user.yonghuid
        except AttributeError:
            return Response({
                'code': 1,
                'msg': '用户认证失败',
                'data': None
            }, status=status.HTTP_401_UNAUTHORIZED)

        # 2. 获取前端参数
        try:
            data = request.data
            dingdan_id = data.get('dingdan_id', '').strip()
        except Exception:
            return Response({
                'code': 2,
                'msg': '参数格式错误',
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)

        if not dingdan_id:
            return Response({
                'code': 3,
                'msg': '订单ID不能为空',
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)

        try:
            # 3. 查询商家订单扩展表，验证权限并获取基础订单数据
            shangjia_kuozhan = DingdanShangjia.objects.filter(
                shangjia_id=yonghuid,
                dingdan__dingdan_id=dingdan_id
            ).select_related('dingdan').first()

            if not shangjia_kuozhan:
                return Response({
                    'code': 4,
                    'msg': '订单不存在或您无权限查看',
                    'data': None
                }, status=status.HTTP_403_FORBIDDEN)

            order = shangjia_kuozhan.dingdan

            # 4. 交付图片列表
            dashou_tupian_list = Dashoutupian.objects.filter(
                dingdan_id=dingdan_id
            ).order_by('create_time').values_list('tupian', flat=True)
            dashou_jiaofu = list(dashou_tupian_list)

            # 5. 打手详细信息（头像、昵称、用户ID）
            dashou_yonghuid = order.jiedan_dashou_id or ''
            dashou_nicheng = ''
            dashou_avatar = ''
            if dashou_yonghuid:
                dashou_user = UserMain.objects.filter(
                    yonghuid=dashou_yonghuid
                ).select_related('dashou_profile').first()
                if dashou_user:
                    dashou_avatar = dashou_user.avatar or ''
                    if hasattr(dashou_user, 'dashou_profile') and dashou_user.dashou_profile:
                        dashou_nicheng = dashou_user.dashou_profile.nicheng or ''

            # 6. 罚款数据（如果存在）
            fadan_obj = Fadan.objects.filter(
                guanliandingdan_id=dingdan_id,
                beichufa_id=dashou_yonghuid
            ).first()
            fadan_dict = None
            if fadan_obj:
                fadan_dict = {
                    'id': fadan_obj.id,
                    'chufaliyou': fadan_obj.chufaliyou or '',
                    'fakuanjine': float(fadan_obj.fakuanjine) if fadan_obj.fakuanjine else 0.0,
                    'yingxiang_qiangdan': fadan_obj.yingxiang_qiangdan,
                    'zhuangtai': fadan_obj.zhuangtai,
                    'shensuliyou': fadan_obj.shensuliyou or '',
                    'tongyi_chufaliyou': fadan_obj.tongyi_chufaliyou or '',
                    'bohuiliyou': fadan_obj.bohuiliyou or '',
                    'create_time': fadan_obj.create_time.strftime('%Y-%m-%d %H:%M:%S') if fadan_obj.create_time else '',
                    'update_time': fadan_obj.update_time.strftime('%Y-%m-%d %H:%M:%S') if fadan_obj.update_time else '',
                }

            # 7. 商家自己的分红利率（用于罚款分红计算）
            fenhong_lilv = 0.0
            try:
                # 查找商家作为分红者的最新记录，取应得利率
                last_fenhong = FadanFenhong.objects.filter(
                    fenhongzhe_id=yonghuid,
                    shenfen=1  # 1=商家
                ).order_by('-create_time').first()
                if last_fenhong:
                    fenhong_lilv = float(last_fenhong.yingde_lilv or 0)
            except Exception as e:
                logger.warning(f'获取分红利率失败: {e}')

            # 8. 更换打手后产生的新订单ID（如果当前订单被更换过）
            xin_dingdan_id = ''
            try:
                # 查找以当前订单作为“上一个订单ID”的新订单扩展记录
                new_shangjia_order = DingdanShangjia.objects.filter(
                    shangyige_dingdan_id=dingdan_id,
                    shangjia_id=yonghuid
                ).select_related('dingdan').first()
                if new_shangjia_order:
                    xin_dingdan_id = new_shangjia_order.dingdan.dingdan_id
            except Exception as e:
                logger.warning(f'查找新订单ID失败: {e}')

            # 9. 构建返回数据
            response_data = {
                # 基础订单字段
                'dingdan_id': order.dingdan_id,
                'zhuangtai': order.zhuangtai or 0,
                'jine': float(order.jine) if order.jine else 0.0,
                'jieshao': order.jieshao or '',
                'beizhu': order.beizhu or '',
                'nicheng': order.nicheng or '',
                'create_time': order.create_time.strftime('%Y-%m-%d %H:%M:%S') if order.create_time else '',

                # 打手信息
                'dashou_yonghuid': dashou_yonghuid,
                'dashou_nicheng': dashou_nicheng,
                'dashou_avatar': dashou_avatar,

                # 服务详情
                'fuwudashou_id': dashou_yonghuid,  # 保留旧字段兼容
                'dashou_liuyan': order.dashou_liuyan or '',
                'dashou_jiaofu': dashou_jiaofu,

                # 商家扩展字段（旧）
                'shangjia_liuyan': shangjia_kuozhan.shangjia_pingjia or '',
                'tkliyou': order.tkly or '',
                'cfliyou': shangjia_kuozhan.cfliyou or '',  # 保留，但不影响新罚款
                'sqzhuangtai': shangjia_kuozhan.sqzhuangtai or 0,
                'bhliyou': shangjia_kuozhan.bhliyou or '',
                'chufa_jieguo': '',  # 已弃用

                # 新增：罚款数据
                'fadan': fadan_dict,

                # 新增：分红利率
                'fenhong_lilv': fenhong_lilv,

                # 新增：更换打手后的新订单ID
                'xin_dingdan_id': xin_dingdan_id,
            }

            return Response({
                'code': 0,
                'msg': '成功',
                'data': response_data
            }, status=status.HTTP_200_OK)

        except Exception as e:
            logger.error(f"商家订单详情查询失败: {str(e)}", exc_info=True)
            return Response({
                'code': 5,
                'msg': '服务器内部错误',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)




from dingdan.models import Dingdan, DingdanShangjia, PreSettlement



logger = logging.getLogger(__name__)

from houtai.utils import update_shangjia_daily
class ShangjiaJiesuanView(APIView):
    """商家结单接口（支持跨平台订单）"""
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        # 1. 获取当前登录用户
        try:
            current_user = request.user
            yonghuid = current_user.yonghuid

            try:
                shangjia = current_user.shop_profile
            except UserShangjia.DoesNotExist:
                return Response({
                    'code': 1,
                    'msg': '您不是商家或商家信息未完善',
                    'data': None
                }, status=status.HTTP_403_FORBIDDEN)

        except AttributeError:
            return Response({
                'code': 1,
                'msg': '用户认证失败',
                'data': None
            }, status=status.HTTP_401_UNAUTHORIZED)

        # 2. 获取前端参数
        try:
            data = request.data
            dingdan_id = data.get('dingdan_id', '').strip()
            pingfen = int(data.get('pingfen', 0))
            liuyan = data.get('liuyan', '').strip()
        except (ValueError, TypeError):
            return Response({
                'code': 2,
                'msg': '参数格式错误',
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)

        # 3. 参数验证
        if not dingdan_id:
            return Response({
                'code': 3,
                'msg': '订单ID不能为空',
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)

        if pingfen < 0 or pingfen > 5:
            return Response({
                'code': 4,
                'msg': '评分必须在0-5分之间',
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)

        try:
            with transaction.atomic():
                # 4. 查询订单并加锁（修复并发问题）
                order = Dingdan.objects.select_for_update().get(dingdan_id=dingdan_id)

                # 验证订单是否属于当前商家
                shangjia_kuozhan = DingdanShangjia.objects.filter(
                    dingdan=order,
                    shangjia_id=yonghuid
                ).first()

                if not shangjia_kuozhan:
                    return Response({
                        'code': 5,
                        'msg': '订单不存在或您无权限操作',
                        'data': None
                    }, status=status.HTTP_403_FORBIDDEN)

                # 5. 验证订单状态
                if order.zhuangtai != 8:
                    return Response({
                        'code': 6,
                        'msg': '订单不在结算状态，无法结单',
                        'data': None
                    }, status=status.HTTP_400_BAD_REQUEST)

                # 获取订单字段
                jine = order.jine or Decimal('0')
                dashou_fencheng = order.dashou_fencheng or Decimal('0')
                jiedan_dashou_id = order.jiedan_dashou_id
                dispatch_type = order.dispatch_type          # 1=我方派单，2=对方派单
                is_cross = order.is_cross
                partner_club_id = order.partner_club_id
                partner_order_id = order.partner_order_id

                if not jiedan_dashou_id:
                    return Response({
                        'code': 7,
                        'msg': '订单没有接单打手，无法结单',
                        'data': None
                    }, status=status.HTTP_400_BAD_REQUEST)

                # ========== 跨平台判断 ==========
                is_cross_claimed_by_partner = (is_cross == 1 and (partner_club_id or partner_order_id))

                # ========== 根据订单类型处理 ==========
                # 情况1：对方派单（我方打手接单）-> 预结算，不直接给打手加钱
                if dispatch_type == 2:
                    # 创建预结算记录
                    PreSettlement.objects.update_or_create(
                        dingdan_id=dingdan_id,
                        defaults={
                            'partner_order_id': partner_order_id,
                            'partner_club_id': partner_club_id or '000001',
                            'dashou_id': jiedan_dashou_id,
                            'amount': dashou_fencheng,
                            'order_amount': jine,
                            'status': 0,
                            'operator': request.user.phone,
                        }
                    )
                    # 更新订单状态
                    order.zhuangtai = 3
                    order.save()

                    # 更新统计表
                    update_daily_dispatch_stat(
                        direction=2,
                        partner_club_id=partner_club_id or '000001',
                        success_amount=jine,
                        success_count=1
                    )

                # 情况2：我方派单且被对方打手接单 -> 只改状态，不给本地打手加钱
                elif dispatch_type == 1 and is_cross_claimed_by_partner:
                    order.zhuangtai = 3
                    order.save()

                    update_daily_dispatch_stat(
                        direction=1,
                        partner_club_id=partner_club_id or '000001',
                        success_amount=dashou_fencheng,
                        success_count=1
                    )

                # 情况3：本地订单 或 跨平台但自家打手接单 -> 正常结算给打手
                else:
                    # 查询打手信息
                    try:
                        dashou_user = UserMain.objects.get(yonghuid=jiedan_dashou_id)
                        dashou = dashou_user.dashou_profile
                    except (UserMain.DoesNotExist, UserDashou.DoesNotExist):
                        return Response({
                            'code': 8,
                            'msg': '接单打手不存在或信息不完整',
                            'data': None
                        }, status=status.HTTP_400_BAD_REQUEST)

                    # 原子更新打手数据（使用 F 表达式）
                    UserDashou.objects.filter(id=dashou.id).update(
                        chengjiaozongliang=F('chengjiaozongliang') + 1,
                        yue=F('yue') + dashou_fencheng,
                        zonge=F('zonge') + dashou_fencheng,
                        jinrishouyi=F('jinrishouyi') + dashou_fencheng,
                        jinyueshouyi=F('jinyueshouyi') + dashou_fencheng,
                    )

                    # 更新商家成交单量
                    UserShangjia.objects.filter(id=shangjia.id).update(
                        chengjiao=F('chengjiao') + 1,
                    )

                    # 更新订单状态
                    order.zhuangtai = 3
                    order.save()

                # 处理评分（所有情况都处理）
                if pingfen > 0:
                    pingfen_obj, created = Pingfen.objects.get_or_create(
                        dashou=jiedan_dashou_id,
                        defaults={'zongfen': pingfen, 'cishu': 1}
                    )
                    if not created:
                        Pingfen.objects.filter(id=pingfen_obj.id).update(
                            zongfen=F('zongfen') + pingfen,
                            cishu=F('cishu') + 1,
                        )

                # 更新商家订单扩展表的评价
                DingdanShangjia.objects.filter(id=shangjia_kuozhan.id).update(
                    shangjia_pingjia=liuyan,
                )

                # 🔥 新增：调用打手每日统计（成交）
                try:
                    update_dashou_daily_by_action(
                        yonghuid=jiedan_dashou_id,
                        amount=dashou_fencheng,
                        action=2  # 2 表示成交（结算）
                    )
                    logger.info(f"打手 {jiedan_dashou_id} 每日统计更新成功")
                except Exception as e:
                    logger.error(f"打手每日统计更新失败: {e}")
                    # 不影响主流程

                # ✅ 新方法（行为驱动，更安全）
                update_shangjia_daily(
                    yonghuid=request.user.yonghuid,
                    amount=Decimal(str(jine)),
                    action=2  # 2 = 结算
                )

                # 商家订单管事分红（仅 fadan_pingtai=2）
                if order.fadan_pingtai == 2:
                    from dingdan.utils import settle_shangjia_order_guanshi_fenhong
                    settle_shangjia_order_guanshi_fenhong(order, jiedan_dashou_id)

                # 返回成功
                return Response({
                    'code': 0,
                    'msg': '结单成功',
                    'data': {
                        'dingdan_id': dingdan_id,
                        'new_zhuangtai': 3,
                        'jine': float(jine),
                        'dashou_fencheng': float(dashou_fencheng),
                        'jiedan_dashou_id': jiedan_dashou_id,
                        'pingfen': pingfen,
                        'liuyan': liuyan
                    }
                }, status=status.HTTP_200_OK)

        except Dingdan.DoesNotExist:
            return Response({
                'code': 5,
                'msg': '订单不存在',
                'data': None
            }, status=status.HTTP_404_NOT_FOUND)
        except Exception as e:
            logger.error(f"商家结单失败: {str(e)}", exc_info=True)
            return Response({
                'code': 9,
                'msg': '服务器内部错误，结单失败',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)




from dingdan.models import Dingdan, DingdanShangjia, Tuikuanjilu


class ShangjiaChexiaoView(APIView):
    """商家撤销订单申请接口"""
    permission_classes = [IsAuthenticated]  # JWT认证

    def post(self, request):
        # 1. 获取当前登录用户并验证商家身份
        try:
            current_user = request.user
            # 使用反向查询获取商家扩展信息（性能最佳）
            shangjia = current_user.shop_profile
        except UserShangjia.DoesNotExist:
            return Response({
                'code': 1,
                'msg': '您不是商家或商家信息未完善',
                'data': None
            }, status=status.HTTP_403_FORBIDDEN)

        # 2. 检查商家账号状态
        if shangjia.zhuangtai != 1:
            return Response({
                'code': 2,
                'msg': '商家账号状态异常，无法操作',
                'data': None
            }, status=status.HTTP_403_FORBIDDEN)

        # 3. 获取前端参数
        try:
            data = request.data
            dingdan_id = data.get('dingdan_id', '').strip()
            chexiao_liyou = data.get('chexiao_liyou', '').strip()
        except Exception:
            return Response({
                'code': 3,
                'msg': '参数格式错误',
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)

        # 4. 参数验证
        if not dingdan_id or not chexiao_liyou:
            return Response({
                'code': 4,
                'msg': '订单ID和撤销原因不能为空',
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)

        try:
            # 5. 使用事务确保数据一致性
            with transaction.atomic():
                # 查询订单主表
                dingdan = Dingdan.objects.filter(dingdan_id=dingdan_id).first()
                if not dingdan:
                    return Response({
                        'code': 5,
                        'msg': '订单不存在',
                        'data': None
                    }, status=status.HTTP_404_NOT_FOUND)

                # 6. 验证订单状态
                if dingdan.zhuangtai not in [1, 7]:
                    return Response({
                        'code': 6,
                        'msg': '当前订单状态不可撤销',
                        'data': None
                    }, status=status.HTTP_400_BAD_REQUEST)

                # 7. 验证订单所属商家（使用反向查询）
                shangjia_kuozhan = DingdanShangjia.objects.filter(
                    dingdan__dingdan_id=dingdan_id,
                    shangjia_id=current_user.yonghuid
                ).first()

                if not shangjia_kuozhan:
                    return Response({
                        'code': 7,
                        'msg': '您无权撤销此订单',
                        'data': None
                    }, status=status.HTTP_403_FORBIDDEN)

                # 8. 创建退款记录（注意：申请状态直接设为1-成功）
                Tuikuanjilu.objects.create(
                    dingdan_id=dingdan_id,
                    qingqiuid=current_user.yonghuid,
                    liyou=chexiao_liyou,
                    sqzhuangtai=1,  # 直接成功
                    jine=dingdan.jine,
                    dashou_fencheng=dingdan.dashou_fencheng,
                    jieshao=dingdan.jieshao,
                    beizhu=dingdan.beizhu,
                    nicheng=dingdan.nicheng,

                )

                # 9. 更新商家扩展表数据（使用F表达式原子操作）
                UserShangjia.objects.filter(id=shangjia.id).update(
                    yue=F('yue') + dingdan.jine,
                    tuikuan=F('tuikuan') + 1,
                    jinridingdan=F('jinridingdan') - 1,
                    jinyuedingdan=F('jinyuedingdan') - 1,
                    jinriliushui=F('jinriliushui') - dingdan.jine,
                    jinyueliushui=F('jinyueliushui') - dingdan.jine,

                )

                # 10. 更新订单状态为5（已退款）
                dingdan.zhuangtai = 5

                dingdan.save()


                # ✅ 新方法（行为驱动，更安全）
                from houtai.utils import update_shangjia_daily
                update_shangjia_daily(
                    yonghuid=request.user.yonghuid,
                    amount=Decimal(str(dingdan.jine)),
                    action=3  # 3 = 退款
                )

                return Response({
                    'code': 0,
                    'msg': '撤销成功',
                    'data': {
                        'dingdan_id': dingdan_id,
                        'new_zhuangtai': 5,
                        'tuikuan_liyou': chexiao_liyou,
                        'jine': float(dingdan.jine) if dingdan.jine else 0.0
                    }
                }, status=status.HTTP_200_OK)

        except Exception as e:
            # 记录异常日志
            import logging
            logger = logging.getLogger(__name__)
            logger.error(f"商家撤销订单失败: {str(e)}", exc_info=True)

            return Response({
                'code': 8,
                'msg': '服务器内部错误，撤销失败',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)






class ShangjiaTuikuanShenqingView(APIView):
    """商家退款申请接口"""
    permission_classes = [IsAuthenticated]  # JWT认证

    def post(self, request):
        # 1. 获取当前登录用户并验证商家身份
        try:
            current_user = request.user
            shangjia = current_user.shop_profile
        except UserShangjia.DoesNotExist:
            return Response({
                'code': 1,
                'msg': '您不是商家或商家信息未完善',
                'data': None
            }, status=status.HTTP_403_FORBIDDEN)

        # 2. 检查商家账号状态
        if shangjia.zhuangtai != 1:
            return Response({
                'code': 2,
                'msg': '商家账号状态异常，无法操作',
                'data': None
            }, status=status.HTTP_403_FORBIDDEN)

        # 3. 获取前端参数
        try:
            data = request.data
            dingdan_id = data.get('dingdan_id', '').strip()
            tuikuan_liyou = data.get('tuikuan_liyou', '').strip()
        except Exception:
            return Response({
                'code': 3,
                'msg': '参数格式错误',
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)

        # 4. 参数验证
        if not dingdan_id or not tuikuan_liyou:
            return Response({
                'code': 4,
                'msg': '订单ID和退款原因不能为空',
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)

        try:
            # 5. 使用事务确保数据一致性
            with transaction.atomic():
                # 查询订单主表
                dingdan = Dingdan.objects.filter(dingdan_id=dingdan_id).first()
                if not dingdan:
                    return Response({
                        'code': 5,
                        'msg': '订单不存在',
                        'data': None
                    }, status=status.HTTP_404_NOT_FOUND)

                # 6. 验证订单状态
                if dingdan.zhuangtai not in [2, 8]:
                    return Response({
                        'code': 6,
                        'msg': '当前订单状态不可申请退款',
                        'data': None
                    }, status=status.HTTP_400_BAD_REQUEST)

                # 7. 验证订单所属商家
                shangjia_kuozhan = DingdanShangjia.objects.filter(
                    dingdan__dingdan_id=dingdan_id,
                    shangjia_id=current_user.yonghuid
                ).first()

                if not shangjia_kuozhan:
                    return Response({
                        'code': 7,
                        'msg': '您无权为此订单申请退款',
                        'data': None
                    }, status=status.HTTP_403_FORBIDDEN)

                # ========== 8. 处理退款记录（修改点：先查询是否存在） ==========
                refund_record, created = Tuikuanjilu.objects.get_or_create(
                    dingdan_id=dingdan_id,
                    defaults={
                        'dashouid': dingdan.jiedan_dashou_id,
                        'qingqiuid': current_user.yonghuid,
                        'liyou': tuikuan_liyou,
                        'sqzhuangtai': 0,  # 待处理
                        'jine': dingdan.jine,
                        'dashou_fencheng': dingdan.dashou_fencheng,
                        'jieshao': dingdan.jieshao,
                        'beizhu': dingdan.beizhu,
                        'nicheng': dingdan.nicheng,
                    }
                )
                if not created:
                    # 记录已存在，更新退款理由和申请时间
                    refund_record.liyou = tuikuan_liyou
                    refund_record.save(update_fields=['liyou', 'update_time'])
                    logger.info(f"订单 {dingdan_id} 已有退款记录，已更新退款理由")

                # 9. 更新订单状态为4（退款中）
                dingdan.zhuangtai = 4
                dingdan.tkly = tuikuan_liyou
                dingdan.save()

                # ====== 原有功能：更新打手状态 ======
                if dingdan.jiedan_dashou_id:
                    try:
                        dashou_main = UserMain.objects.filter(
                            yonghuid=dingdan.jiedan_dashou_id
                        ).first()
                        if dashou_main and hasattr(dashou_main, 'dashou_profile'):
                            dashou_profile = dashou_main.dashou_profile
                            dashou_profile.zhuangtai = 1
                            dashou_profile.save()
                            logger.info(f"退款申请成功，打手状态已更新：订单{dingdan_id}，打手{dingdan.jiedan_dashou_id}状态变更为1")
                    except Exception as e:
                        logger.error(f"更新打手状态失败：{str(e)}，订单{dingdan_id}，打手ID{dingdan.jiedan_dashou_id}")

                # ========== 新增：如果是跨平台订单，异步通知对方平台 ==========
                if dingdan.is_cross == 1:
                    import threading
                    import requests
                    from django.conf import settings

                    def send_refund_notify():
                        url = f"{settings.PARTNER_BASE_URL}{settings.PARTNER_REFUND_NOTIFY_URL}"
                        payload = {
                            'token': settings.CROSS_PLATFORM_TOKEN,
                            'order_id': dingdan.dingdan_id
                        }
                        try:
                            resp = requests.post(url, json=payload, timeout=5)
                            if resp.status_code == 200:
                                data = resp.json()
                                if data.get('code') == 0:
                                    logger.info(f"跨平台退款通知发送成功: {dingdan.dingdan_id}")
                                else:
                                    logger.error(f"跨平台退款通知业务失败: {data}")
                            else:
                                logger.error(f"跨平台退款通知HTTP失败: {resp.status_code}")
                        except Exception as e:
                            logger.error(f"跨平台退款通知异常: {str(e)}", exc_info=True)

                    thread = threading.Thread(target=send_refund_notify)
                    thread.daemon = True
                    thread.start()
                    logger.info(f"跨平台退款通知线程已启动: {dingdan.dingdan_id}")
                # ========== 新增结束 ==========

                return Response({
                    'code': 0,
                    'msg': '退款申请提交成功',
                    'data': {
                        'dingdan_id': dingdan_id,
                        'new_zhuangtai': 4,
                        'tuikuan_liyou': tuikuan_liyou,
                        'jine': float(dingdan.jine) if dingdan.jine else 0.0,
                        'dashou_id': dingdan.jiedan_dashou_id
                    }
                }, status=status.HTTP_200_OK)

        except Exception as e:
            logger.error(f"商家退款申请失败: {str(e)}", exc_info=True)
            return Response({
                'code': 8,
                'msg': '服务器内部错误，申请失败',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


'''class ShangjiaTuikuanShenqingView(APIView):
    """商家退款申请接口"""
    permission_classes = [IsAuthenticated]  # JWT认证

    def post(self, request):
        # 1. 获取当前登录用户并验证商家身份
        try:
            current_user = request.user
            shangjia = current_user.shop_profile
        except UserShangjia.DoesNotExist:
            return Response({
                'code': 1,
                'msg': '您不是商家或商家信息未完善',
                'data': None
            }, status=status.HTTP_403_FORBIDDEN)

        # 2. 检查商家账号状态
        if shangjia.zhuangtai != 1:
            return Response({
                'code': 2,
                'msg': '商家账号状态异常，无法操作',
                'data': None
            }, status=status.HTTP_403_FORBIDDEN)

        # 3. 获取前端参数
        try:
            data = request.data
            dingdan_id = data.get('dingdan_id', '').strip()
            tuikuan_liyou = data.get('tuikuan_liyou', '').strip()
        except Exception:
            return Response({
                'code': 3,
                'msg': '参数格式错误',
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)

        # 4. 参数验证
        if not dingdan_id or not tuikuan_liyou:
            return Response({
                'code': 4,
                'msg': '订单ID和退款原因不能为空',
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)

        try:
            # 5. 使用事务确保数据一致性
            with transaction.atomic():
                # 查询订单主表
                dingdan = Dingdan.objects.filter(dingdan_id=dingdan_id).first()
                if not dingdan:
                    return Response({
                        'code': 5,
                        'msg': '订单不存在',
                        'data': None
                    }, status=status.HTTP_404_NOT_FOUND)

                # 6. 验证订单状态
                if dingdan.zhuangtai not in [2, 8]:
                    return Response({
                        'code': 6,
                        'msg': '当前订单状态不可申请退款',
                        'data': None
                    }, status=status.HTTP_400_BAD_REQUEST)

                # 7. 验证订单所属商家
                shangjia_kuozhan = DingdanShangjia.objects.filter(
                    dingdan__dingdan_id=dingdan_id,
                    shangjia_id=current_user.yonghuid
                ).first()

                if not shangjia_kuozhan:
                    return Response({
                        'code': 7,
                        'msg': '您无权为此订单申请退款',
                        'data': None
                    }, status=status.HTTP_403_FORBIDDEN)

                # 8. 创建退款记录（申请状态为0-待处理）
                Tuikuanjilu.objects.create(
                    dingdan_id=dingdan_id,
                    dashouid=dingdan.jiedan_dashou_id,
                    qingqiuid=current_user.yonghuid,
                    liyou=tuikuan_liyou,
                    sqzhuangtai=0,  # 待处理
                    jine=dingdan.jine,
                    dashou_fencheng=dingdan.dashou_fencheng,
                    jieshao=dingdan.jieshao,
                    beizhu=dingdan.beizhu,
                    nicheng=dingdan.nicheng,
                )

                # 9. 更新订单状态为4（退款中）
                dingdan.zhuangtai = 4
                dingdan.tkly = tuikuan_liyou
                dingdan.save()

                # ====== 原有功能：更新打手状态 ======
                if dingdan.jiedan_dashou_id:
                    try:
                        dashou_main = UserMain.objects.filter(
                            yonghuid=dingdan.jiedan_dashou_id
                        ).first()
                        if dashou_main and hasattr(dashou_main, 'dashou_profile'):
                            dashou_profile = dashou_main.dashou_profile
                            dashou_profile.zhuangtai = 1
                            dashou_profile.save()
                            logger.info(f"退款申请成功，打手状态已更新：订单{dingdan_id}，打手{dingdan.jiedan_dashou_id}状态变更为1")
                    except Exception as e:
                        logger.error(f"更新打手状态失败：{str(e)}，订单{dingdan_id}，打手ID{dingdan.jiedan_dashou_id}")

                # ========== 新增：如果是跨平台订单，异步通知对方平台 ==========
                if dingdan.is_cross == 1:
                    import threading
                    import requests
                    from django.conf import settings

                    def send_refund_notify():
                        url = f"{settings.PARTNER_BASE_URL}{settings.PARTNER_REFUND_NOTIFY_URL}"
                        payload = {
                            'token': settings.CROSS_PLATFORM_TOKEN,
                            'order_id': dingdan.dingdan_id  # 发送我方订单ID，对方用 partner_order_id 查找
                        }
                        try:
                            resp = requests.post(url, json=payload, timeout=5)
                            if resp.status_code == 200:
                                data = resp.json()
                                if data.get('code') == 0:
                                    logger.info(f"跨平台退款通知发送成功: {dingdan.dingdan_id}")
                                else:
                                    logger.error(f"跨平台退款通知业务失败: {data}")
                            else:
                                logger.error(f"跨平台退款通知HTTP失败: {resp.status_code}")
                        except Exception as e:
                            logger.error(f"跨平台退款通知异常: {str(e)}", exc_info=True)

                    thread = threading.Thread(target=send_refund_notify)
                    thread.daemon = True
                    thread.start()
                    logger.info(f"跨平台退款通知线程已启动: {dingdan.dingdan_id}")
                # ========== 新增结束 ==========

                return Response({
                    'code': 0,
                    'msg': '退款申请提交成功',
                    'data': {
                        'dingdan_id': dingdan_id,
                        'new_zhuangtai': 4,
                        'tuikuan_liyou': tuikuan_liyou,
                        'jine': float(dingdan.jine) if dingdan.jine else 0.0,
                        'dashou_id': dingdan.jiedan_dashou_id
                    }
                }, status=status.HTTP_200_OK)

        except Exception as e:
            logger.error(f"商家退款申请失败: {str(e)}", exc_info=True)
            return Response({
                'code': 8,
                'msg': '服务器内部错误，申请失败',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)'''




class ShangjiaChufaShenqingView(APIView):
    """商家处罚申请接口（已添加图片上传功能）"""
    permission_classes = [IsAuthenticated]  # JWT认证

    def post(self, request):
        # 1. 获取当前登录用户并验证商家身份
        try:
            current_user = request.user
            shangjia = current_user.shop_profile
        except UserShangjia.DoesNotExist:
            return Response({
                'code': 1,
                'msg': '您不是商家或商家信息未完善',
                'data': None
            }, status=status.HTTP_403_FORBIDDEN)

        # 2. 检查商家账号状态
        if shangjia.zhuangtai != 1:
            return Response({
                'code': 2,
                'msg': '商家账号状态异常，无法操作',
                'data': None
            }, status=status.HTTP_403_FORBIDDEN)

        # 3. 获取前端参数
        try:
            data = request.data
            dingdan_id = data.get('dingdan_id', '').strip()
            dashou_id = data.get('dashou_id', '').strip()
            chufa_liyou = data.get('chufa_liyou', '').strip()
            chufa_tupian_urls = data.get('chufa_tupian_urls', [])  # 🔴 新增：图片URL数组
        except Exception:
            return Response({
                'code': 3,
                'msg': '参数格式错误',
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)

        # 4. 参数验证
        if not dingdan_id or not dashou_id or not chufa_liyou:
            return Response({
                'code': 4,
                'msg': '订单ID、打手ID和处罚原因不能为空',
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)

        try:
            # 5. 使用事务确保数据一致性
            with transaction.atomic():
                # 验证打手身份
                try:
                    dashou_user = UserMain.objects.get(yonghuid=dashou_id)
                    dashou = dashou_user.dashou_profile
                except UserMain.DoesNotExist:
                    return Response({
                        'code': 5,
                        'msg': '打手用户不存在',
                        'data': None
                    }, status=status.HTTP_404_NOT_FOUND)
                except UserDashou.DoesNotExist:
                    return Response({
                        'code': 5,
                        'msg': '该用户不是打手',
                        'data': None
                    }, status=status.HTTP_400_BAD_REQUEST)

                # 查询订单主表
                dingdan = Dingdan.objects.filter(dingdan_id=dingdan_id).first()
                if not dingdan:
                    return Response({
                        'code': 6,
                        'msg': '订单不存在',
                        'data': None
                    }, status=status.HTTP_404_NOT_FOUND)

                # 验证订单状态
                if dingdan.zhuangtai not in [2, 8, 4, 5, 6, 3]:
                    return Response({
                        'code': 7,
                        'msg': '当前订单状态不可申请处罚',
                        'data': None
                    }, status=status.HTTP_400_BAD_REQUEST)

                # 验证订单所属商家
                shangjia_kuozhan = DingdanShangjia.objects.filter(
                    dingdan__dingdan_id=dingdan_id,
                    shangjia_id=current_user.yonghuid
                ).first()

                if not shangjia_kuozhan:
                    return Response({
                        'code': 8,
                        'msg': '您无权为此订单申请处罚',
                        'data': None
                    }, status=status.HTTP_403_FORBIDDEN)

                # 验证订单的打手是否与提供的打手ID一致
                if dingdan.jiedan_dashou_id != dashou_id:
                    return Response({
                        'code': 9,
                        'msg': '该打手并非此订单的服务打手',
                        'data': None
                    }, status=status.HTTP_400_BAD_REQUEST)

                # 创建处罚记录
                chufajilu = Chufajilu.objects.create(
                    dashouid=dashou_id,
                    qingqiuid=current_user.yonghuid,
                    cfliyou=chufa_liyou,
                    sqzhuangtai=0,  # 待处理
                    jifen=5,  # 扣除5积分
                    dingdan_id=dingdan_id,
                )
                # 🔴【新增】在创建处罚记录后立即扣除打手积分
                # 注意：这里使用前面已经获取的dashou对象（打手扩展表）
                jifen_kouchu = chufajilu.jifen  # 扣除的积分，这里是5
                if jifen_kouchu > 0:
                    # 检查打手积分是否足够
                    if dashou.jifen < jifen_kouchu:
                        dashou.jifen = 0
                    else:
                        dashou.jifen -= jifen_kouchu
                    dashou.save()

                # 🔴【新增】保存处罚图片到数据库
                if chufa_tupian_urls and isinstance(chufa_tupian_urls, list):
                    for tupian_url in chufa_tupian_urls:
                        if tupian_url and tupian_url.strip():
                            Chufatupian.objects.create(
                                dingdan_id=dingdan_id,
                                yonghuid=current_user.yonghuid,
                                tupian=tupian_url
                            )

                # 更新商家订单扩展表的处罚相关字段
                shangjia_kuozhan.cfliyou = chufa_liyou
                shangjia_kuozhan.sqzhuangtai = 0
                shangjia_kuozhan.save()

                return Response({
                    'code': 0,
                    'msg': '处罚申请提交成功',
                    'data': {
                        'dingdan_id': dingdan_id,
                        'dashou_id': dashou_id,
                        'chufa_liyou': chufa_liyou,
                        'sqzhuangtai': 0,
                        'jifen': 5,
                        'tupian_count': len(chufa_tupian_urls) if chufa_tupian_urls else 0  # 🔴 返回图片数量
                    }
                }, status=status.HTTP_200_OK)

        except Exception as e:
            import logging
            logger = logging.getLogger(__name__)
            logger.error(f"商家处罚申请失败: {str(e)}", exc_info=True)

            return Response({
                'code': 10,
                'msg': '服务器内部错误，申请失败',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


# apps/dingdan/views.py
from django.db.models import Q, OuterRef, Subquery
from django.core.paginator import Paginator
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from rest_framework_simplejwt.authentication import JWTAuthentication
from .models import Dingdan, DingdanShangjia



'''class DashouDingdanHuoquView(APIView):
    """
    获取可抢订单列表
    POST /dingdan/ddhq
    需要JWT Token认证
    """

    permission_classes = [IsAuthenticated]

    def post(self, request):
        # 1. 获取请求参数
        data = request.data
        leixing_id = data.get('leixing_id')
        page = int(data.get('page', 1))
        page_size = int(data.get('page_size', 10))

        # 2. 构建基础查询条件
        base_query = Q(zhuangtai__in=[1, 7])
        if leixing_id:
            base_query &= Q(leixing_id=leixing_id)

        # 3. 构建基础查询集（仅过滤，不执行）
        base_qs = Dingdan.objects.filter(base_query).order_by('-create_time')

        # 4. 获取总记录数
        total = base_qs.count()

        # 5. 计算分页偏移量
        offset = (page - 1) * page_size
        limit = page_size

        # 6. 获取当前页数据（数据库层切片，只返回当前页）
        page_qs = base_qs[offset:offset + limit]

        # 7. 使用子查询获取商家昵称（性能优化，只针对当前页）
        shangjia_sub = DingdanShangjia.objects.filter(
            dingdan_id=OuterRef('id')
        ).values('sjnicheng')[:1]

        # 8. 获取当前页所有需要的字段（包含商家昵称）
        dingdan_values = page_qs.annotate(
            sjnicheng=Subquery(shangjia_sub)
        ).values(
            'dingdan_id', 'zhuangtai', 'fadan_pingtai', 'dashou_fencheng',
            'zhiding_id', 'leixing_id', 'tupian', 'yaoqiuleixing',
            'huiyuan_id', 'yongjin', 'jieshao', 'beizhu', 'create_time',
            'sjnicheng'
        )

        # 9. 转换为列表以便后续修改
        dingdan_list = list(dingdan_values)

        # 10. 批量获取指定打手的头像和昵称
        zhiding_ids = {item['zhiding_id'] for item in dingdan_list if item.get('zhiding_id')}
        zhiding_info = {}
        if zhiding_ids:
            # 一次性查询所有打手信息（通过 UserMain 关联 UserDashou）
            dashou_query = UserMain.objects.filter(
                yonghuid__in=zhiding_ids
            ).select_related('dashou_profile').annotate(
                nicheng=F('dashou_profile__nicheng')
            ).values('yonghuid', 'avatar', 'nicheng')

            zhiding_info = {
                item['yonghuid']: {
                    'avatar': item['avatar'] or '',
                    'nicheng': item['nicheng'] or ''
                }
                for item in dashou_query
            }

        # 11. 格式化返回数据，并添加打手头像和昵称
        formatted_list = []
        for order in dingdan_list:
            zid = order.get('zhiding_id')
            info = zhiding_info.get(zid, {})
            formatted_order = {
                'dingdan_id': order['dingdan_id'],
                'zhuangtai': order['zhuangtai'],
                'pingtai': order['fadan_pingtai'],
                'fadan_pingtai': order['fadan_pingtai'],
                'dashou_fencheng': float(order['dashou_fencheng']) if order['dashou_fencheng'] else 0.0,
                'zhiding_id': order['zhiding_id'] or '',
                'leixing_id': order['leixing_id'] or 0,
                'tupian': order['tupian'] or '',
                'yaoqiuleixing': order['yaoqiuleixing'] or 0,
                'huiyuan_id': order['huiyuan_id'] or '',
                'yajin': float(order['yongjin']) if order['yongjin'] else 0.0,
                'yongjin': float(order['yongjin']) if order['yongjin'] else 0.0,
                'jieshao': order['jieshao'] or '',
                'beizhu': order['beizhu'] or '',
                'creat_time': order['create_time'].strftime('%Y-%m-%d %H:%M:%S') if order['create_time'] else '',
                'sjnicheng': order['sjnicheng'] or '',
                'zhiding_uid': order['zhiding_id'] or '',
                # 新增字段
                'zhiding_avatar': info.get('avatar', ''),
                'zhiding_nicheng': info.get('nicheng', ''),
            }
            formatted_list.append(formatted_order)

        # 12. 判断是否有更多数据
        has_more = (page * page_size) < total

        return Response({
            'code': 200,
            'msg': '获取成功',
            'data': {
                'list': formatted_list,
                'has_more': has_more,
                'total': total,
                'current_page': page,
                'page_size': page_size,
                'total_pages': (total + page_size - 1) // page_size,
            }
        })'''

# apps/dingdan/views.py
from shangpin.models import ShangpinLeixing  # 假设这是你的商品类型模型


class ShangpinLeixingHuoquView(APIView):
    """
    获取商品类型列表
    POST /dingdan/ddlxhq
    需要JWT Token认证
    """
    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAuthenticated]

    def post(self, request):
        # 1. 查询商品类型表
        # 假设你的商品类型模型字段为：id, jieshao, tupian_url
        leixing_list = ShangpinLeixing.objects.all().values(
            'id',  # 商品类型ID
            'jieshao',  # 类型介绍
            'tupian_url'  # 类型图片URL（相对URL）
        ).order_by('id')  # 按ID排序，可根据需要调整

        # 2. 格式化返回数据
        formatted_list = []
        for leixing in leixing_list:
            formatted_leixing = {
                'id': leixing['id'],
                'jieshao': leixing['jieshao'] or '',  # 处理空值
                'tupian_url': leixing['tupian_url'] or ''  # 处理空值
            }
            formatted_list.append(formatted_leixing)

        # 3. 返回响应
        return Response({
            'code': 200,
            'msg': '获取成功',
            'data': {
                'list': formatted_list,
                'total': len(formatted_list)
            }
        })












# dingdan/views.py
from django.db.models import Q, OuterRef, Subquery, F, Prefetch

from dengji.models import  DingdanBiaoqian
from dengji.models import YonghuChenghao, Chenghao
from rest_framework_simplejwt.authentication import JWTAuthentication

class DashouDingdanHuoquView(APIView):
    """
    获取可抢订单列表（支持标签筛选）
    POST /dingdan/ddhq
    需要JWT Token认证
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # 1. 获取请求参数
            data = request.data
            leixing_id = data.get('leixing_id')
            page = int(data.get('page', 1))
            page_size = int(data.get('page_size', 10))
            biaoqian_id = data.get('biaoqian_id')

            # 2. 构建基础查询条件
            base_query = Q(zhuangtai__in=[1, 7])
            if leixing_id:
                base_query &= Q(leixing_id=leixing_id)

            # 3. 标签筛选
            if biaoqian_id and int(biaoqian_id) > 0:
                base_query &= Q(dingdanbiaoqian__chenghao_id=int(biaoqian_id))

            # 4. 构建基础查询集
            base_qs = Dingdan.objects.filter(base_query).order_by('-create_time').distinct()

            # 5. 获取总记录数
            total = base_qs.count()

            # 6. 计算分页偏移量
            offset = (page - 1) * page_size
            limit = page_size

            # 7. 获取当前页数据，并通过 select_related 预取商家扩展表（反向关联）
            page_qs = base_qs[offset:offset + limit].select_related('shangjia_kuozhan')

            # 8. 获取当前页所有需要的字段
            dingdan_values = page_qs.values(
                'dingdan_id', 'zhuangtai', 'fadan_pingtai', 'dashou_fencheng',
                'zhiding_id', 'leixing_id', 'tupian', 'yaoqiuleixing',
                'huiyuan_id', 'yongjin', 'jieshao', 'beizhu', 'create_time',
                'shangjia_kuozhan__sjnicheng',  # 商家昵称
                'shangjia_kuozhan__shangjia_id', # 商家ID
            )

            # 9. 转换为列表并格式化
            dingdan_list = []
            for order in dingdan_values:
                dingdan_list.append({
                    'dingdan_id': order['dingdan_id'],
                    'zhuangtai': order['zhuangtai'],
                    'pingtai': order['fadan_pingtai'],
                    'fadan_pingtai': order['fadan_pingtai'],
                    'dashou_fencheng': float(order['dashou_fencheng']) if order['dashou_fencheng'] else 0.0,
                    'zhiding_id': order['zhiding_id'] or '',
                    'leixing_id': order['leixing_id'] or 0,
                    'tupian': order['tupian'] or '',
                    'yaoqiuleixing': order['yaoqiuleixing'] or 0,
                    'huiyuan_id': order['huiyuan_id'] or '',
                    'yajin': float(order['yongjin']) if order['yongjin'] else 0.0,
                    'yongjin': float(order['yongjin']) if order['yongjin'] else 0.0,
                    'jieshao': order['jieshao'] or '',
                    'beizhu': order['beizhu'] or '',
                    'creat_time': order['create_time'].strftime('%Y-%m-%d %H:%M:%S') if order['create_time'] else '',
                    'sjnicheng': order['shangjia_kuozhan__sjnicheng'] or '',
                    'sj_id': order['shangjia_kuozhan__shangjia_id'] or '',
                    # 其他字段后面补充
                })

            # 10. 批量获取指定打手的头像和昵称
            zhiding_ids = {item['zhiding_id'] for item in dingdan_list if item.get('zhiding_id')}
            zhiding_info = {}
            if zhiding_ids:
                dashou_query = UserMain.objects.filter(
                    yonghuid__in=zhiding_ids
                ).select_related('dashou_profile').annotate(
                    nicheng=F('dashou_profile__nicheng')
                ).values('yonghuid', 'avatar', 'nicheng')
                zhiding_info = {
                    item['yonghuid']: {
                        'avatar': item['avatar'] or '',
                        'nicheng': item['nicheng'] or ''
                    }
                    for item in dashou_query
                }

            # 11. 批量获取三层标签（不变）
            order_ids = [item['dingdan_id'] for item in dingdan_list]

            # --- 订单需求标签 ---
            xuqiu_tags_map = {}
            if order_ids:
                try:
                    dbq_qs = DingdanBiaoqian.objects.filter(
                        dingdan_id__in=order_ids
                    ).select_related('chenghao')
                    for dbq in dbq_qs:
                        oid = dbq.dingdan_id
                        if oid not in xuqiu_tags_map:
                            xuqiu_tags_map[oid] = []
                        ch = dbq.chenghao
                        xuqiu_tags_map[oid].append({
                            'id': ch.id,
                            'mingcheng': ch.mingcheng,
                            'texiao_json': self._parse_texiao_json(ch.texiao_miaoshu)
                        })
                except Exception as e:
                    logger.error(f"查询订单需求标签失败: {e}", exc_info=True)

            # --- 用户标签（打手+商家） ---
            yonghuid_set = set(zhiding_ids)
            # 商家ID从订单列表中提取（已含 sj_id）
            for item in dingdan_list:
                if item['fadan_pingtai'] == 2 and item.get('sj_id'):
                    yonghuid_set.add(item['sj_id'])

            user_id_map = {}
            if yonghuid_set:
                users = UserMain.objects.filter(yonghuid__in=yonghuid_set).values('id', 'yonghuid')
                for u in users:
                    user_id_map[u['yonghuid']] = u['id']

            user_main_ids = list(user_id_map.values())
            user_tags_map = {}
            if user_main_ids:
                uc_qs = YonghuChenghao.objects.filter(
                    yonghu_id__in=user_main_ids
                ).select_related('chenghao')
                for uc in uc_qs:
                    uid = uc.yonghu_id
                    if uid not in user_tags_map:
                        user_tags_map[uid] = []
                    user_tags_map[uid].append(uc.chenghao)

            # 为每个订单组装标签
            dashou_tags_map = {}
            shangjia_tags_map = {}
            for item in dingdan_list:
                oid = item['dingdan_id']
                # 打手标签
                zhid = item['zhiding_id']
                dashou_tags = []
                if zhid and zhid in user_id_map:
                    uid = user_id_map[zhid]
                    if uid in user_tags_map:
                        for ch in user_tags_map[uid]:
                            if ch.leixing == 'dashou':
                                dashou_tags.append({
                                    'id': ch.id,
                                    'mingcheng': ch.mingcheng,
                                    'texiao_json': self._parse_texiao_json(ch.texiao_miaoshu)
                                })
                dashou_tags_map[oid] = dashou_tags

                # 商家标签
                sj_tags = []
                if item['fadan_pingtai'] == 2:
                    sj_yonghuid = item.get('sj_id')
                    if sj_yonghuid and sj_yonghuid in user_id_map:
                        uid = user_id_map[sj_yonghuid]
                        if uid in user_tags_map:
                            for ch in user_tags_map[uid]:
                                if ch.leixing == 'shangjia':
                                    sj_tags.append({
                                        'id': ch.id,
                                        'mingcheng': ch.mingcheng,
                                        'texiao_json': self._parse_texiao_json(ch.texiao_miaoshu)
                                    })
                shangjia_tags_map[oid] = sj_tags

            # 12. 组装最终返回数据
            formatted_list = []
            for item in dingdan_list:
                oid = item['dingdan_id']
                zid = item.get('zhiding_id')
                info = zhiding_info.get(zid, {})
                formatted_list.append({
                    **item,
                    'zhiding_uid': zid,
                    'zhiding_avatar': info.get('avatar', ''),
                    'zhiding_nicheng': info.get('nicheng', ''),
                    'xuqiu_biaoqian': xuqiu_tags_map.get(oid, []),
                    'dashou_biaoqian': dashou_tags_map.get(oid, []),
                    'shangjia_biaoqian': shangjia_tags_map.get(oid, []),
                })

            has_more = (page * page_size) < total

            return Response({
                'code': 200,
                'msg': '获取成功',
                'data': {
                    'list': formatted_list,
                    'has_more': has_more,
                    'total': total,
                    'current_page': page,
                    'page_size': page_size,
                    'total_pages': (total + page_size - 1) // page_size,
                }
            })

        except Exception as e:
            logger.error(f"订单列表查询失败: {e}", exc_info=True)
            return Response({'code': 500, 'msg': f'服务器内部错误: {str(e)}'}, status=500)

    def _parse_texiao_json(self, texiao_miaoshu):
        if not texiao_miaoshu:
            return {}
        try:
            return json.loads(texiao_miaoshu)
        except:
            return {}






import logging

logger = logging.getLogger(__name__)




from rest_framework_simplejwt.authentication import JWTAuthentication
import logging


from .models import Dingdan, DingdanPingtai, DingdanShangjia


logger = logging.getLogger(__name__)

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from django.utils import timezone
from django.db.models import F


logger = logging.getLogger(__name__)






'''class QiangdanView(APIView):
    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAuthenticated]

    def post(self, request):
        data = request.data
        dingdan_id = data.get('dingdan_id')
        if not dingdan_id:
            return Response({'code': 400, 'msg': '订单ID不能为空'}, status=400)

        try:
            with transaction.atomic():
                # 1. 验证打手身份和状态
                dashou_profile = self._validate_dashou_status(request.user)
                if not dashou_profile:
                    return Response({'code': 403, 'msg': '您不是打手或账号状态异常'}, status=403)

                # 2. 锁定并验证订单（行锁）
                order_result = self._validate_and_lock_order(dingdan_id, request.user.yonghuid)
                if isinstance(order_result, str):
                    return Response({'code': 400, 'msg': order_result})
                order = order_result

                is_cross = order.is_cross == 1
                dispatch_type = order.dispatch_type  # 1=我方派单，2=对方派单

                # ========== 跨平台订单处理 ==========
                if is_cross and dispatch_type == 2:
                    # 对方派单（跨平台且对方派给我方）
                    validation_result = self._validate_order_requirements(order, dashou_profile, request.user.yonghuid)
                    if not validation_result['success']:
                        return Response({'code': 400, 'msg': validation_result['message']})

                    # 向对方平台发送抢单询问
                    claim_allowed = self._request_partner_check_claim(order, request.user.yonghuid)
                    if claim_allowed is None:
                        return Response({'code': 500, 'msg': '跨平台通信失败，请重试'}, status=500)
                    elif claim_allowed is False:
                        if order.zhuangtai == 1:
                            order.zhuangtai = 21
                            order.save()
                            logger.info(f"订单 {dingdan_id} 被对方拒绝抢单，状态改为21")
                        else:
                            order.zhuangtai = 20
                            order.save()
                            logger.info(f"订单 {dingdan_id} 已被其他平台抢走，状态改为20")
                        return Response({'code': 400, 'msg': '订单已被其他平台打手抢走或不可抢'})

                    # 允许抢单，执行本地抢单
                    self._execute_qiangdan(order, dashou_profile, request.user.yonghuid)

                    # 更新抢单统计（对方派单，我方抢到）
                    try:
                        update_daily_dispatch_stat(
                            direction=2,  # 对方派单
                            partner_club_id=order.partner_club_id or '000001',
                            claimed_amount=order.jine,   # 订单金额
                            claimed_count=1
                        )
                    except Exception as e:
                        logger.error(f"更新抢单统计失败: {e}", exc_info=True)

                elif is_cross and dispatch_type == 1:
                    # 我方派单
                    validation_result = self._validate_order_requirements(order, dashou_profile, request.user.yonghuid)
                    if not validation_result['success']:
                        return Response({'code': 400, 'msg': validation_result['message']})

                    self._execute_qiangdan(order, dashou_profile, request.user.yonghuid)

                    # 异步通知所有合作俱乐部：此订单已被抢
                    self._async_notify_partners_order_claimed(order)

                else:
                    # 普通订单
                    validation_result = self._validate_order_requirements(order, dashou_profile, request.user.yonghuid)
                    if not validation_result['success']:
                        return Response({'code': 400, 'msg': validation_result['message']})
                    self._execute_qiangdan(order, dashou_profile, request.user.yonghuid)

                # 抢单成功后建立聊天关系（事务外）
                chat_success = self._establish_chat_relationship(order, request.user.yonghuid, dashou_profile, request.user.avatar)

            # 🔥 新增：调用打手每日统计（成交）
            try:
                update_dashou_daily_by_action(
                    yonghuid=order.jiedan_dashou_id,
                    amount=order.dashou_fencheng,
                    action=1  # 1 表示接单（接单）
                )
                logger.info(f"打手 {order.jiedan_dashou_id} 每日统计更新成功")
            except Exception as e:
                logger.error(f"打手每日统计更新失败: {e}")
                # 不影响主流程

            return Response({
                'code': 200,
                'msg': '抢单成功',
                'data': {
                    'dingdan_id': dingdan_id,
                    'chat_established': chat_success
                }
            })

        except Exception as e:
            logger.error(f"抢单异常: {str(e)}", exc_info=True)
            return Response({'code': 500, 'msg': '系统异常，请稍后重试'}, status=500)

    # ---------- 辅助方法 ----------
    def _validate_dashou_status(self, user):
        try:
            dashou_profile = user.dashou_profile
            if (dashou_profile.zhuangtai != 1 or
                dashou_profile.zhanghaozhuangtai != 1 or
                dashou_profile.jifen < 5):
                return None
            return dashou_profile
        except UserDashou.DoesNotExist:
            return None

    def _validate_and_lock_order(self, dingdan_id, dashou_yonghuid):
        try:
            order = Dingdan.objects.select_for_update().get(dingdan_id=dingdan_id)
            if order.zhuangtai not in [1, 7]:
                return "订单状态不可抢"
            if order.zhuangtai == 7:
                if not order.zhiding_id or order.zhiding_id != dashou_yonghuid:
                    return "此订单为指定单，您不是指定打手"
            if order.jiedan_dashou_id:
                return "订单已被其他打手抢走"
            return order
        except Dingdan.DoesNotExist:
            return "订单不存在"

    def _validate_order_requirements(self, order, dashou_profile, dashou_yonghuid):
        if order.yaoqiuleixing == 1:
            return self._validate_huiyuan_requirement(order, dashou_yonghuid)
        elif order.yaoqiuleixing == 2:
            return self._validate_yajin_requirement(order, dashou_profile)
        return {'success': True, 'message': '验证通过'}

    def _validate_huiyuan_requirement(self, order, dashou_yonghuid):
        try:
            huiyuan_record = Huiyuangoumai.objects.get(
                huiyuan_id=order.huiyuan_id,
                yonghu_id=dashou_yonghuid
            )
            if huiyuan_record.jiance_shifou_daoqi() or huiyuan_record.huiyuan_zhuangtai != 1:
                return {'success': False, 'message': '会员已过期或未开通对应会员'}
            return {'success': True, 'message': '会员验证通过'}
        except Huiyuangoumai.DoesNotExist:
            return {'success': False, 'message': '未开通对应会员，无法抢此订单'}

    def _validate_yajin_requirement(self, order, dashou_profile):
        yajin_required = order.yongjin or 0
        dashou_yajin = dashou_profile.yajin or 0
        if dashou_yajin < yajin_required:
            return {'success': False, 'message': f'押金不足，需要{yajin_required}元，当前有{dashou_yajin}元'}
        return {'success': True, 'message': '押金验证通过'}

    def _execute_qiangdan(self, order, dashou_profile, dashou_yonghuid):
        order.zhuangtai = 2
        order.jiedan_dashou_id = dashou_yonghuid
        order.user2_id = f"Ds{dashou_yonghuid}"
        order.save()

        dashou_profile.zhuangtai = 0
        dashou_profile.jiedanzongliang = F('jiedanzongliang') + 1
        dashou_profile.jinrijiedan = F('jinrijiedan') + 1
        dashou_profile.jinyuejiedan = F('jinyuejiedan') + 1
        dashou_profile.save()

    # ---------- 跨平台询问对方 ----------
    def _request_partner_check_claim(self, order, dashou_id):
        partner_club_id = order.partner_club_id or '000001'
        try:
            club = Club.objects.filter(partner_club_id=partner_club_id).first()
            if not club or not club.partner_domain:
                logger.error(f"未找到对方俱乐部配置: partner_club_id={partner_club_id}")
                return None

            my_club = Club.objects.filter(partner_club_id=club.partner_club_id).first()
            if not my_club:
                logger.error(f"未找到我方俱乐部配置: partner_club_id={club.partner_club_id}")
                return None

            payload = {
                'token': settings.CROSS_PLATFORM_TOKEN,
                'wofangdingdan_id': order.partner_order_id,
                'partner_order_id': order.dingdan_id,
                'our_club_id': my_club.club_id,
                'partner_club_id': club.partner_club_id,
                'dashou_id': dashou_id,
                'sj_id': f"Sj{settings.AGENT_SHANGJIA_ID}"
            }

            url = club.partner_domain.rstrip('/') + '/dingdan/partner_check_claim'
            resp = requests.post(url, json=payload, timeout=5)

            if resp.status_code != 200:
                logger.error(f"跨平台抢单询问HTTP失败: {resp.status_code}")
                return None

            data = resp.json()
            if data.get('code') == 0:
                return data.get('data', {}).get('can_claim') is True
            else:
                logger.error(f"跨平台抢单询问业务失败: {data}")
                return False
        except Exception as e:
            logger.error(f"跨平台抢单询问异常: {e}", exc_info=True)
            return None

    # ---------- 异步通知其他俱乐部 ----------
    def _async_notify_partners_order_claimed(self, order):
        def notify_task():
            clubs = Club.objects.filter(is_interop_enabled=True).select_related()
            for club in clubs:
                for attempt in range(1, 4):
                    success = self._send_claim_notification_to_partner(order, club)
                    if success:
                        break
                    if attempt < 3:
                        import time
                        time.sleep(2 ** attempt)
                    else:
                        logger.error(f"通知俱乐部 {club.club_id} 订单已抢失败，重试3次后仍失败")

        thread = threading.Thread(target=notify_task)
        thread.daemon = True
        thread.start()

    def _send_claim_notification_to_partner(self, order, club):
        try:
            my_club = Club.objects.filter(partner_club_id=club.partner_club_id).first()
            if not my_club:
                logger.warning(f"未找到我方俱乐部配置: partner_club_id={club.partner_club_id}")
                return False

            payload = {
                'token': settings.CROSS_PLATFORM_TOKEN,
                'our_club_id': my_club.club_id,
                'partner_club_id': club.partner_club_id,
                'partner_order_id': order.dingdan_id,
                'claimed': True
            }
            url = club.partner_domain.rstrip('/') + '/dingdan/partner_notify_claim'
            resp = requests.post(url, json=payload, timeout=3)
            return resp.status_code == 200
        except Exception as e:
            logger.error(f"通知俱乐部 {club.club_id} 异常: {e}")
            return False

    # ---------- 聊天关系建立（完整版） ----------
    def _establish_chat_relationship(self, order, dashou_yonghuid, dashou_profile, dashou_avatar):
        try:
            dashou_info = {
                'goeasy_id': f"Ds{dashou_yonghuid}",
                'avatar': dashou_avatar or '',
                'nickname': dashou_profile.nicheng or f'打手{dashou_yonghuid}'
            }

            laoban_info = self._get_laoban_info(order)
            if not laoban_info:
                return False

            # 打手给老板/商家发消息
            success1 = self._send_goeasy_message(
                sender_id=dashou_info['goeasy_id'],
                sender_data={
                    "avatar": dashou_info['avatar'],
                    "name": dashou_info['nickname'],
                    "nickname": dashou_info['nickname']
                },
                receiver_id=laoban_info['goeasy_id'],
                receiver_data={
                    "avatar": laoban_info['avatar'],
                    "name": laoban_info['nickname'],
                    "nickname": laoban_info['nickname']
                },
                message_type="text",
                message_payload={
                    "action": "new_chat",
                    "partner_id": laoban_info['goeasy_id'],
                    "partner_info": {
                        "userId": laoban_info['goeasy_id'],
                        "avatar": laoban_info['avatar'],
                        "name": laoban_info['nickname'],
                        "nickname": laoban_info['nickname']
                    },
                    "order_id": order.dingdan_id,
                    "message": f"您好，我已接单：{order.jieshao}，您的备注是：{order.beizhu}，游戏ID是：{order.nicheng}  请确认订单信息"
                }
            )

            # 老板/商家给打手发消息
            success2 = self._send_goeasy_message(
                sender_id=laoban_info['goeasy_id'],
                sender_data={
                    "avatar": laoban_info['avatar'],
                    "name": laoban_info['nickname'],
                    "nickname": laoban_info['nickname']
                },
                receiver_id=dashou_info['goeasy_id'],
                receiver_data={
                    "avatar": dashou_info['avatar'],
                    "name": dashou_info['nickname'],
                    "nickname": dashou_info['nickname']
                },
                message_type="text",
                message_payload={
                    "action": "new_chat",
                    "partner_id": dashou_info['goeasy_id'],
                    "partner_info": {
                        "userId": dashou_info['goeasy_id'],
                        "avatar": dashou_info['avatar'],
                        "name": dashou_info['nickname'],
                        "nickname": dashou_info['nickname']
                    },
                    "order_id": order.dingdan_id,
                    "message": f"好的，订单已确认，请开始服务"
                }
            )

            return success1 and success2

        except Exception as e:
            logger.error(f"建立聊天关系异常: {e}", exc_info=True)
            return False

    def _get_laoban_info(self, order):
        try:
            laoban_info = {
                'goeasy_id': '',
                'avatar': '',
                'nickname': ''
            }

            if order.fadan_pingtai == 1:
                pingtai_kuozhan = DingdanPingtai.objects.filter(dingdan=order).first()
                if not pingtai_kuozhan or not pingtai_kuozhan.laoban_id:
                    return None
                yonghuid = pingtai_kuozhan.laoban_id
                laoban_info['goeasy_id'] = f"Boss{yonghuid}"
                laoban_user = UserMain.objects.filter(yonghuid=yonghuid).first()
                if not laoban_user:
                    return None
                laoban_info['avatar'] = laoban_user.avatar or ''
                boss_profile = UserBoss.objects.filter(user=laoban_user).first()
                laoban_info['nickname'] = boss_profile.nickname if boss_profile and boss_profile.nickname else f'老板{yonghuid}'

            elif order.fadan_pingtai == 2:
                shangjia_kuozhan = DingdanShangjia.objects.filter(dingdan=order).first()
                if not shangjia_kuozhan or not shangjia_kuozhan.shangjia_id:
                    return None
                yonghuid = shangjia_kuozhan.shangjia_id
                laoban_info['goeasy_id'] = f"Sj{yonghuid}"
                shangjia_user = UserMain.objects.filter(yonghuid=yonghuid).first()
                if not shangjia_user:
                    return None
                laoban_info['avatar'] = shangjia_user.avatar or ''
                if shangjia_kuozhan.sjnicheng:
                    laoban_info['nickname'] = shangjia_kuozhan.sjnicheng
                else:
                    shop_profile = UserShangjia.objects.filter(user=shangjia_user).first()
                    laoban_info['nickname'] = shop_profile.nicheng if shop_profile else f'商家{yonghuid}'
            else:
                if order.user1_id:
                    laoban_info['goeasy_id'] = order.user1_id
                    if laoban_info['goeasy_id'].startswith('Boss'):
                        yonghuid = laoban_info['goeasy_id'][4:]
                        laoban_info['nickname'] = f'老板{yonghuid}'
                    elif laoban_info['goeasy_id'].startswith('Sj'):
                        yonghuid = laoban_info['goeasy_id'][2:]
                        laoban_info['nickname'] = f'商家{yonghuid}'
                    else:
                        laoban_info['nickname'] = '用户'
                else:
                    return None

            if not laoban_info['goeasy_id']:
                return None
            return laoban_info

        except Exception as e:
            logger.error(f"获取老板信息异常: {e}", exc_info=True)
            return None

    def _send_goeasy_message(self, sender_id, sender_data, receiver_id, receiver_data, message_type, message_payload):
        try:
            if not hasattr(settings, 'GOEASY_APPKEY') or not settings.GOEASY_APPKEY:
                return False
            if not hasattr(settings, 'GOEASY_SECRET') or not settings.GOEASY_SECRET:
                return False
            if not hasattr(settings, 'GOEASY_REST_URL') or not settings.GOEASY_REST_URL:
                return False

            appkey = settings.GOEASY_APPKEY
            secret = settings.GOEASY_SECRET
            url = settings.GOEASY_REST_URL

            if isinstance(message_payload, dict) and 'message' in message_payload:
                payload_text = str(message_payload['message'])
            else:
                payload_text = str(message_payload)

            payload_data = {"text": payload_text}
            payload_str = json.dumps(payload_data, ensure_ascii=False)

            request_data = {
                "appkey": appkey,
                "senderId": str(sender_id),
                "senderData": {
                    "avatar": str(sender_data.get('avatar', '')),
                    "name": str(sender_data.get('name', '系统通知'))
                },
                "to": {
                    "type": "private",
                    "id": str(receiver_id),
                    "data": {
                        "avatar": str(receiver_data.get('avatar', '')),
                        "name": str(receiver_data.get('name', '用户'))
                    }
                },
                "type": "text",
                "payload": payload_str
            }

            headers = {
                "Content-Type": "application/json",
                "Authorization": f"Bearer {secret}"
            }

            response = requests.post(url, headers=headers, json=request_data, timeout=10)
            return response.status_code == 200

        except Exception as e:
            logger.error(f"发送GoEasy消息异常: {e}", exc_info=True)
            return False'''



from peizhi.models import ClubConfig
from utils.chat_utils import establish_order_chat   # 【新增】导入聊天工具
class QiangdanView(APIView):
    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAuthenticated]

    def post(self, request):
        data = request.data
        dingdan_id = data.get('dingdan_id')
        if not dingdan_id:
            return Response({'code': 400, 'msg': '订单ID不能为空'}, status=400)

        try:
            with transaction.atomic():
                # 1. 验证打手身份和状态
                dashou_profile = self._validate_dashou_status(request.user)
                if not dashou_profile:
                    return Response({'code': 403, 'msg': '您不是打手或账号状态异常'}, status=403)

                # ==================== 【新增】罚单检查 ====================
                from utils.fadan_utils import check_fadan_qiangdan_eligible
                fadan_ok, fadan_msg = check_fadan_qiangdan_eligible(request.user.yonghuid,1)
                if not fadan_ok:
                    return Response({'code': 400, 'msg': fadan_msg})
                # =========================================================
                # ========== 标签快速校验（提前拒绝，避免锁资源） ==========
                from dengji.utils import check_dashou_biaoqian_required
                biaoqian_ok, biaoqian_msg = check_dashou_biaoqian_required(dingdan_id, request.user.yonghuid)
                if not biaoqian_ok:
                    return Response({'code': 400, 'msg': biaoqian_msg})
                # ===========================================================

                # 2. 锁定并验证订单（行锁）
                order_result = self._validate_and_lock_order(dingdan_id, request.user.yonghuid)
                if isinstance(order_result, str):
                    return Response({'code': 400, 'msg': order_result})
                order = order_result

                is_cross = order.is_cross == 1
                dispatch_type = order.dispatch_type

                if is_cross and dispatch_type == 2:
                    validation_result = self._validate_order_requirements(order, dashou_profile, request.user.yonghuid)
                    if not validation_result['success']:
                        return Response({'code': 400, 'msg': validation_result['message']})

                    claim_allowed = self._request_partner_check_claim(order, request.user.yonghuid)
                    if claim_allowed is None:
                        return Response({'code': 500, 'msg': '跨平台通信失败，请重试'}, status=500)
                    elif claim_allowed is False:
                        if order.zhuangtai == 1:
                            order.zhuangtai = 21
                            order.save()
                            logger.info(f"订单 {dingdan_id} 被对方拒绝抢单，状态改为21")
                        else:
                            order.zhuangtai = 20
                            order.save()
                            logger.info(f"订单 {dingdan_id} 已被其他平台抢走，状态改为20")
                        return Response({'code': 400, 'msg': '订单已被其他平台打手抢走或不可抢'})

                    self._execute_qiangdan(order, dashou_profile, request.user.yonghuid)

                    try:
                        update_daily_dispatch_stat(
                            direction=2,
                            partner_club_id=order.partner_club_id or '000001',
                            claimed_amount=order.jine,
                            claimed_count=1
                        )
                    except Exception as e:
                        logger.error(f"更新抢单统计失败: {e}", exc_info=True)

                elif is_cross and dispatch_type == 1:
                    validation_result = self._validate_order_requirements(order, dashou_profile, request.user.yonghuid)
                    if not validation_result['success']:
                        return Response({'code': 400, 'msg': validation_result['message']})

                    self._execute_qiangdan(order, dashou_profile, request.user.yonghuid)
                    self._async_notify_partners_order_claimed(order)

                else:
                    validation_result = self._validate_order_requirements(order, dashou_profile, request.user.yonghuid)
                    if not validation_result['success']:
                        return Response({'code': 400, 'msg': validation_result['message']})
                    self._execute_qiangdan(order, dashou_profile, request.user.yonghuid)

                # ========== 【唯一改动】聊天建立方式 ==========
                chat_success = establish_order_chat(dingdan_id)

            try:
                update_dashou_daily_by_action(
                    yonghuid=order.jiedan_dashou_id,
                    amount=order.dashou_fencheng,
                    action=1
                )
                logger.info(f"打手 {order.jiedan_dashou_id} 每日统计更新成功")
            except Exception as e:
                logger.error(f"打手每日统计更新失败: {e}")

            # 在 QiangdanView.post 里，_execute_qiangdan 之后添加：
            from dengji.services import record_dashou_biaoxian
            # 记录抢单表现（不影响主流程）
            # 如果订单表里有 bankuai 信息，可以用 order.bankuai 代替 None
            record_dashou_biaoxian(
                dingdan_id=dingdan_id,
                dashou_id=order.jiedan_dashou_id,
                xingwei=1,
                jiedan_time=timezone.now(),  # 直接取当前时间
                bankuai=None  # 暂不填，后续提交时补上
            )


            return Response({
                'code': 200,
                'msg': '抢单成功',
                'data': {
                    'dingdan_id': dingdan_id,
                    'chat_established': chat_success
                }
            })

        except Exception as e:
            logger.error(f"抢单异常: {str(e)}", exc_info=True)
            return Response({'code': 500, 'msg': '系统异常，请稍后重试'}, status=500)

    # ---------- 以下所有方法原封不动照抄旧版 ----------
    def _validate_dashou_status(self, user):
        try:
            dashou_profile = user.dashou_profile
            if (dashou_profile.zhuangtai != 1 or
                dashou_profile.zhanghaozhuangtai != 1 or
                dashou_profile.jifen < 5):
                return None
            return dashou_profile
        except UserDashou.DoesNotExist:
            return None

    def _validate_and_lock_order(self, dingdan_id, dashou_yonghuid):
        try:
            order = Dingdan.objects.select_for_update().get(dingdan_id=dingdan_id)
            if order.zhuangtai not in [1, 7]:
                return "订单状态不可抢"
            if order.zhuangtai == 7:
                if not order.zhiding_id or order.zhiding_id != dashou_yonghuid:
                    return "此订单为指定单，您不是指定打手"
            if order.jiedan_dashou_id:
                return "订单已被其他打手抢走"
            return order
        except Dingdan.DoesNotExist:
            return "订单不存在"

    def _validate_order_requirements(self, order, dashou_profile, dashou_yonghuid):
        if order.yaoqiuleixing == 1:
            return self._validate_huiyuan_requirement(order, dashou_yonghuid)
        elif order.yaoqiuleixing == 2:
            return self._validate_yajin_requirement(order, dashou_profile)
        return {'success': True, 'message': '验证通过'}

    def _validate_huiyuan_requirement(self, order, dashou_yonghuid):
        try:
            huiyuan_record = Huiyuangoumai.objects.get(
                huiyuan_id=order.huiyuan_id,
                yonghu_id=dashou_yonghuid
            )
            if huiyuan_record.jiance_shifou_daoqi() or huiyuan_record.huiyuan_zhuangtai != 1:
                return {'success': False, 'message': '会员已过期或未开通对应会员'}
            return {'success': True, 'message': '会员验证通过'}
        except Huiyuangoumai.DoesNotExist:
            return {'success': False, 'message': '未开通对应会员，无法抢此订单'}

    def _validate_yajin_requirement(self, order, dashou_profile):
        yajin_required = order.yongjin or 0
        dashou_yajin = dashou_profile.yajin or 0
        if dashou_yajin < yajin_required:
            return {'success': False, 'message': f'押金不足，需要{yajin_required}元，当前有{dashou_yajin}元'}
        return {'success': True, 'message': '押金验证通过'}

    def _execute_qiangdan(self, order, dashou_profile, dashou_yonghuid):
        order.zhuangtai = 2
        order.jiedan_dashou_id = dashou_yonghuid
        order.user2_id = f"Ds{dashou_yonghuid}"
        order.save()

        dashou_profile.zhuangtai = 0
        dashou_profile.jiedanzongliang = F('jiedanzongliang') + 1
        dashou_profile.jinrijiedan = F('jinrijiedan') + 1
        dashou_profile.jinyuejiedan = F('jinyuejiedan') + 1
        dashou_profile.save()

    # ---------- 跨平台询问对方（照抄） ----------
    def _request_partner_check_claim(self, order, dashou_id):
        partner_club_id = order.partner_club_id or '000001'
        try:
            club = Club.objects.filter(partner_club_id=partner_club_id).first()
            if not club or not club.partner_domain:
                logger.error(f"未找到对方俱乐部配置: partner_club_id={partner_club_id}")
                return None

            my_club = Club.objects.filter(partner_club_id=club.partner_club_id).first()
            if not my_club:
                logger.error(f"未找到我方俱乐部配置: partner_club_id={club.partner_club_id}")
                return None

            payload = {
                'token': settings.CROSS_PLATFORM_TOKEN,
                'wofangdingdan_id': order.partner_order_id,
                'partner_order_id': order.dingdan_id,
                'our_club_id': my_club.club_id,
                'partner_club_id': club.partner_club_id,
                'dashou_id': dashou_id,
                'sj_id': f"Sj{settings.AGENT_SHANGJIA_ID}"
            }

            url = club.partner_domain.rstrip('/') + '/dingdan/partner_check_claim'
            resp = requests.post(url, json=payload, timeout=5)

            if resp.status_code != 200:
                logger.error(f"跨平台抢单询问HTTP失败: {resp.status_code}")
                return None

            data = resp.json()
            if data.get('code') == 0:
                return data.get('data', {}).get('can_claim') is True
            else:
                logger.error(f"跨平台抢单询问业务失败: {data}")
                return False
        except Exception as e:
            logger.error(f"跨平台抢单询问异常: {e}", exc_info=True)
            return None

    # ---------- 异步通知其他俱乐部 ----------
    def _async_notify_partners_order_claimed(self, order):
        def notify_task():
            clubs = Club.objects.filter(is_interop_enabled=True).select_related()
            for club in clubs:
                for attempt in range(1, 4):
                    success = self._send_claim_notification_to_partner(order, club)
                    if success:
                        break
                    if attempt < 3:
                        time.sleep(2 ** attempt)
                    else:
                        logger.error(f"通知俱乐部 {club.club_id} 订单已抢失败，重试3次后仍失败")

        thread = threading.Thread(target=notify_task)
        thread.daemon = True
        thread.start()

    def _send_claim_notification_to_partner(self, order, club):
        try:
            my_club = Club.objects.filter(partner_club_id=club.partner_club_id).first()
            if not my_club:
                logger.warning(f"未找到我方俱乐部配置: partner_club_id={club.partner_club_id}")
                return False

            payload = {
                'token': settings.CROSS_PLATFORM_TOKEN,
                'our_club_id': my_club.club_id,
                'partner_club_id': club.partner_club_id,
                'partner_order_id': order.dingdan_id,
                'claimed': True
            }
            url = club.partner_domain.rstrip('/') + '/dingdan/partner_notify_claim'
            resp = requests.post(url, json=payload, timeout=3)
            return resp.status_code == 200
        except Exception as e:
            logger.error(f"通知俱乐部 {club.club_id} 异常: {e}")
            return False


# dingdan/views.py
import logging
import requests
from rest_framework.views import APIView
from rest_framework.response import Response
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

logger = logging.getLogger('dingdan')


# ----------------- 基础配置获取 -----------------
def get_self_goeasy_appkey():
    try:
        cfg = ClubConfig.objects.filter(is_self=1).first()
        return cfg.chat_api_key if cfg else None
    except Exception:
        return None


def get_self_goeasy_secret():
    try:
        cfg = ClubConfig.objects.filter(is_self=1).first()
        return cfg.chat_api_id if cfg else None
    except Exception:
        return None


def get_self_storage_domain():
    try:
        cfg = ClubConfig.objects.filter(is_self=1).first()
        return cfg.storage_bucket_domain if cfg else ''
    except Exception:
        return ''


def full_avatar(relative_url, bucket_domain=None):
    if not relative_url:
        return ''
    if relative_url.startswith('http'):
        return relative_url
    domain = bucket_domain or get_self_storage_domain()
    if domain:
        domain = domain.rstrip('/') + '/'
        return domain + relative_url.lstrip('/')
    return relative_url


# ----------------- GoEasy API 封装 -----------------
def subscribe_users_to_group(user_ids, group_ids, appkey=None, secret=None):
    """订阅用户到群组，确保能收发该群消息"""
    if not appkey:
        appkey = get_self_goeasy_appkey()
    if not secret:
        secret = get_self_goeasy_secret()
    if not appkey:
        logger.error("订阅失败：GoEasy AppKey 未配置")
        return False
    url = 'https://rest-hangzhou.goeasy.io/v2/im/subscribe-groups'
    body = {"appkey": appkey, "userIds": user_ids, "groupIds": group_ids}
    headers = {"Content-Type": "application/json"}
    if secret:
        headers["Authorization"] = f"Bearer {secret}"
    try:
        r = requests.post(url, headers=headers, json=body, timeout=10)
        if r.status_code == 200:
            logger.info(f"订阅成功：用户 {user_ids} -> 群 {group_ids}")
            return True
        logger.error(f"订阅失败：{r.status_code} {r.text}")
        return False
    except Exception as e:
        logger.exception("订阅异常")
        return False


def send_group_message(
    appkey, secret, group_id, sender_id, sender_name, sender_avatar,
    message_text='', custom_payload=None, group_name='', order_id='', is_cross=0
):
    """
    通过 GoEasy REST API 发送群消息。
    message_text: 普通文本内容
    custom_payload: 自定义消息体（如订单卡片），此时 type 设为 'order'
    """
    url = 'https://rest-hangzhou.goeasy.io/v2/im/message'
    to_data = {
        "name": group_name or group_id,
        "avatar": sender_avatar or '',
        "orderId": order_id,
        "isCross": is_cross
    }
    msg_type = 'order' if custom_payload else 'text'
    payload = custom_payload if custom_payload else message_text

    body = {
        "appkey": appkey,
        "senderId": sender_id,
        "senderData": {"avatar": sender_avatar, "name": sender_name},
        "to": {"type": "group", "id": group_id, "data": to_data},
        "type": msg_type,
        "payload": payload
    }
    headers = {"Content-Type": "application/json"}
    if secret:
        headers["Authorization"] = f"Bearer {secret}"

    for attempt in range(3):  # 最多重试3次
        try:
            r = requests.post(url, headers=headers, json=body, timeout=10)
            if r.status_code == 200:
                logger.info(f"消息发送成功：sender={sender_id}, group={group_id}, type={msg_type}")
                return True
            logger.warning(f"消息发送失败 (尝试 {attempt+1}/3)：状态码 {r.status_code}, 响应 {r.text}")
        except Exception as e:
            logger.warning(f"消息发送异常 (尝试 {attempt+1}/3)：{e}")
        if attempt < 2:
            time.sleep(1)
    logger.error(f"消息最终发送失败：sender={sender_id}, group={group_id}")
    return False


# ----------------- 权限校验 -----------------
def check_user_permission(identity_type, uid, order):
    """验证用户身份、账号状态、以及是否属于该订单"""
    try:
        user = UserMain.objects.get(yonghuid=uid)
    except UserMain.DoesNotExist:
        return False, '用户不存在'

    if identity_type == 'dashou':
        try:
            dashou = UserDashou.objects.get(user=user)
            if dashou.zhanghaozhuangtai != 1 :
                return False, '打手账号已被封禁或状态异常'
        except UserDashou.DoesNotExist:
            return False, '该用户不是打手'
        if order.jiedan_dashou_id != uid:
            return False, '你不是该订单的接单打手'

    elif identity_type == 'shangjia':
        try:
            shop = UserShangjia.objects.get(user=user)
            if shop.zhuangtai != 1:
                return False, '商家账号已被禁用'
        except UserShangjia.DoesNotExist:
            return False, '该用户不是商家'
        try:
            if order.shangjia_kuozhan.shangjia_id != uid:
                return False, '你不是该订单的发布商家'
        except DingdanShangjia.DoesNotExist:
            return False, '订单缺少商家信息'

    elif identity_type == 'boss':
        try:
            UserBoss.objects.get(user=user)  # 老板暂无封禁字段，仅需存在
        except UserBoss.DoesNotExist:
            return False, '该用户不是老板'
        try:
            if order.pingtai_kuozhan.laoban_id != uid:
                return False, '你不是该订单的老板'
        except DingdanPingtai.DoesNotExist:
            return False, '订单缺少平台信息'

    else:
        return False, '不支持的身份类型'
    return True, ''


# ----------------- 跨平台对方配置获取 -----------------
def get_partner_club_config(partner_club_id):
    try:
        return ClubConfig.objects.get(club_id=partner_club_id, is_self=0)
    except ClubConfig.DoesNotExist:
        return None


# ----------------- 主视图 -----------------


class DaiLiQunLiaoXiaoXiView(APIView):
    """
    代理发送群聊消息
    支持：
    - 非跨平台订单：直接用我方 GoEasy Key 以真实身份发送
    - 跨平台订单（双方任意一方派单）：除了我方群外，还需用对方 GoEasy Key 以代理身份向对方群发送
    跨平台判断条件：订单同时存在 partner_order_id 和 partner_club_id 即视为跨平台
    """
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        # ===== 1. 参数解析 =====
        order_id = request.data.get('orderId')
        identity_type = request.data.get('identityType')  # dashou / shangjia / boss
        sender_name = request.data.get('senderName', '')
        sender_avatar_raw = request.data.get('senderAvatar', '')
        message_type = request.data.get('messageType', 'text')
        message_text = request.data.get('text', '')
        order_payload = request.data.get('orderPayload', None)

        logger.info(f"[群聊代理] 收到请求: orderId={order_id}, identityType={identity_type}, "
                    f"messageType={message_type}, text={message_text[:20]}...")

        if not order_id or not identity_type:
            return Response({'code': 400, 'msg': '缺少 orderId 或 identityType'})
        if identity_type not in ('dashou', 'shangjia', 'boss'):
            return Response({'code': 400, 'msg': 'identityType 无效'})

        # ===== 2. 构造 senderId =====
        uid = request.user.yonghuid
        prefix_map = {'dashou': 'Ds', 'shangjia': 'Sj', 'boss': 'Boss'}
        sender_id = prefix_map[identity_type] + uid
        logger.info(f"[群聊代理] 登录用户 yonghuid={uid}, 构造 senderId={sender_id}")

        # ===== 3. 查询订单 =====
        try:
            order = Dingdan.objects.select_related('pingtai_kuozhan', 'shangjia_kuozhan').get(dingdan_id=order_id)
        except Dingdan.DoesNotExist:
            logger.warning(f"[群聊代理] 订单 {order_id} 不存在")
            return Response({'code': 404, 'msg': '订单不存在'})

        # ===== 4. 权限校验 =====
        valid, err_msg = check_user_permission(identity_type, uid, order)
        if not valid:
            logger.warning(f"[群聊代理] 权限校验失败: {err_msg}, uid={uid}, identity={identity_type}")
            return Response({'code': 403, 'msg': err_msg})

        # ===== 5. 我方 GoEasy 配置 =====
        self_appkey = get_self_goeasy_appkey()
        self_secret = get_self_goeasy_secret()
        if not self_appkey:
            logger.error("[群聊代理] 我方 GoEasy AppKey 未配置")
            return Response({'code': 500, 'msg': '系统配置错误(APPKEY)'})

        # ===== 6. 公共群信息 =====
        real_group_id = f"group_{order.dingdan_id}"
        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('')

        # ===== 7. 订阅发送者到群 =====
        if not subscribe_users_to_group([sender_id], [real_group_id], self_appkey, self_secret):
            logger.error("[群聊代理] 订阅群组失败")
            return Response({'code': 500, 'msg': '订阅群组失败'})

        # ===== 8. 判断跨平台（只看对方订单ID和俱乐部ID） =====
        partner_order_id = order.partner_order_id
        partner_club_id = order.partner_club_id
        is_cross = 1 if (partner_order_id and partner_club_id) else 0
        logger.info(f"[群聊代理] 订单 {order_id} partner_order_id={partner_order_id}, partner_club_id={partner_club_id}, 判定跨平台={is_cross}")

        custom_payload = order_payload if message_type == 'order' else None
        text_content = message_text

        # ---------- 先向我方群发送消息（永远执行） ----------
        local_ok = send_group_message(
            appkey=self_appkey,
            secret=self_secret,
            group_id=real_group_id,
            sender_id=sender_id,
            sender_name=sender_name,
            sender_avatar=sender_avatar,
            message_text=text_content,
            custom_payload=custom_payload,
            group_name=group_name,
            order_id=order.dingdan_id,
            is_cross=is_cross
        )
        if not local_ok:
            return Response({'code': 500, 'msg': '消息发送失败'})

        # ---------- 跨平台转发（如果有对方订单ID和俱乐部ID） ----------
        if is_cross:
            logger.info("[群聊代理] 满足跨平台条件，准备双平台发送")
            partner_cfg = get_partner_club_config(partner_club_id)
            if not partner_cfg or not partner_cfg.chat_api_key:
                logger.warning("[群聊代理] 对方俱乐部配置不可用，仅发送我方群")
                return Response({'code': 200, 'msg': '发送成功（对方GoEasy未配置）'})

            partner_appkey = partner_cfg.chat_api_key
            partner_secret = partner_cfg.chat_api_id or ''
            partner_group_id = f"group_{partner_order_id}"

            # 构造代理身份
            agent_sender_id = f"{order.dingdan_id}_{sender_id}"
            if identity_type == 'dashou':
                agent_sender_name = f"[我方]{sender_name}"
            elif identity_type == 'shangjia':
                agent_sender_name = f"[我方商家]{sender_name}"
            else:
                agent_sender_name = f"[我方老板]{sender_name}"
            agent_avatar = full_avatar('')

            logger.info(f"[群聊代理] 对方群组={partner_group_id}, 代理身份={agent_sender_id}/{agent_sender_name}")

            # 向对方群发送代理消息
            partner_ok = send_group_message(
                appkey=partner_appkey,
                secret=partner_secret,
                group_id=partner_group_id,
                sender_id=agent_sender_id,
                sender_name=agent_sender_name,
                sender_avatar=agent_avatar,
                message_text=text_content,
                custom_payload=custom_payload,
                group_name='跨平台订单交流',
                order_id=partner_order_id,
                is_cross=1
            )
            logger.info(f"[群聊代理] 对方群发送结果: {partner_ok}")

            if partner_ok:
                return Response({'code': 200, 'msg': '发送成功（双平台）'})
            else:
                return Response({'code': 200, 'msg': '我方发送成功，对方发送失败'})
        else:
            logger.info("[群聊代理] 非跨平台，仅发送我方群")
            return Response({'code': 200, 'msg': '发送成功'})


'''class DaiLiQunLiaoXiaoXiView(APIView):
    """
    代理发送群聊消息
    支持：
    - 非跨平台订单：直接用我方 GoEasy Key 以真实身份发送
    - 跨平台订单（我方派单）：同上
    - 跨平台订单（对方派单）：除了我方群外，还需用对方 GoEasy Key 以代理身份向对方群发送
    """
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        # ===== 1. 参数解析 =====
        order_id = request.data.get('orderId')
        identity_type = request.data.get('identityType')  # 前端必传：dashou / shangjia / boss
        sender_name = request.data.get('senderName', '')
        sender_avatar_raw = request.data.get('senderAvatar', '')
        message_type = request.data.get('messageType', 'text')
        message_text = request.data.get('text', '')
        order_payload = request.data.get('orderPayload', None)

        logger.info(f"[群聊代理] 收到请求: orderId={order_id}, identityType={identity_type}, "
                    f"messageType={message_type}, text={message_text[:20]}...")

        if not order_id or not identity_type:
            return Response({'code': 400, 'msg': '缺少 orderId 或 identityType'})
        if identity_type not in ('dashou', 'shangjia', 'boss'):
            return Response({'code': 400, 'msg': 'identityType 无效'})

        # ===== 2. 构造 senderId =====
        uid = request.user.yonghuid
        prefix_map = {'dashou': 'Ds', 'shangjia': 'Sj', 'boss': 'Boss'}
        sender_id = prefix_map[identity_type] + uid
        logger.info(f"[群聊代理] 登录用户 yonghuid={uid}, 构造 senderId={sender_id}")

        # ===== 3. 查询订单 =====
        try:
            order = Dingdan.objects.select_related('pingtai_kuozhan', 'shangjia_kuozhan').get(dingdan_id=order_id)
        except Dingdan.DoesNotExist:
            logger.warning(f"[群聊代理] 订单 {order_id} 不存在")
            return Response({'code': 404, 'msg': '订单不存在'})

        # ===== 4. 权限校验 =====
        valid, err_msg = check_user_permission(identity_type, uid, order)
        if not valid:
            logger.warning(f"[群聊代理] 权限校验失败: {err_msg}, uid={uid}, identity={identity_type}")
            return Response({'code': 403, 'msg': err_msg})

        # ===== 5. 我方 GoEasy 配置 =====
        self_appkey = get_self_goeasy_appkey()
        self_secret = get_self_goeasy_secret()
        if not self_appkey:
            logger.error("[群聊代理] 我方 GoEasy AppKey 未配置")
            return Response({'code': 500, 'msg': '系统配置错误(APPKEY)'})

        # ===== 6. 公共群信息 =====
        real_group_id = f"group_{order.dingdan_id}"
        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('')

        # ===== 7. 订阅发送者到群（确保在群内） =====
        if not subscribe_users_to_group([sender_id], [real_group_id], self_appkey, self_secret):
            logger.error("[群聊代理] 订阅群组失败")
            return Response({'code': 500, 'msg': '订阅群组失败'})

        # ===== 8. 判断跨平台状态 =====
        is_cross = order.is_cross
        dispatch_type = order.dispatch_type  # 1=我方派单, 2=对方派单
        logger.info(f"[群聊代理] 订单 {order_id} is_cross={is_cross}, dispatch_type={dispatch_type}")

        custom_payload = order_payload if message_type == 'order' else None
        text_content = message_text

        # ---------- 非跨平台 或 我方派单 ----------
        if is_cross != 1 or dispatch_type == 1:
            logger.info("[群聊代理] 走非跨平台/我方派单发送通道")
            success = send_group_message(
                appkey=self_appkey,
                secret=self_secret,
                group_id=real_group_id,
                sender_id=sender_id,
                sender_name=sender_name,
                sender_avatar=sender_avatar,
                message_text=text_content,
                custom_payload=custom_payload,
                group_name=group_name,
                order_id=order.dingdan_id,
                is_cross=1 if is_cross == 1 else 0
            )
            if success:
                return Response({'code': 200, 'msg': '发送成功'})
            else:
                return Response({'code': 500, 'msg': '消息发送失败'})

        # ---------- 跨平台且对方派单 ----------
        logger.info("[群聊代理] 检测到跨平台对方派单，准备双平台发送")
        partner_club_id = order.partner_club_id
        partner_order_id = order.partner_order_id

        if not partner_club_id or not partner_order_id:
            logger.warning("[群聊代理] 缺少 partner_club_id 或 partner_order_id，降级为本地发送")
            success = send_group_message(
                self_appkey, self_secret, real_group_id, sender_id, sender_name,
                sender_avatar, text_content, custom_payload, group_name, order.dingdan_id, is_cross=1
            )
            return Response({'code': 200, 'msg': '发送成功（对方信息缺失）'} if success else ('发送失败', 500))

        partner_cfg = get_partner_club_config(partner_club_id)
        if not partner_cfg or not partner_cfg.chat_api_key:
            logger.warning("[群聊代理] 对方俱乐部配置不可用，仅发送我方群")
            success = send_group_message(
                self_appkey, self_secret, real_group_id, sender_id, sender_name,
                sender_avatar, text_content, custom_payload, group_name, order.dingdan_id, is_cross=1
            )
            return Response({'code': 200, 'msg': '发送成功（对方GoEasy未配置）'} if success else ('发送失败', 500))

        partner_appkey = partner_cfg.chat_api_key
        partner_secret = partner_cfg.chat_api_id or ''
        partner_group_id = f"group_{partner_order_id}"

        # 构造代理身份（参考 chat_utils.py）
        agent_sender_id = f"{order.dingdan_id}_{sender_id}"
        if identity_type == 'dashou':
            agent_sender_name = f"[我方]{sender_name}"
        elif identity_type == 'shangjia':
            agent_sender_name = f"[我方商家]{sender_name}"
        else:
            agent_sender_name = f"[我方老板]{sender_name}"
        agent_avatar = full_avatar('')  # 可定制

        logger.info(f"[群聊代理] 对方群组={partner_group_id}, 代理身份={agent_sender_id}/{agent_sender_name}")

        # 1) 在我方群发送真实身份消息
        local_ok = send_group_message(
            self_appkey, self_secret, real_group_id, sender_id, sender_name,
            sender_avatar, text_content, custom_payload, group_name, order.dingdan_id, is_cross=1
        )
        logger.info(f"[群聊代理] 我方群发送结果: {local_ok}")

        # 2) 在对方群发送代理身份消息
        partner_ok = send_group_message(
            partner_appkey, partner_secret, partner_group_id,
            agent_sender_id, agent_sender_name, agent_avatar,
            text_content, custom_payload,
            '跨平台订单交流', partner_order_id, is_cross=1
        )
        logger.info(f"[群聊代理] 对方群发送结果: {partner_ok}")

        if local_ok and partner_ok:
            return Response({'code': 200, 'msg': '发送成功（双平台）'})
        elif local_ok:
            return Response({'code': 200, 'msg': '我方发送成功，对方发送失败'})
        else:
            return Response({'code': 500, 'msg': '消息发送失败'})'''




'''class DashouDingdanHuoquView1(APIView):
    """打手订单获取接口"""
    permission_classes = [IsAuthenticated]  # JWT认证

    def post(self, request):
        # 1. 获取当前登录用户的yonghuid
        try:
            current_user = request.user
            yonghuid = current_user.yonghuid

        except AttributeError:
            return Response({
                'code': 1,
                'msg': '用户认证失败',
                'data': None
            }, status=status.HTTP_401_UNAUTHORIZED)

        # 2. 获取和验证前端参数
        try:
            data = request.data
            zhuangtai_list = data.get('zhuangtai_list', [])
            page = max(1, int(data.get('page', 1)))
            page_size = min(100, max(1, int(data.get('page_size', 10))))



        except (ValueError, TypeError):
            return Response({
                'code': 2,
                'msg': '参数格式错误',
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)

        # 3. 验证状态列表参数
        if not isinstance(zhuangtai_list, list) or len(zhuangtai_list) == 0:
            return Response({
                'code': 3,
                'msg': '状态列表不能为空',
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)

        try:
            # 4. 构建查询条件 - 直接查询订单主表
            # 条件1: 当前打手是接单打手
            # 条件2: 订单状态在指定列表中

            # 注意：打手看不到状态1和7的订单（已下单、指定中）
            # 但这里由前端控制传递的zhuangtai_list决定
            dashou_query = Q(jiedan_dashou_id=yonghuid)
            zhuangtai_query = Q(zhuangtai__in=zhuangtai_list)

            # 5. 执行查询 - 只查询需要的字段，按创建时间倒序
            dingdan_query = Dingdan.objects.filter(
                dashou_query & zhuangtai_query
            ).order_by('-create_time')

            # 只选择需要的字段，提高性能
            dingdan_query = dingdan_query.only(
                'dingdan_id',
                'zhuangtai',
                'dashou_fencheng',  # ✅ 关键：打手分成，不是jine
                'jieshao',
                'tupian',
                'nicheng',
                'create_time'
            )

            total_count = dingdan_query.count()


            # 6. 计算分页
            start_index = (page - 1) * page_size
            end_index = start_index + page_size

            # 获取当前页的订单数据
            current_page_orders = dingdan_query[start_index:end_index]
            current_page_count = len(current_page_orders)

            # 7. 构建返回数据 - 只返回前端需要的字段
            order_list = []
            for order in current_page_orders:
                order_data = {
                    # 核心字段 - 必须与前端完全对应
                    'dingdan_id': order.dingdan_id,  # 订单ID
                    'zhuangtai': order.zhuangtai,  # 订单状态码
                    # ✅ 关键：这里返回的是打手分成，不是订单金额
                    'jine': float(order.dashou_fencheng) if order.dashou_fencheng else 0.0,
                    'jieshao': order.jieshao or '',  # 订单介绍
                    'tupian': order.tupian or '',  # 商品图片URL
                    'nicheng': order.nicheng or '',  # 游戏昵称
                    'create_time': order.create_time.strftime('%Y-%m-%d %H:%M:%S') if order.create_time else ''
                }
                order_list.append(order_data)



            # 8. 判断是否还有更多数据
            # 条件1: 当前页获取了满page_size条数据
            # 条件2: 还有更多数据没取完
            has_more = current_page_count == page_size and end_index < total_count

            # 如果总数为0，直接没有更多
            if total_count == 0:
                has_more = False



            return Response({
                'code': 0,
                'msg': '成功',
                'data': {
                    'list': order_list,  # 订单列表
                    'has_more': has_more,  # 是否还有更多数据
                    'total': total_count  # 总订单数（可选）
                }
            }, status=status.HTTP_200_OK)

        except Exception as e:
            # 记录异常日志
            import logging
            logger = logging.getLogger(__name__)
            logger.error(f"打手订单获取失败: {str(e)}", exc_info=True)



            return Response({
                'code': 4,
                'msg': '服务器内部错误',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)'''





class DashouDingdanHuoquView1(APIView):
    """
    打手订单获取接口
    支持筛选条件：
    - zhuangtai_list: 订单状态列表（可选，空数组或不传表示全部状态）
    - leixing_id: 商品类型ID（可选）
    - keyword: 搜索关键词，模糊匹配订单ID和订单介绍（可选）
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        # 1. 获取当前登录用户的 yonghuid
        try:
            current_user = request.user
            yonghuid = current_user.yonghuid
        except AttributeError:
            return Response({
                'code': 1,
                'msg': '用户认证失败',
                'data': None
            }, status=status.HTTP_401_UNAUTHORIZED)

        # 2. 获取并校验前端参数
        try:
            data = request.data
            zhuangtai_list = data.get('zhuangtai_list', [])   # 可选，默认空列表（全部）
            page = max(1, int(data.get('page', 1)))
            page_size = min(100, max(1, int(data.get('page_size', 10))))
            leixing_id = data.get('leixing_id', None)          # 可选，商品类型ID
            keyword = data.get('keyword', '').strip()          # 可选，搜索关键词
        except (ValueError, TypeError):
            return Response({
                'code': 2,
                'msg': '参数格式错误',
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)

        # 3. 参数默认值与类型修正
        if not isinstance(zhuangtai_list, list):
            zhuangtai_list = []   # 非列表则视为全部
        if leixing_id is not None:
            try:
                leixing_id = int(leixing_id)
            except (ValueError, TypeError):
                leixing_id = None

        # 4. 构建查询条件
        try:
            # 基础条件：当前打手接单
            query = Q(jiedan_dashou_id=yonghuid)

            # 状态筛选：如果 zhuangtai_list 不为空列表，则加入筛选；否则查询全部状态
            if zhuangtai_list:
                query &= Q(zhuangtai__in=zhuangtai_list)

            # 商品类型筛选
            if leixing_id is not None:
                query &= Q(leixing_id=leixing_id)

            # 关键词搜索：模糊匹配订单ID和订单介绍
            if keyword:
                keyword_query = Q(dingdan_id__icontains=keyword) | Q(jieshao__icontains=keyword)
                query &= keyword_query

            # 5. 执行查询，按创建时间倒序
            dingdan_query = Dingdan.objects.filter(query).order_by('-create_time')

            # 只选择需要的字段，提高性能
            dingdan_query = dingdan_query.only(
                'dingdan_id',
                'zhuangtai',
                'dashou_fencheng',   # 打手分成金额
                'jieshao',
                'tupian',
                'nicheng',
                'create_time'
            )

            total_count = dingdan_query.count()

            # 6. 分页处理
            start_index = (page - 1) * page_size
            end_index = start_index + page_size
            current_page_orders = dingdan_query[start_index:end_index]
            current_page_count = len(current_page_orders)

            # 7. 构建返回数据列表
            order_list = []
            for order in current_page_orders:
                order_data = {
                    'dingdan_id': order.dingdan_id,
                    'zhuangtai': order.zhuangtai,
                    'jine': float(order.dashou_fencheng) if order.dashou_fencheng else 0.0,
                    'jieshao': order.jieshao or '',
                    'tupian': order.tupian or '',
                    'nicheng': order.nicheng or '',
                    'create_time': order.create_time.strftime('%Y-%m-%d %H:%M:%S') if order.create_time else ''
                }
                order_list.append(order_data)

            # 8. 判断是否还有更多数据
            has_more = (current_page_count == page_size) and (end_index < total_count)
            if total_count == 0:
                has_more = False

            return Response({
                'code': 0,
                'msg': '成功',
                'data': {
                    'list': order_list,
                    'has_more': has_more,
                    'total': total_count
                }
            }, status=status.HTTP_200_OK)

        except Exception as e:
            import logging
            logger = logging.getLogger(__name__)
            logger.error(f"打手订单获取失败: {str(e)}", exc_info=True)

            return Response({
                'code': 4,
                'msg': '服务器内部错误',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)







from peizhi.models import ClubConfig, ShangjiaLianjie
logger = logging.getLogger('dingdan')

# ---------- 跨平台对方配置获取 ----------
def get_partner_club_config(partner_club_id):
    try:
        return ClubConfig.objects.get(club_id=partner_club_id, is_self=0)
    except ClubConfig.DoesNotExist:
        return None


class ShangjiaLianjieLiuYanZhuanFaView(APIView):
    """
    商家链接留言转发接口
    路径：POST /dingdan/sjljlbxxzf
    固定以 B{商家ID} 身份发送群消息。通过 partner_order_id/partner_club_id 判断是否跨平台。
    """
    permission_classes = []

    def post(self, request):
        token = request.data.get('token')
        text = request.data.get('text', '')

        if not token or not text:
            return Response({'code': 400, 'msg': '缺少参数'})

        try:
            lianjie = ShangjiaLianjie.objects.get(lianjie_token=token)
        except ShangjiaLianjie.DoesNotExist:
            return Response({'code': 404, 'msg': '链接不存在或已失效'})

        if not lianjie.dingdan_id:
            return Response({'code': 400, 'msg': '链接缺少订单ID'})

        try:
            order = Dingdan.objects.select_related('pingtai_kuozhan', 'shangjia_kuozhan').get(dingdan_id=lianjie.dingdan_id)
        except Dingdan.DoesNotExist:
            return Response({'code': 500, 'msg': '订单数据异常'})

        shangjia_uid = lianjie.yonghu_id
        sender_id = f"B{shangjia_uid}"
        sender_name = "老板"
        sender_avatar = ''

        appkey = get_self_goeasy_appkey()
        secret = get_self_goeasy_secret()
        if not appkey:
            return Response({'code': 500, 'msg': '系统配置错误(APPKEY)'})

        group_id = f"group_{order.dingdan_id}"
        group_name = (order.jieshao[:20] + '…') if order.jieshao and len(order.jieshao) > 20 else f"订单{order.dingdan_id}"

        local_cross_flag = 1 if (order.partner_order_id and order.partner_club_id) else 0

        if not _subscribe_users_to_group([sender_id], [group_id], appkey, secret):
            return Response({'code': 500, 'msg': '订阅群组失败'})

        local_ok = _send_group_message(
            appkey=appkey,
            secret=secret,
            group_id=group_id,
            sender_id=sender_id,
            sender_name=sender_name,
            sender_avatar=sender_avatar,
            message_text=text,
            custom_payload=None,
            group_name=group_name,
            order_id=order.dingdan_id,
            is_cross=local_cross_flag
        )
        if not local_ok:
            return Response({'code': 500, 'msg': '消息发送失败'})

        # 跨平台转发
        partner_order_id = order.partner_order_id
        partner_club_id = order.partner_club_id

        if not partner_order_id or not partner_club_id:
            return Response({'code': 200, 'msg': '发送成功'})

        partner_cfg = get_partner_club_config(partner_club_id)
        if not partner_cfg or not partner_cfg.chat_api_key:
            return Response({'code': 200, 'msg': '发送成功（对方未配置）'})

        agent_sender_id = f"{order.dingdan_id}_{sender_id}"
        agent_sender_name = f"[我方老板]{shangjia_uid}"

        partner_group_id = f"group_{partner_order_id}"

        partner_ok = _send_group_message(
            appkey=partner_cfg.chat_api_key,
            secret=partner_cfg.chat_api_id or '',
            group_id=partner_group_id,
            sender_id=agent_sender_id,
            sender_name=agent_sender_name,
            sender_avatar='',
            message_text=text,
            custom_payload=None,
            group_name='跨平台订单交流',
            order_id=partner_order_id,
            is_cross=1
        )

        if partner_ok:
            return Response({'code': 200, 'msg': '发送成功（双平台）'})
        else:
            return Response({'code': 200, 'msg': '我方发送成功，对方发送失败'})



# views.py - 打手COS凭证接口（完整替换）
import json
import time
from tencentcloud.common import credential
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
from tencentcloud.sts.v20180813 import sts_client, models
from django.conf import settings
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework import status
import logging

logger = logging.getLogger(__name__)

class DashouCOSZhengshuView(APIView):
    """打手获取COS上传凭证接口（调试版本）"""
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # 1. 接收参数（修复 int 无 strip 问题）
            dingdan_id = str(request.data.get('dingdan_id', '')).strip()
            yongtu = request.data.get('yongtu', 'dingdan')

            # 2. 条件判断修正：除了 fakuan 之外，其他用途均需提供 dingdan_id
            if yongtu != 'fakuan' and not dingdan_id:
                return Response(
                    {'code': 400, 'msg': '订单ID不能为空', 'error': 'dingdan_id is required when yongtu is not fakuan'},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 3. 业务验证逻辑（根据用途分别验证）
            if yongtu == 'chufa':
                try:
                    from .models import Chufajilu
                    chufa_record = Chufajilu.objects.filter(
                        dingdan_id=dingdan_id,
                        dashouid=request.user.yonghuid,
                        sqzhuangtai__in=[0, 3]
                    ).first()
                    if not chufa_record:
                        return Response(
                            {'code': 403, 'msg': '处罚记录无权限或状态不对',
                             'error': f'No punishment record found for user {request.user.yonghuid} on order {dingdan_id}'},
                            status=status.HTTP_403_FORBIDDEN
                        )
                except Exception as e:
                    logger.error(f"查处罚记录异常: {str(e)}")
                    return Response(
                        {'code': 500, 'msg': '服务器内部错误', 'error': str(e)},
                        status=status.HTTP_500_INTERNAL_SERVER_ERROR
                    )
            elif yongtu == 'fakuan':
                # 罚款申诉不需要订单验证
                pass
            else:
                # 默认为订单相关，需要验证订单且打手必须接单
                try:
                    from .models import Dingdan
                    dingdan = Dingdan.objects.get(
                        dingdan_id=dingdan_id,
                        jiedan_dashou_id=request.user.yonghuid,
                        zhuangtai__in=[2, 8]
                    )
                except Dingdan.DoesNotExist:
                    return Response(
                        {'code': 403, 'msg': '此功能暂未开放', 'error': f'Order {dingdan_id} not found or not assigned to user {request.user.yonghuid}'},
                        status=status.HTTP_403_FORBIDDEN
                    )

            # 4. 获取腾讯云STS临时密钥
            try:
                # 初始化固定凭证
                cred = credential.Credential(
                    settings.COS_SECRET_ID,
                    settings.COS_SECRET_KEY
                )

                # 创建STS客户端
                http_profile = HttpProfile()
                http_profile.endpoint = "sts.tencentcloudapi.com"
                client_profile = ClientProfile()
                client_profile.httpProfile = http_profile
                client = sts_client.StsClient(cred, "ap-shanghai", client_profile)

                # 构建策略资源
                resources = []
                if yongtu == 'chufa':
                    resources.append(
                        f"qcs::cos:{settings.COS_REGION}:uid/{settings.COS_APPID}:{settings.COS_BUCKET}/a_long/chfajltp/dssstp/*"
                    )
                elif yongtu == 'fakuan':
                    resources.append(
                        f"qcs::cos:{settings.COS_REGION}:uid/{settings.COS_APPID}:{settings.COS_BUCKET}/fakuan/dashoufakuan/dashoufakuanshensu/*"
                    )
                else:
                    resources.append(
                        f"qcs::cos:{settings.COS_REGION}:uid/{settings.COS_APPID}:{settings.COS_BUCKET}/order/{dingdan_id}/*"
                    )

                policy = {
                    "version": "2.0",
                    "statement": [{
                        "effect": "allow",
                        "action": [
                            "cos:PutObject",
                            "cos:PostObject",
                            "cos:InitiateMultipartUpload",
                            "cos:UploadPart",
                            "cos:CompleteMultipartUpload"
                        ],
                        "resource": resources
                    }]
                }

                req = models.GetFederationTokenRequest()
                req.Name = f"dashou_{dingdan_id}_{int(time.time())}"
                req.Policy = json.dumps(policy)
                req.DurationSeconds = 7200

                resp = client.GetFederationToken(req)
                credentials = resp.Credentials

            except TencentCloudSDKException as e:
                logger.error(f"获取STS临时密钥失败: {str(e)}")
                return Response({
                    'code': 500,
                    'msg': f'获取上传凭证失败: {str(e)}',
                    'error_detail': str(e)
                }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

            # 5. 构建响应
            current_time = int(time.time())
            upload_dir = 'fakuan/dashoufakuan/dashoufakuanshensu/' if yongtu == 'fakuan' else (
                'a_long/chfajltp/dssstp/' if yongtu == 'chufa' else f'order/{dingdan_id}/'
            )
            response_data = {
                'credentials': {
                    'tmpSecretId': credentials.TmpSecretId,
                    'tmpSecretKey': credentials.TmpSecretKey,
                    'sessionToken': credentials.Token,
                },
                'startTime': current_time,
                'expiredTime': current_time + 7200,
                'bucket': settings.COS_BUCKET,
                'region': settings.COS_REGION,
                'upload_dir': upload_dir,
            }
            return Response({'code': 0, 'msg': '成功', 'data': response_data})

        except Exception as e:
            # 捕捉所有未预期的异常，返回完整 traceback
            logger.error(f'COS凭证接口未知错误: {traceback.format_exc()}')
            return Response({
                'code': 500,
                'msg': f'服务器内部错误: {str(e)}',
                'error_detail': traceback.format_exc()
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class ShangjiaCOSZhengshuView(APIView):
    """商家获取COS上传凭证接口（用于处罚申诉图片上传）"""
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # 1. 接收参数
            dingdan_id = request.data.get('dingdan_id', '').strip()
            yongtu = request.data.get('yongtu', 'chufa')  # 用途：chufa=处罚申诉

            if not dingdan_id:
                return Response({'code': 1, 'msg': '订单ID不能为空', 'data': None},
                                status=status.HTTP_400_BAD_REQUEST)

            # 2. 🔴【修改】验证商家身份 - 通过反向查询shop_profile判断是否为商家
            try:
                # 检查是否有商家扩展表
                shangjia_profile = request.user.shop_profile

                # 验证商家状态是否为1（正常）
                if shangjia_profile.zhuangtai != 1:
                    return Response({'code': 3, 'msg': '商家账号状态异常，无法操作', 'data': None},
                                    status=status.HTTP_403_FORBIDDEN)

                # 🔴【重要】获取商家ID（从商家扩展表中获取）
                shangjia_id = request.user.yonghuid  # 假设商家扩展表中有yonghuid字段

            except AttributeError:
                # 没有shop_profile属性，说明不是商家
                return Response({'code': 3, 'msg': '非商家用户无权限', 'data': None},
                                status=status.HTTP_403_FORBIDDEN)

            # 3. 🔴【修改】验证订单权限 - 通过商家订单扩展表验证
            try:
                from .models import Dingdan, DingdanShangjia

                # 获取订单
                dingdan = Dingdan.objects.get(dingdan_id=dingdan_id)

                # 🔴【重要】通过反向查询商家扩展表验证订单是否属于当前商家
                try:
                    shangjia_kuozhan = dingdan.shangjia_kuozhan  # 使用反向关系名

                    # 验证商家ID是否匹配
                    if str(shangjia_kuozhan.shangjia_id) != str(shangjia_id):
                        return Response({'code': 2, 'msg': '订单不属于当前商家', 'data': None},
                                        status=status.HTTP_403_FORBIDDEN)

                    # 验证订单状态是否允许申请处罚（根据前端逻辑）
                    allowed_zhuangtai = [2, 4, 5, 6, 8]
                    if dingdan.zhuangtai not in allowed_zhuangtai:
                        return Response({'code': 4, 'msg': '当前订单状态不允许申请处罚', 'data': None},
                                        status=status.HTTP_400_BAD_REQUEST)

                    # 🔴【新增】检查是否已存在处罚申请（通过Chufajilu模型）
                    # 注意：这里假设Chufajilu模型存在，并且有shangjia_id字段
                    try:
                        from .models import Chufajilu
                        existing_chufa = Chufajilu.objects.filter(
                            dingdan_id=dingdan_id,
                            qingqiuid=shangjia_id,
                            sqzhuangtai__in=[0, 1]  # 审核中或已处罚状态
                        ).exists()

                        if existing_chufa:
                            return Response({'code': 5, 'msg': '该订单已有处罚申请，请勿重复上传', 'data': None},
                                            status=status.HTTP_400_BAD_REQUEST)
                    except ImportError:
                        # 如果没有Chufajilu模型，跳过这个检查
                        pass

                except DingdanShangjia.DoesNotExist:
                    # 没有商家扩展记录，说明这不是商家订单
                    return Response({'code': 2, 'msg': '非商家订单无法操作', 'data': None},
                                    status=status.HTTP_403_FORBIDDEN)

            except Dingdan.DoesNotExist:
                return Response({'code': 2, 'msg': '订单不存在', 'data': None},
                                status=status.HTTP_404_NOT_FOUND)
            except Exception as e:
                logger.error(f"订单验证异常: {str(e)}")
                return Response({'code': 500, 'msg': '服务器验证异常', 'data': None},
                                status=status.HTTP_500_INTERNAL_SERVER_ERROR)

            # 4. 获取腾讯云STS临时密钥
            try:
                # 初始化固定凭证
                cred = credential.Credential(
                    settings.COS_SECRET_ID,
                    settings.COS_SECRET_KEY
                )

                # 创建STS客户端
                http_profile = HttpProfile()
                http_profile.endpoint = "sts.tencentcloudapi.com"
                client_profile = ClientProfile()
                client_profile.httpProfile = http_profile

                client = sts_client.StsClient(cred, "ap-shanghai", client_profile)

                # 🔴【修改】构建策略 - 只允许上传到商家处罚证据图片目录
                resources = [
                    f"qcs::cos:{settings.COS_REGION}:uid/{settings.COS_APPID}:{settings.COS_BUCKET}/a_long/chfajltp/sjzjtp/*"
                ]

                policy = {
                    "version": "2.0",
                    "statement": [
                        {
                            "effect": "allow",
                            "action": [
                                "cos:PutObject",
                                "cos:PostObject",
                                "cos:InitiateMultipartUpload",
                                "cos:UploadPart",
                                "cos:CompleteMultipartUpload"
                            ],
                            "resource": resources
                        }
                    ]
                }

                # 请求STS临时凭证
                req = models.GetFederationTokenRequest()
                # 🔴【修改】命名包含商家ID
                req.Name = f"shangjia_{shangjia_id}_{dingdan_id}_{int(time.time())}"
                req.Policy = json.dumps(policy)
                req.DurationSeconds = 7200  # 2小时有效期

                resp = client.GetFederationToken(req)

                # 提取临时密钥
                credentials = resp.Credentials

            except TencentCloudSDKException as e:
                logger.error(f"商家获取STS临时密钥失败: {str(e)}")
                return Response({
                    'code': 500,
                    'msg': f'获取上传凭证失败: {str(e)}',
                    'data': None
                }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

            # 5. 构建响应数据
            current_time = int(time.time())
            response_data = {
                'credentials': {
                    'tmpSecretId': credentials.TmpSecretId,
                    'tmpSecretKey': credentials.TmpSecretKey,
                    'sessionToken': credentials.Token,
                },
                'startTime': current_time,
                'expiredTime': current_time + 7200,
                'bucket': settings.COS_BUCKET,
                'region': settings.COS_REGION,
                # 🔴【修改】商家专用上传目录
                'upload_dir': 'a_long/chfajltp/sjzjtp/',
                # 🔴【新增】返回商家ID和订单ID，便于前端生成文件名
                'dingdan_id': dingdan_id,
                'shangjia_id': shangjia_id,
                # 🔴【新增】可选：返回商家昵称，便于前端显示
                'shangjia_nicheng': shangjia_profile.nicheng if hasattr(shangjia_profile, 'nicheng') else ''
            }

            # 6. 返回成功
            return Response({
                'code': 0,
                'msg': '成功',
                'data': response_data
            }, status=status.HTTP_200_OK)

        except Exception as e:
            logger.error(f'商家COS凭证接口未知错误: {str(e)}', exc_info=True)
            return Response({
                'code': 500,
                'msg': f'服务器内部错误: {str(e)}',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

'''class DashouCOSZhengshuView(APIView):
    """打手获取COS上传凭证接口（使用腾讯云STS临时密钥）"""
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:


            # 1. 接收参数
            dingdan_id = request.data.get('dingdan_id', '').strip()
            print(dingdan_id)
            if not dingdan_id:
                return Response({'code': 1, 'msg': '订单ID不能为空', 'data': None}, status=status.HTTP_400_BAD_REQUEST)

            # 2. 业务验证逻辑（保持你的原有逻辑）
            try:
                from .models import Dingdan
                dingdan = Dingdan.objects.get(
                    dingdan_id=dingdan_id,
                    jiedan_dashou_id=request.user.yonghuid,
                    #zhuangtai=2
                )

            except Dingdan.DoesNotExist:
                return Response({'code': 5, 'msg': '订单无权限或状态不对', 'data': None},
                                status=status.HTTP_403_FORBIDDEN)
            except Exception as e:

                return Response({'code': 500, 'msg': '服务器验证异常', 'data': None},
                                status=status.HTTP_500_INTERNAL_SERVER_ERROR)

            # 3. 获取腾讯云STS临时密钥
            try:
                # 初始化固定凭证
                cred = credential.Credential(
                    settings.COS_SECRET_ID,
                    settings.COS_SECRET_KEY
                )

                # 创建STS客户端
                http_profile = HttpProfile()
                http_profile.endpoint = "sts.tencentcloudapi.com"
                client_profile = ClientProfile()
                client_profile.httpProfile = http_profile

                client = sts_client.StsClient(cred, "ap-shanghai", client_profile)

                # 构建策略（允许上传到订单目录）
                policy = {
                    "version": "2.0",
                    "statement": [
                        {
                            "effect": "allow",
                            "action": [
                                "cos:PutObject",
                                "cos:PostObject",
                                "cos:InitiateMultipartUpload",
                                "cos:UploadPart",
                                "cos:CompleteMultipartUpload"
                            ],
                            "resource": [
                                f"qcs::cos:{settings.COS_REGION}:uid/{settings.COS_APPID}:{settings.COS_BUCKET}/order/{dingdan_id}/*"
                            ]
                        }
                    ]
                }

                # 请求STS临时凭证
                req = models.GetFederationTokenRequest()
                req.Name = f"dashou_{dingdan_id}_{int(time.time())}"
                req.Policy = json.dumps(policy)
                req.DurationSeconds = 7200  # 2小时有效期

                resp = client.GetFederationToken(req)

                # 提取临时密钥
                credentials = resp.Credentials


            except TencentCloudSDKException as e:
                logger.error(f"获取STS临时密钥失败: {str(e)}")
                return Response({
                    'code': 500,
                    'msg': f'获取上传凭证失败: {str(e)}',
                    'data': None
                }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

            # 4. 构建响应数据（严格遵循小程序COS SDK要求）
            current_time = int(time.time())
            response_data = {
                'credentials': {
                    'tmpSecretId': credentials.TmpSecretId,  # 临时SecretId
                    'tmpSecretKey': credentials.TmpSecretKey,  # 临时SecretKey
                    'sessionToken': credentials.Token,  # 必须的Token
                },
                'startTime': current_time,
                'expiredTime': current_time + 7200,
                'bucket': settings.COS_BUCKET,
                'region': settings.COS_REGION,
                'upload_dir': f'order/{dingdan_id}/'
            }



            # 5. 返回成功
            return Response({
                'code': 0,
                'msg': '成功',
                'data': response_data
            }, status=status.HTTP_200_OK)

        except Exception as e:
            logger.error(f'COS凭证接口未知错误: {str(e)}', exc_info=True)
            return Response({
                'code': 500,
                'msg': f'服务器内部错误: {str(e)}',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)'''

#


class DashouTijiaoView(APIView):
    """打手提交订单完成接口"""
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # 1. 获取参数
            data = request.data
            dingdan_id = data.get('dingdan_id', '')
            liuyan = data.get('liuyan', '')
            jiaofu_tupian_urls = data.get('jiaofu_tupian_urls', [])

            # 2. 参数验证
            if not dingdan_id:
                return Response({
                    'code': 1,
                    'msg': '订单ID不能为空',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            if not isinstance(jiaofu_tupian_urls, list):
                return Response({
                    'code': 2,
                    'msg': '图片URL列表格式错误',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 限制图片数量（最多9张，最少1张）
            if len(jiaofu_tupian_urls) == 0:
                return Response({
                    'code': 3,
                    'msg': '至少需要上传一张图片',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            if len(jiaofu_tupian_urls) > 9:
                return Response({
                    'code': 4,
                    'msg': '最多只能上传9张图片',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 留言长度限制（50字）
            if liuyan and len(liuyan) > 50:
                return Response({
                    'code': 5,
                    'msg': '留言最多50个字',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 3. 获取当前用户并验证打手身份
            current_user = request.user
            yonghuid = current_user.yonghuid

            try:
                dashou_profile = current_user.dashou_profile
            except UserDashou.DoesNotExist:
                return Response({
                    'code': 6,
                    'msg': '用户不是打手身份',
                    'data': None
                }, status=status.HTTP_403_FORBIDDEN)

            # 4. 验证订单状态和权限
            try:
                dingdan = Dingdan.objects.get(
                    dingdan_id=dingdan_id,
                    jiedan_dashou_id=yonghuid,
                    zhuangtai=2  # 必须是进行中的订单
                )
            except Dingdan.DoesNotExist:
                return Response({
                    'code': 7,
                    'msg': '订单不存在或没有提交权限',
                    'data': None
                }, status=status.HTTP_403_FORBIDDEN)

            # 5. 存储图片到Dashoutupian表
            for tupian_url in jiaofu_tupian_urls:
                # 创建打手提交图片记录
                Dashoutupian.objects.create(
                    dingdan_id=dingdan_id,
                    dashou=yonghuid,
                    tupian=tupian_url,
                    create_time=timezone.now()
                )

            # 6. 更新订单主表
            dingdan.dashou_liuyan = liuyan
            dingdan.zhuangtai = 8  # 状态改为结算中
            dingdan.update_time = timezone.now()
            dingdan.save()

            # 7. 更新打手扩展表状态
            dashou_profile.zhuangtai = 1  # 改为数字1（根据你之前说的）
            dashou_profile.save()

            from dengji.services import record_dashou_biaoxian
            # ========== 新增：记录打手提交时间 ==========
            record_dashou_biaoxian(
                dingdan_id=dingdan_id,
                dashou_id=yonghuid,
                xingwei=2,  # 提交
                tijiao_time=timezone.now()
            )
            # ===========================================

            # 8. 返回成功响应
            return Response({
                'code': 0,
                'msg': '订单提交成功',
                'data': {
                    'dingdan_id': dingdan_id,
                    'new_zhuangtai': 8,  # 新的订单状态
                    'dashou_zhuangtai': 1  # 打手新的状态
                }
            }, status=status.HTTP_200_OK)

        except Exception as e:
            import logging
            logger = logging.getLogger(__name__)
            logger.error(f"打手提交订单失败: {str(e)}", exc_info=True)

            return Response({
                'code': 8,
                'msg': '服务器内部错误',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)










class DashouDingdanXiangqingView(APIView):
    """打手订单详情获取接口"""
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # 1. 获取订单ID
            dingdan_id = request.data.get('dingdan_id', '')
            if not dingdan_id:
                return Response({
                    'code': 1,
                    'msg': '订单ID不能为空',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 2. 获取当前用户并验证权限
            current_user = request.user
            yonghuid = current_user.yonghuid

            try:
                dashou_profile = current_user.dashou_profile
            except UserDashou.DoesNotExist:
                return Response({
                    'code': 2,
                    'msg': '用户不是打手身份',
                    'data': None
                }, status=status.HTTP_403_FORBIDDEN)

            # 3. 查询订单主表
            try:
                dingdan = Dingdan.objects.get(dingdan_id=dingdan_id)
            except Dingdan.DoesNotExist:
                return Response({
                    'code': 3,
                    'msg': '订单不存在',
                    'data': None
                }, status=status.HTTP_404_NOT_FOUND)

            # 4. 验证订单是否属于当前打手
            if dingdan.jiedan_dashou_id != yonghuid:
                return Response({
                    'code': 4,
                    'msg': '没有权限查看此订单',
                    'data': None
                }, status=status.HTTP_403_FORBIDDEN)

            # 5. 构建基础订单数据
            dingdan_data = {
                'dingdan_id': dingdan.dingdan_id,
                'zhuangtai': dingdan.zhuangtai,
                'jine': float(dingdan.dashou_fencheng) if dingdan.dashou_fencheng else 0.0,
                'jieshao': dingdan.jieshao or '',
                'tupian': dingdan.tupian or '',
                'nicheng': dingdan.nicheng or '',
                'beizhu': dingdan.beizhu or '',
                'create_time': dingdan.create_time.strftime('%Y-%m-%d %H:%M:%S') if dingdan.create_time else '',
                'dashou_liuyan': dingdan.dashou_liuyan or '',
                'fuwudashou_id': dingdan.jiedan_dashou_id or '',
                'fadanpingtai': dingdan.fadan_pingtai or '',
                'tuikuan_liyou': dingdan.tkly or ''
            }

            # 6. 查询打手提交的图片
            dashou_tupian_list = Dashoutupian.objects.filter(
                dingdan_id=dingdan_id,
                dashou=yonghuid
            ).order_by('create_time')

            jiaofu_tupian_urls = []
            for tupian_record in dashou_tupian_list:
                if tupian_record.tupian:
                    jiaofu_tupian_urls.append(tupian_record.tupian)

            dingdan_data['dashou_jiaofu'] = jiaofu_tupian_urls

            # 7. 查询商家扩展表信息
            shangjia_info = {}
            try:
                shangjia_kuozhan = dingdan.shangjia_kuozhan
                shangjia_info = {
                    'shangjia_id': shangjia_kuozhan.shangjia_id or '',
                    'shangjia_nicheng': shangjia_kuozhan.sjnicheng or '',
                    'shangjia_liuyan': shangjia_kuozhan.shangjia_pingjia or '',

                    'chufa_liyou': shangjia_kuozhan.cfliyou or '',
                    'chufa_zhuangtai': shangjia_kuozhan.sqzhuangtai or 0,
                    #'chufa_jieguo': shangjia_kuozhan.chufa_jieguo or '',
                    'bohui_liyou': shangjia_kuozhan.bhliyou or '',
                    #'tuikuan_liyou': dingdan.tkly or ''
                }
            except DingdanShangjia.DoesNotExist:
                # 没有商家扩展信息，返回空值
                shangjia_info = {
                    'shangjia_id': '',
                    'shangjia_nicheng': '',
                    'shangjia_liuyan': '',
                    #'tuikuan_liyou': '',
                    'chufa_liyou': '',
                    'chufa_zhuangtai': 0,
                    'chufa_jieguo': '',
                    'bohui_liyou': ''
                }

            # 8. 查询平台扩展表信息（如果有的话）
            pingtai_info = {}
            try:
                pingtai_kuozhan = dingdan.pingtai_kuozhan
                pingtai_info = {
                    'laoban_id': pingtai_kuozhan.laoban_id or '',
                    'laoban_pingjia': pingtai_kuozhan.laoban_pingjia or ''
                }
            except DingdanPingtai.DoesNotExist:
                pingtai_info = {
                    'laoban_id': '',
                    'laoban_pingjia': ''
                }

            # 9. 合并所有数据
            response_data = {
                **dingdan_data,
                **shangjia_info,
                **pingtai_info
            }

            return Response({
                'code': 0,
                'msg': '成功',
                'data': response_data
            }, status=status.HTTP_200_OK)

        except Exception as e:
            import logging
            logger = logging.getLogger(__name__)
            logger.error(f"获取打手订单详情失败: {str(e)}", exc_info=True)

            return Response({
                'code': 5,
                'msg': '服务器内部错误',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)




# dingdan/views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from rest_framework.parsers import JSONParser
import logging


logger = logging.getLogger(__name__)


class AdGetDingdanXiangQing(APIView):
    """
    后台订单详情获取接口
    权限: JWT Token认证 + 管理员身份验证
    前端调用: POST /dingdan/adddxq
    参数: {"zhanghao": "管理员手机号", "dingdan_id": "订单ID"}
    """

    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        """
        获取订单详情数据
        返回: 订单主表数据 + 扩展表数据 + 打手图片列表
        """
        try:
            # 1. 获取前端参数
            qianzhanghao = request.data.get('zhanghao', '').strip()
            dingdan_id = request.data.get('dingdan_id', '').strip()

            if not qianzhanghao or not dingdan_id:
                return Response(
                    {'code': 400, 'message': '参数不完整', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 2. JWT Token身份验证 (IsAuthenticated已处理)
            dangqianyonghu = request.user

            # 3. 验证手机号是否匹配
            if not hasattr(dangqianyonghu, 'phone') or str(dangqianyonghu.phone) != qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 4. 验证用户类型是否为管理员
            if dangqianyonghu.user_type != 'admin':
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 5. 验证管理员扩展表是否存在
            try:
                guanliyuan = dangqianyonghu.admin_profile
            except AttributeError:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 6. 查询订单主表
            try:
                from dingdan.models import Dingdan, DingdanPingtai, DingdanShangjia, Dashoutupian

                # 查询订单主表 - 使用select_related预加载关联表
                dingdan_obj = Dingdan.objects.select_related(
                    'pingtai_kuozhan', 'shangjia_kuozhan'
                ).get(dingdan_id=dingdan_id)

            except Dingdan.DoesNotExist:
                return Response(
                    {'code': 404, 'message': '订单不存在', 'data': None},
                    status=status.HTTP_404_NOT_FOUND
                )

            # 7. 构建返回数据 - 主表字段
            response_data = {
                # 基础信息字段
                'dingdan_id': dingdan_obj.dingdan_id or '',
                'jieshao': dingdan_obj.jieshao or '',
                'zhuangtai': dingdan_obj.zhuangtai or 0,
                'leixing': dingdan_obj.leixing_id or 0,  # 前端需要 leixing，对应 leixing_id
                'fadanpingtai': dingdan_obj.fadan_pingtai or 0,  # 前端需要 fadanpingtai，对应 fadan_pingtai
                'jiage': float(dingdan_obj.jine) if dingdan_obj.jine else 0.00,  # 前端需要 jiage，对应 jine
                'tupian_url': dingdan_obj.tupian or '',  # 前端需要 tupian_url，对应 tupian
                'beizhu': dingdan_obj.beizhu or '',

                # 服务信息字段
                'jiedan_dashou_id': dingdan_obj.jiedan_dashou_id or '',
                'dashou_fencheng': float(dingdan_obj.dashou_fencheng) if dingdan_obj.dashou_fencheng else 0.00,
                'zhiding_id': dingdan_obj.zhiding_id or '',
                'dashou_liuyan': dingdan_obj.dashou_liuyan or '',

                # 时间字段
                'chuangjianshijian': dingdan_obj.create_time.strftime(
                    '%Y-%m-%d %H:%M:%S') if dingdan_obj.create_time else '',
                'genggaishijian': dingdan_obj.update_time.strftime(
                    '%Y-%m-%d %H:%M:%S') if dingdan_obj.update_time else '',
            }

            # 8. 根据发单平台查询扩展表数据
            fadan_pingtai = dingdan_obj.fadan_pingtai

            if fadan_pingtai == 1:
                # 平台发单 - 查询平台订单扩展表
                try:
                    # 使用反向关联 pingtai_kuozhan
                    pingtai_kuozhan = dingdan_obj.pingtai_kuozhan

                    response_data.update({
                        'laoban_id': pingtai_kuozhan.laoban_id or '',
                        'nicheng': dingdan_obj.nicheng or '',  # 这个字段在订单主表
                        'laoban_pingjia': pingtai_kuozhan.laoban_pingjia or '',
                    })
                except DingdanPingtai.DoesNotExist:
                    # 扩展表不存在，返回空值
                    response_data.update({
                        'laoban_id': '',
                        'nicheng': dingdan_obj.nicheng or '',
                        'laoban_pingjia': '',
                    })

            elif fadan_pingtai == 2:
                # 商家发单 - 查询商家订单扩展表
                try:
                    # 使用反向关联 shangjia_kuozhan
                    shangjia_kuozhan = dingdan_obj.shangjia_kuozhan

                    response_data.update({
                        'shangjia_id': shangjia_kuozhan.shangjia_id or '',
                        'sjnicheng': shangjia_kuozhan.sjnicheng or '',
                        'shangjia_pingjia': shangjia_kuozhan.shangjia_pingjia or '',
                        'cfliyou': shangjia_kuozhan.cfliyou or '',  # 商家处罚理由
                        'bhliyou': shangjia_kuozhan.bhliyou or '',  # 驳回理由
                    })
                except DingdanShangjia.DoesNotExist:
                    # 扩展表不存在，返回空值
                    response_data.update({
                        'shangjia_id': '',
                        'sjnicheng': '',
                        'shangjia_pingjia': '',
                        'cfliyou': '',
                        'bhliyou': '',
                    })

            # 9. 查询打手提交的图片
            try:
                # 查询该订单的所有打手提交图片
                dashou_tupian_list = Dashoutupian.objects.filter(
                    dingdan_id=dingdan_id
                ).values_list('tupian', flat=True)

                # 转换为列表，过滤空值
                dashou_images = [img for img in dashou_tupian_list if img]
                response_data['dashou_images'] = dashou_images
            except Exception as e:
                logger.warning(f"查询打手图片失败: {str(e)}")
                response_data['dashou_images'] = []

            # 🔥 新增：查询退款记录表中的商家退款理由
            try:
                # 导入退款记录模型
                from dingdan.models import Tuikuanjilu

                # 查询该订单的退款记录（一个订单可能有多次退款申请，我们取最新的）
                tuikuan_record = Tuikuanjilu.objects.filter(
                    dingdan_id=dingdan_id
                ).order_by('-create_time').first()  # 按创建时间倒序，取最新的

                if tuikuan_record and tuikuan_record.liyou:
                    # 如果有退款记录且理由不为空，添加到返回数据
                    response_data['tuikuan_liyou'] = tuikuan_record.liyou
                else:
                    # 没有找到退款记录或理由为空
                    response_data['tuikuan_liyou'] = ''
            except Tuikuanjilu.DoesNotExist:
                # 退款记录表不存在该订单的记录
                response_data['tuikuan_liyou'] = ''
            except Exception as e:
                # 查询过程中出现其他异常
                logger.warning(f"查询退款记录失败: {str(e)}")
                response_data['tuikuan_liyou'] = ''

            # 10. 返回成功响应
            return Response({
                'code': 0,
                'message': '获取成功',
                'data': response_data
            })

        except Exception as e:
            logger.error(f"获取订单详情异常: {str(e)}", exc_info=True)
            return Response(
                {'code': 500, 'message': '服务器内部错误', 'data': None},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )




# 获取日志器
logger = logging.getLogger(__name__)


class AdGengHuanDaShou(APIView):
    """
    后台更换打手接口
    权限: JWT Token认证 + 管理员身份验证
    前端调用: POST /dingdan/adddgh
    参数: {
        "zhanghao": "管理员账号",
        "dingdan_id": "订单ID",
        "new_dashou_id": "新打手ID"
    }
    """

    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        """
        更换订单的打手
        核心逻辑：
        1. 验证管理员身份
        2. 验证订单存在且状态为进行中(2)或结算中(8)
        3. 验证新打手ID存在且是打手身份
        4. 验证新打手状态正常（zhuangtai=1且zhanghaozhuangtai=1）
        5. 根据订单的抢单要求类型进行验证：
           - 会员抢单(1)：验证打手有对应会员且未过期
           - 押金抢单(2)：验证打手押金≥订单押金
        6. 更新新打手状态和统计数据
        7. 更新原打手状态和统计数据
        8. 更新订单信息
        """
        try:
            # 1. 获取前端参数
            qianzhanghao = request.data.get('zhanghao', '').strip()
            dingdan_id = request.data.get('dingdan_id', '').strip()
            new_dashou_id = request.data.get('new_dashou_id', '').strip()

            if not qianzhanghao or not dingdan_id or not new_dashou_id:
                return Response(
                    {'code': 400, 'message': '参数不完整', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 2. JWT Token身份验证
            dangqianyonghu = request.user

            # 3. 验证手机号是否匹配
            if not hasattr(dangqianyonghu, 'phone') or str(dangqianyonghu.phone) != qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 4. 验证用户类型是否为管理员
            if dangqianyonghu.user_type != 'admin':
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 5. 验证管理员扩展表是否存在
            try:
                guanliyuan = dangqianyonghu.admin_profile
            except AttributeError:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 6. 查询订单主表
            try:
                from dingdan.models import Dingdan
                dingdan_obj = Dingdan.objects.get(dingdan_id=dingdan_id)
            except Dingdan.DoesNotExist:
                return Response(
                    {'code': 404, 'message': '订单不存在', 'data': None},
                    status=status.HTTP_404_NOT_FOUND
                )

            # 7. 验证订单状态是否为进行中(2)或结算中(8)
            if dingdan_obj.zhuangtai not in [2, 8]:
                return Response(
                    {'code': 400, 'message': '订单状态不允许更换打手', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 8. 验证新打手ID是否存在，并且是打手身份
            try:
                new_dashou_user = UserMain.objects.get(
                    yonghuid=new_dashou_id,
                    #user_type='dashou'
                )
            except UserMain.DoesNotExist:
                return Response(
                    {'code': 404, 'message': '打手不存在或不是打手身份', 'data': None},
                    status=status.HTTP_404_NOT_FOUND
                )

            # 9. 获取新打手扩展表
            try:
                new_dashou_profile = new_dashou_user.dashou_profile
            except AttributeError:
                return Response(
                    {'code': 404, 'message': '打手信息不完整', 'data': None},
                    status=status.HTTP_404_NOT_FOUND
                )

            # 10. 验证新打手状态：zhuangtai=1且zhanghaozhuangtai=1
            if new_dashou_profile.zhuangtai != 1 or new_dashou_profile.zhanghaozhuangtai != 1:
                return Response(
                    {'code': 400, 'message': '打手状态不允许接单', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 11. 根据订单的抢单要求类型进行验证
            yaoqiuleixing = dingdan_obj.yaoqiuleixing

            if yaoqiuleixing == 1:  # 会员抢单
                # 获取订单的会员ID
                huiyuan_id = dingdan_obj.huiyuan_id
                if not huiyuan_id:
                    return Response(
                        {'code': 400, 'message': '订单会员ID为空', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                # 查询会员购买记录
                try:
                    from shangpin.models import Huiyuangoumai
                    huiyuan_goumai = Huiyuangoumai.objects.get(
                        huiyuan_id=huiyuan_id,
                        yonghu_id=new_dashou_id  # 注意：yonghu_id存储的是用户ID（yonghuid）
                    )
                except Huiyuangoumai.DoesNotExist:
                    return Response(
                        {'code': 400, 'message': '打手未购买该订单要求的会员', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                # 检查会员是否过期
                # ✅ 可以调用！因为jiance_shifou_daoqi()是Huiyuangoumai模型的实例方法
                is_expired = huiyuan_goumai.jiance_shifou_daoqi()
                if is_expired or huiyuan_goumai.huiyuan_zhuangtai != 1:
                    return Response(
                        {'code': 400, 'message': '打手的会员已过期', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

            elif yaoqiuleixing == 2:  # 押金抢单
                # 获取订单的押金（yongjin字段）
                order_yajin = dingdan_obj.yongjin
                if order_yajin is None:
                    return Response(
                        {'code': 400, 'message': '订单押金为空', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                # 验证打手押金是否大于等于订单押金
                if new_dashou_profile.yajin < order_yajin:
                    return Response(
                        {'code': 400, 'message': '打手押金不足', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )
            else:
                # 未知的抢单要求类型
                return Response(
                    {'code': 400, 'message': '订单抢单要求类型错误', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 12. 所有验证通过，开始更换打手（使用事务保证一致性）
            with transaction.atomic():
                # 12.1 更新新打手扩展表
                new_dashou_profile.zhuangtai = 0  # 接单中
                new_dashou_profile.jiedanzongliang += 1
                new_dashou_profile.jinrijiedan += 1
                new_dashou_profile.jinyuejiedan += 1
                new_dashou_profile.save()

                # 12.2 如果原订单有接单打手，则更新原打手状态
                old_dashou_id = dingdan_obj.jiedan_dashou_id
                if old_dashou_id:
                    try:
                        # 查询原打手主表
                        old_dashou_user = UserMain.objects.get(
                            yonghuid=old_dashou_id,
                            #user_type='dashou'
                        )

                        # 获取原打手扩展表
                        old_dashou_profile = old_dashou_user.dashou_profile

                        # 更新原打手状态
                        old_dashou_profile.zhuangtai = 1  # 空闲
                        old_dashou_profile.tuikuanliang += 1  # 退款订单总量+1
                        old_dashou_profile.save()

                        logger.info(f"成功更新原打手{old_dashou_id}状态")
                    except UserMain.DoesNotExist:
                        # 原打手不存在，继续执行不影响更换
                        logger.warning(f"原打手{old_dashou_id}不存在，跳过更新")
                    except AttributeError:
                        # 原打手扩展表不存在，继续执行不影响更换
                        logger.warning(f"原打手{old_dashou_id}扩展信息不存在，跳过更新")
                    except Exception as e:
                        # 其他异常，记录日志但继续执行
                        logger.error(f"更新原打手状态异常: {str(e)}", exc_info=True)

                # 12.3 更新订单表
                dingdan_obj.jiedan_dashou_id = new_dashou_id
                dingdan_obj.zhuangtai = 2  # 进行中状态
                dingdan_obj.save()

            # 13. 返回成功响应
            return Response({
                'code': 0,
                'message': '更换打手成功',
                'data': None
            })

        except Exception as e:
            logger.error(f"更换打手接口异常: {str(e)}", exc_info=True)
            return Response(
                {'code': 500, 'message': '服务器内部错误', 'data': None},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )


import logging

# 获取日志器
logger = logging.getLogger(__name__)


'''class AdQiangZhiJieDan(APIView):
    """
    后台强制结单接口
    权限: JWT Token认证 + 管理员身份验证
    前端调用: POST /dingdan/adddqzjd
    参数: {
        "zhanghao": "管理员账号",
        "dingdan_id": "订单ID"
    }
    """

    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        """
        强制结单接口
        核心逻辑：
        1. 验证管理员身份
        2. 验证订单状态为2(进行中)、8(结算中)或4(退款审核中)才能强制结单
        3. 根据发单平台(1=平台发单, 2=商家发单)分别处理
        4. 更新订单状态为3(已完成)
        5. 给打手结算分成金额
        6. 如果是商家发单，还需要更新商家成交订单数量
        """
        try:
            # 1. 获取前端参数
            qianzhanghao = request.data.get('zhanghao', '').strip()
            dingdan_id = request.data.get('dingdan_id', '').strip()

            if not qianzhanghao or not dingdan_id:
                return Response(
                    {'code': 400, 'message': '参数不完整', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 2. JWT Token身份验证
            dangqianyonghu = request.user

            # 3. 验证手机号是否匹配
            if not hasattr(dangqianyonghu, 'phone') or str(dangqianyonghu.phone) != qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 4. 验证用户类型是否为管理员
            if dangqianyonghu.user_type != 'admin':
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 5. 验证管理员扩展表是否存在
            try:
                guanliyuan = dangqianyonghu.admin_profile
            except AttributeError:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 6. 查询订单主表
            try:
                from dingdan.models import Dingdan, DingdanPingtai, DingdanShangjia
                dingdan_obj = Dingdan.objects.get(dingdan_id=dingdan_id)
            except Dingdan.DoesNotExist:
                return Response(
                    {'code': 404, 'message': '订单不存在', 'data': None},
                    status=status.HTTP_404_NOT_FOUND
                )

            # 7. 验证订单状态是否为2、8或4
            if dingdan_obj.zhuangtai not in [2, 8, 4]:
                return Response(
                    {'code': 400, 'message': '订单状态不允许强制结单', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 8. 获取订单的重要字段
            jiedan_dashou_id = dingdan_obj.jiedan_dashou_id  # 接单打手ID
            dashou_fencheng = dingdan_obj.dashou_fencheng  # 打手分成金额
            fadan_pingtai = dingdan_obj.fadan_pingtai  # 发单平台

            # 9. 验证打手分成金额是否存在
            if dashou_fencheng is None:
                return Response(
                    {'code': 400, 'message': '订单缺少打手分成金额', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 10. 使用事务保证数据一致性
            with transaction.atomic():
                # 10.1 更新订单状态为3（已完成）
                dingdan_obj.zhuangtai = 3
                dingdan_obj.save()

                # 10.2 处理打手结算
                if jiedan_dashou_id:
                    try:
                        # 查询打手用户主表
                        dashou_user = UserMain.objects.get(
                            yonghuid=jiedan_dashou_id,
                            #user_type='dashou'
                        )

                        # 获取打手扩展表
                        dashou_profile = dashou_user.dashou_profile

                        dashou_profile.zhuangtai = 1

                        # 更新打手扩展表数据
                        # ✅ 确认字段：chengjiaozongliang 成交单总量
                        dashou_profile.chengjiaozongliang += 1

                        # ✅ 确认字段：yue 可提现余额
                        dashou_profile.yue += dashou_fencheng

                        # ✅ 确认字段：zonge 打单赚取总额
                        dashou_profile.zonge += dashou_fencheng

                        # ✅ 确认字段：jinrishouyi 今日收益金额
                        dashou_profile.jinrishouyi += dashou_fencheng

                        # ✅ 确认字段：jinyueshouyi 今月收益金额
                        dashou_profile.jinyueshouyi += dashou_fencheng

                        dashou_profile.save()
                        logger.info(f"强制结单成功，打手{jiedan_dashou_id}结算分成：{dashou_fencheng}")

                    except UserMain.DoesNotExist:
                        # 打手用户不存在，记录日志但不影响强制结单
                        logger.warning(f"强制结单：打手{jiedan_dashou_id}不存在，跳过打手结算")
                    except AttributeError:
                        # 打手扩展表不存在，记录日志但不影响强制结单
                        logger.warning(f"强制结单：打手{jiedan_dashou_id}扩展信息不存在，跳过打手结算")

                # 10.3 如果是商家发单，还需要更新商家扩展表
                if fadan_pingtai == 2:
                    try:
                        # 获取商家订单扩展表
                        shangjia_kuozhan = dingdan_obj.shangjia_kuozhan
                        shangjia_id = shangjia_kuozhan.shangjia_id

                        if shangjia_id:
                            # 查询商家用户主表
                            shangjia_user = UserMain.objects.get(
                                yonghuid=shangjia_id,
                                #user_type='shop'
                            )

                            # 获取商家扩展表
                            shangjia_profile = shangjia_user.shop_profile

                            # ✅ 确认字段：chengjiao 商家成交订单总量
                            shangjia_profile.chengjiao += 1
                            shangjia_profile.save()

                            logger.info(f"强制结单成功，商家{shangjia_id}成交订单+1")

                    except DingdanShangjia.DoesNotExist:
                        # 商家订单扩展表不存在，跳过商家更新
                        logger.warning(f"强制结单：订单{dingdan_id}商家扩展表不存在，跳过商家更新")
                    except UserMain.DoesNotExist:
                        # 商家用户不存在，跳过商家更新
                        logger.warning(f"强制结单：商家{shangjia_id}不存在，跳过商家更新")
                    except AttributeError:
                        # 商家扩展表不存在，跳过商家更新
                        logger.warning(f"强制结单：商家{shangjia_id}扩展信息不存在，跳过商家更新")

            # 11. 返回成功响应
            # 12. 更新平台收益流水（仅在平台发单时）
            if dingdan_obj.fadan_pingtai == 1:
                try:
                    from dingdan.utils import update_platform_profit  # 导入函数
                    update_platform_profit(dingdan_id)
                except Exception as e:
                    # 平台收益更新失败不影响主流程，但记录日志
                    logger.error(f"强制结单后更新平台收益失败: {str(e)}")

            return Response({
                'code': 0,
                'message': '强制结单成功',
                'data': None
            })

        except Exception as e:
            logger.error(f"强制结单接口异常: {str(e)}", exc_info=True)
            return Response(
                {'code': 500, 'message': '服务器内部错误', 'data': None},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )'''



class AdQiangZhiJieDan(APIView):
    """后台强制结单接口（支持跨平台订单）"""
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        try:
            # 1. 获取参数
            qianzhanghao = request.data.get('zhanghao', '').strip()
            dingdan_id = request.data.get('dingdan_id', '').strip()

            if not qianzhanghao or not dingdan_id:
                return Response(
                    {'code': 400, 'message': '参数不完整', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 2. 身份验证
            dangqianyonghu = request.user
            if not hasattr(dangqianyonghu, 'phone') or str(dangqianyonghu.phone) != qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            if dangqianyonghu.user_type != 'admin':
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            try:
                guanliyuan = dangqianyonghu.admin_profile
            except AttributeError:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 3. 查询订单并加锁（修复并发问题）
            with transaction.atomic():
                try:
                    order = Dingdan.objects.select_for_update().get(dingdan_id=dingdan_id)
                except Dingdan.DoesNotExist:
                    return Response(
                        {'code': 404, 'message': '订单不存在', 'data': None},
                        status=status.HTTP_404_NOT_FOUND
                    )

                # 4. 验证订单状态
                if order.zhuangtai not in [2, 8, 4]:
                    return Response(
                        {'code': 400, 'message': '订单状态不允许强制结单', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                # 获取订单字段
                jiedan_dashou_id = order.jiedan_dashou_id
                dashou_fencheng = order.dashou_fencheng or Decimal('0')
                fadan_pingtai = order.fadan_pingtai
                dispatch_type = order.dispatch_type
                is_cross = order.is_cross
                partner_club_id = order.partner_club_id
                partner_order_id = order.partner_order_id
                jine = order.jine or Decimal('0')

                if dashou_fencheng is None:
                    return Response(
                        {'code': 400, 'message': '订单缺少打手分成金额', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                # ========== 跨平台判断 ==========
                is_cross_claimed_by_partner = (is_cross == 1 and (partner_club_id or partner_order_id))

                # ========== 根据订单类型处理 ==========
                # 情况1：对方派单（我方打手接单）-> 预结算，不直接给打手加钱
                if dispatch_type == 2:
                    # 创建预结算记录
                    PreSettlement.objects.update_or_create(
                        dingdan_id=dingdan_id,
                        defaults={
                            'partner_order_id': partner_order_id,
                            'partner_club_id': partner_club_id or '000001',
                            'dashou_id': jiedan_dashou_id,
                            'amount': dashou_fencheng,
                            'order_amount': jine,
                            'status': 0,
                            'operator': qianzhanghao,
                        }
                    )
                    order.zhuangtai = 3
                    order.save()

                    # 更新统计表
                    update_daily_dispatch_stat(
                        direction=2,
                        partner_club_id=partner_club_id or '000001',
                        success_amount=jine,
                        success_count=1
                    )

                # 情况2：我方派单且被对方打手接单 -> 只改状态，不给本地打手加钱
                elif dispatch_type == 1 and is_cross_claimed_by_partner:
                    order.zhuangtai = 3
                    order.save()

                    update_daily_dispatch_stat(
                        direction=1,
                        partner_club_id=partner_club_id or '000001',
                        success_amount=dashou_fencheng,
                        success_count=1
                    )

                # 情况3：本地订单 或 跨平台但自家打手接单 -> 正常结算给打手
                else:
                    # 处理打手结算
                    if jiedan_dashou_id:
                        try:
                            dashou_user = UserMain.objects.get(yonghuid=jiedan_dashou_id)
                            dashou_profile = dashou_user.dashou_profile

                            # 原子更新打手数据
                            dashou_profile.zhuangtai = 1
                            dashou_profile.chengjiaozongliang = F('chengjiaozongliang') + 1
                            dashou_profile.yue = F('yue') + dashou_fencheng
                            dashou_profile.zonge = F('zonge') + dashou_fencheng
                            dashou_profile.jinrishouyi = F('jinrishouyi') + dashou_fencheng
                            dashou_profile.jinyueshouyi = F('jinyueshouyi') + dashou_fencheng
                            dashou_profile.save(update_fields=[
                                'zhuangtai', 'chengjiaozongliang', 'yue', 'zonge',
                                'jinrishouyi', 'jinyueshouyi'
                            ])
                            logger.info(f"强制结单成功，打手{jiedan_dashou_id}结算分成：{dashou_fencheng}")
                        except (UserMain.DoesNotExist, AttributeError):
                            logger.warning(f"强制结单：打手{jiedan_dashou_id}不存在，跳过打手结算")

                    # 处理商家订单
                    if fadan_pingtai == 2:
                        try:
                            shangjia_kuozhan = order.shangjia_kuozhan
                            shangjia_id = shangjia_kuozhan.shangjia_id
                            if shangjia_id:
                                shangjia_user = UserMain.objects.get(yonghuid=shangjia_id)
                                shangjia_profile = shangjia_user.shop_profile
                                shangjia_profile.chengjiao = F('chengjiao') + 1
                                shangjia_profile.save(update_fields=['chengjiao'])
                                logger.info(f"强制结单成功，商家{shangjia_id}成交订单+1")
                        except Exception as e:
                            logger.warning(f"强制结单：商家更新失败 - {str(e)}")

                    order.zhuangtai = 3
                    order.save()

                if fadan_pingtai == 2 and order.zhuangtai == 3:
                    from dingdan.utils import settle_shangjia_order_guanshi_fenhong
                    settle_shangjia_order_guanshi_fenhong(order, jiedan_dashou_id)

            # 返回成功
            return Response({
                'code': 0,
                'message': '强制结单成功',
                'data': None
            })

        except Exception as e:
            logger.error(f"强制结单接口异常: {str(e)}", exc_info=True)
            return Response(
                {'code': 500, 'message': '服务器内部错误', 'data': None},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )



class AdJuJueTuiKuan(APIView):
    """
    后台拒绝退款接口
    权限: JWT Token认证 + 管理员身份验证
    前端调用: POST /dingdan/adddjj
    参数: {
        "zhanghao": "管理员账号",
        "dingdan_id": "订单ID",
        "jujue_liyou": "拒绝退款理由（可选）"
    }
    """

    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        """
        拒绝退款接口
        核心逻辑：
        1. 验证管理员身份
        2. 拒绝退款后订单状态改为6（退款失败）
        3. 给打手结算分成金额
        4. 如果是商家发单，更新商家成交订单数量
        5. 更新退款记录表，状态改为2（驳回）
        """
        try:
            # 1. 获取前端参数
            qianzhanghao = request.data.get('zhanghao', '').strip()
            dingdan_id = request.data.get('dingdan_id', '').strip()
            jujue_liyou = request.data.get('jujue_liyou', '').strip()

            if not qianzhanghao or not dingdan_id:
                return Response(
                    {'code': 400, 'message': '参数不完整', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 2. JWT Token身份验证
            dangqianyonghu = request.user

            # 3. 验证手机号是否匹配
            if not hasattr(dangqianyonghu, 'phone') or str(dangqianyonghu.phone) != qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 4. 验证用户类型是否为管理员
            if dangqianyonghu.user_type != 'admin':
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 5. 验证管理员扩展表是否存在
            try:
                guanliyuan = dangqianyonghu.admin_profile
            except AttributeError:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 6. 查询订单主表
            try:
                from dingdan.models import Dingdan, DingdanShangjia, Tuikuanjilu
                dingdan_obj = Dingdan.objects.get(dingdan_id=dingdan_id)
            except Dingdan.DoesNotExist:
                return Response(
                    {'code': 404, 'message': '订单不存在', 'data': None},
                    status=status.HTTP_404_NOT_FOUND
                )

            # 7. 获取订单的重要字段
            jiedan_dashou_id = dingdan_obj.jiedan_dashou_id  # 接单打手ID
            dashou_fencheng = dingdan_obj.dashou_fencheng  # 打手分成金额
            fadan_pingtai = dingdan_obj.fadan_pingtai  # 发单平台

            # 8. 验证打手分成金额是否存在
            if dashou_fencheng is None:
                return Response(
                    {'code': 400, 'message': '订单缺少打手分成金额', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 9. 使用事务保证数据一致性
            with transaction.atomic():
                # 9.1 更新订单状态为6（退款失败）
                dingdan_obj.zhuangtai = 6
                dingdan_obj.save()

                # 9.2 处理打手结算
                if jiedan_dashou_id:
                    try:
                        # 查询打手用户主表
                        dashou_user = UserMain.objects.get(
                            yonghuid=jiedan_dashou_id,
                            #user_type='dashou'
                        )

                        # 获取打手扩展表
                        dashou_profile = dashou_user.dashou_profile

                        # 更新打手扩展表数据
                        # ✅ 确认字段：chengjiaozongliang 成交单总量
                        dashou_profile.chengjiaozongliang += 1

                        # ✅ 确认字段：yue 可提现余额
                        dashou_profile.yue += dashou_fencheng

                        # ✅ 确认字段：zonge 打单赚取总额
                        dashou_profile.zonge += dashou_fencheng

                        # ✅ 确认字段：jinrishouyi 今日收益金额
                        dashou_profile.jinrishouyi += dashou_fencheng

                        # ✅ 确认字段：jinyueshouyi 今月收益金额
                        dashou_profile.jinyueshouyi += dashou_fencheng

                        dashou_profile.save()
                        logger.info(f"拒绝退款成功，打手{jiedan_dashou_id}结算分成：{dashou_fencheng}")

                    except UserMain.DoesNotExist:
                        # 打手用户不存在，记录日志但不影响操作
                        logger.warning(f"拒绝退款：打手{jiedan_dashou_id}不存在，跳过打手结算")
                    except AttributeError:
                        # 打手扩展表不存在，记录日志但不影响操作
                        logger.warning(f"拒绝退款：打手{jiedan_dashou_id}扩展信息不存在，跳过打手结算")

                # 9.3 如果是商家发单，还需要更新商家扩展表
                if fadan_pingtai == 2:
                    try:
                        # 获取商家订单扩展表
                        shangjia_kuozhan = dingdan_obj.shangjia_kuozhan
                        shangjia_id = shangjia_kuozhan.shangjia_id

                        if shangjia_id:
                            # 查询商家用户主表
                            shangjia_user = UserMain.objects.get(
                                yonghuid=shangjia_id,
                                #user_type='shop'
                            )

                            # 获取商家扩展表
                            shangjia_profile = shangjia_user.shop_profile

                            # ✅ 确认字段：chengjiao 商家成交订单总量
                            shangjia_profile.chengjiao += 1
                            shangjia_profile.save()

                            logger.info(f"拒绝退款成功，商家{shangjia_id}成交订单+1")

                    except DingdanShangjia.DoesNotExist:
                        # 商家订单扩展表不存在，跳过商家更新
                        logger.warning(f"拒绝退款：订单{dingdan_id}商家扩展表不存在，跳过商家更新")
                    except UserMain.DoesNotExist:
                        # 商家用户不存在，跳过商家更新
                        logger.warning(f"拒绝退款：商家{shangjia_id}不存在，跳过商家更新")
                    except AttributeError:
                        # 商家扩展表不存在，跳过商家更新
                        logger.warning(f"拒绝退款：商家{shangjia_id}扩展信息不存在，跳过商家更新")

                # 9.4 更新退款记录表
                try:
                    # 查询退款记录表
                    tuikuan_jilu = Tuikuanjilu.objects.get(dingdan_id=dingdan_id)

                    # ✅ 确认字段：sqzhuangtai 申请状态，改为2（驳回）
                    tuikuan_jilu.sqzhuangtai = 2

                    # ✅ 确认字段：bhliyou 驳回理由
                    tuikuan_jilu.bhliyou = jujue_liyou

                    # ✅ 确认字段：chuliid 处理人ID（使用管理员账号，即手机号）
                    tuikuan_jilu.chuliid = qianzhanghao

                    tuikuan_jilu.save()
                    logger.info(f"拒绝退款成功，更新退款记录表，订单：{dingdan_id}")

                except Tuikuanjilu.DoesNotExist:
                    # 退款记录表不存在，记录日志但不影响主流程
                    logger.warning(f"拒绝退款：订单{dingdan_id}退款记录不存在，跳过更新")

            # 10. 返回成功响应
            return Response({
                'code': 0,
                'message': '拒绝退款成功',
                'data': None
            })

        except Exception as e:
            logger.error(f"拒绝退款接口异常: {str(e)}", exc_info=True)
            return Response(
                {'code': 500, 'message': '服务器内部错误', 'data': None},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )


class AdTongYiTuiKuanShangJia(APIView):
    """
    后台同意退款接口（商家发单）
    权限: JWT Token认证 + 管理员身份验证 + 密码验证
    前端调用: POST /dingdan/adddsjtk
    参数: {
        "zhanghao": "管理员账号",
        "dingdan_id": "订单ID",
        "tuikuan_liyou": "退款理由（可选）",
        "pay_password": "支付密码（openid）"
    }
    """

    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        """
        同意退款接口（商家发单）
        核心逻辑：
        1. 验证管理员身份
        2. 验证支付密码（openid）
        3. 检查订单状态为4（退款审核中）
        4. 更新订单状态为5（已退款）
        5. 更新打手退款订单数量
        6. 更新商家退款订单数量和余额（加上订单金额）
        7. 更新退款记录表，状态改为1（成功）
        """
        try:
            # 1. 获取前端参数
            qianzhanghao = request.data.get('zhanghao', '').strip()
            dingdan_id = request.data.get('dingdan_id', '').strip()
            tuikuan_liyou = request.data.get('tuikuan_liyou', '').strip()
            pay_password = request.data.get('pay_password', '').strip()

            if not qianzhanghao or not dingdan_id or not pay_password:
                return Response(
                    {'code': 400, 'message': '参数不完整', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 2. JWT Token身份验证
            dangqianyonghu = request.user

            # 3. 验证手机号是否匹配
            if not hasattr(dangqianyonghu, 'phone') or str(dangqianyonghu.phone) != qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 4. 验证用户类型是否为管理员
            if dangqianyonghu.user_type != 'admin':
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 5. 验证管理员扩展表是否存在
            try:
                guanliyuan = dangqianyonghu.admin_profile
            except AttributeError:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 6. 验证支付密码（对比openid）
            if pay_password != dangqianyonghu.openid:
                return Response(
                    {'code': 401, 'message': '支付密码错误', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 7. 查询订单主表
            try:
                from dingdan.models import Dingdan, DingdanShangjia, Tuikuanjilu
                dingdan_obj = Dingdan.objects.get(dingdan_id=dingdan_id)
            except Dingdan.DoesNotExist:
                return Response(
                    {'code': 404, 'message': '订单不存在', 'data': None},
                    status=status.HTTP_404_NOT_FOUND
                )

            # 8. 验证订单状态为4（退款审核中）

            # 8. 验证订单状态是否为允许退款的状态
            allowed_statuses = [4, 8, 1, 2, 7]  # 允许退款的状态：退款审核中、已下单、结算中、进行中、指定中
            if dingdan_obj.zhuangtai not in allowed_statuses:
                return Response(
                    {
                        'code': 400,
                        'message': f'订单当前状态不允许退款。允许退款的状态为：退款审核中(4)、已下单(8)、结算中(1)、进行中(2)、指定中(7)',
                        'data': None
                    },
                    status=status.HTTP_400_BAD_REQUEST
                )
            '''if dingdan_obj.zhuangtai != 4:
                return Response(
                    {'code': 400, 'message': '订单状态不是退款审核中', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )'''

            # 9. 验证订单为商家发单
            if dingdan_obj.fadan_pingtai != 2:
                return Response(
                    {'code': 400, 'message': '此接口只处理商家发单的退款', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 10. 获取订单的重要字段
            jiedan_dashou_id = dingdan_obj.jiedan_dashou_id  # 接单打手ID
            jine = dingdan_obj.jine  # 订单金额（不是打手分成）

            # 11. 验证订单金额是否存在
            if jine is None:
                return Response(
                    {'code': 400, 'message': '订单缺少订单金额', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 12. 获取商家ID
            try:
                shangjia_kuozhan = dingdan_obj.shangjia_kuozhan
                shangjia_id = shangjia_kuozhan.shangjia_id
            except DingdanShangjia.DoesNotExist:
                return Response(
                    {'code': 400, 'message': '订单商家信息不存在', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 13. 使用事务保证数据一致性
            with transaction.atomic():
                # 13.1 更新订单状态为5（已退款）
                dingdan_obj.zhuangtai = 5
                dingdan_obj.save()

                # 13.2 更新打手扩展表（退款订单总量+1）
                if jiedan_dashou_id:
                    try:
                        # 查询打手用户主表
                        dashou_user = UserMain.objects.get(
                            yonghuid=jiedan_dashou_id,
                            #user_type='dashou'
                        )

                        # 获取打手扩展表
                        dashou_profile = dashou_user.dashou_profile

                        # ✅ 确认字段：tuikuanliang 退款订单总量
                        dashou_profile.tuikuanliang += 1
                        dashou_profile.zhuangtai = 1

                        dashou_profile.save()
                        logger.info(f"同意退款成功，打手{jiedan_dashou_id}退款订单+1")

                    except UserMain.DoesNotExist:
                        # 打手用户不存在，记录日志但不影响操作
                        logger.warning(f"同意退款：打手{jiedan_dashou_id}不存在，跳过打手更新")
                    except AttributeError:
                        # 打手扩展表不存在，记录日志但不影响操作
                        logger.warning(f"同意退款：打手{jiedan_dashou_id}扩展信息不存在，跳过打手更新")

                # 13.3 更新商家扩展表
                if shangjia_id:
                    try:
                        # 查询商家用户主表
                        shangjia_user = UserMain.objects.get(
                            yonghuid=shangjia_id,
                            #user_type='shop'
                        )

                        # 获取商家扩展表
                        shangjia_profile = shangjia_user.shop_profile

                        # ✅ 确认字段：tuikuan 退款订单总量
                        shangjia_profile.tuikuan += 1

                        # ✅ 确认字段：yue 商家余额（加上订单金额）
                        shangjia_profile.yue += jine

                        shangjia_profile.save()
                        logger.info(f"同意退款成功，商家{shangjia_id}退款订单+1，余额增加：{jine}")

                    except UserMain.DoesNotExist:
                        # 商家用户不存在，记录日志但不影响操作
                        logger.warning(f"同意退款：商家{shangjia_id}不存在，跳过商家更新")
                    except AttributeError:
                        # 商家扩展表不存在，记录日志但不影响操作
                        logger.warning(f"同意退款：商家{shangjia_id}扩展信息不存在，跳过商家更新")

                # 13.4 更新退款记录表
                try:
                    # 查询退款记录表
                    tuikuan_jilu = Tuikuanjilu.objects.get(dingdan_id=dingdan_id)

                    # ✅ 确认字段：sqzhuangtai 申请状态，改为1（成功）
                    tuikuan_jilu.sqzhuangtai = 1

                    # 可以添加同意理由字段，如：tongyi_liyou
                    # tuikuan_jilu.tongyi_liyou = tuikuan_liyou

                    # ✅ 确认字段：chuliid 处理人ID（使用管理员账号，即手机号）
                    tuikuan_jilu.chuliid = qianzhanghao

                    tuikuan_jilu.save()
                    logger.info(f"同意退款成功，更新退款记录表，订单：{dingdan_id}")

                except Tuikuanjilu.DoesNotExist:
                    # 退款记录表不存在，记录日志但不影响主流程
                    logger.warning(f"同意退款：订单{dingdan_id}退款记录不存在，跳过更新")

            # 14. 返回成功响应
            return Response({
                'code': 0,
                'message': '同意退款成功',
                'data': None
            })

        except Exception as e:
            logger.error(f"同意退款接口异常: {str(e)}", exc_info=True)
            return Response(
                {'code': 500, 'message': '服务器内部错误', 'data': None},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )


# dingdan/views.py
import logging
import time
import random
import hashlib
import requests
import xml.etree.ElementTree as ET
from decimal import Decimal
from django.db import transaction
from django.conf import settings
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from rest_framework.parsers import JSONParser

from yonghu.models import UserMain, UserDashou, UserBoss
from dingdan.models import Dingdan, DingdanPingtai, Tuikuanjilu
from peizhi.models import Szjilu

logger = logging.getLogger(__name__)


class AdTongYiTuiKuanPingTai(APIView):
    """
    后台同意退款接口（平台发单）
    权限: JWT Token认证 + 管理员身份验证 + 密码验证
    前端调用: POST /dingdan/adddpttk
    参数: {
        "zhanghao": "管理员账号",
        "dingdan_id": "订单ID",
        "tuikuan_liyou": "退款理由（可选）",
        "pay_password": "支付密码（openid）"
    }
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        try:
            # 1. 获取前端参数
            qianzhanghao = request.data.get('zhanghao', '').strip()
            dingdan_id = request.data.get('dingdan_id', '').strip()
            tuikuan_liyou = request.data.get('tuikuan_liyou', '').strip()
            pay_password = request.data.get('pay_password', '').strip()

            if not qianzhanghao or not dingdan_id or not pay_password:
                return Response(
                    {'code': 400, 'message': '参数不完整', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 2. JWT Token身份验证
            dangqianyonghu = request.user

            # 3. 验证手机号是否匹配
            if str(getattr(dangqianyonghu, 'phone', '')) != qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 4. 验证用户类型是否为管理员
            if dangqianyonghu.user_type != 'admin':
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 5. 验证管理员扩展表是否存在
            try:
                guanliyuan = dangqianyonghu.admin_profile
            except AttributeError:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 6. 验证支付密码（对比openid）
            if pay_password != dangqianyonghu.openid:
                return Response(
                    {'code': 401, 'message': '支付密码错误', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 7. 查询订单主表（加锁）
            with transaction.atomic():
                try:
                    dingdan_obj = Dingdan.objects.select_related('pingtai_kuozhan').select_for_update().get(dingdan_id=dingdan_id)
                except Dingdan.DoesNotExist:
                    return Response(
                        {'code': 404, 'message': '订单不存在', 'data': None},
                        status=status.HTTP_404_NOT_FOUND
                    )

                # 8. 验证订单状态为1、7、2、8、4（允许退款的状态）
                if dingdan_obj.zhuangtai not in [1, 7, 2, 8, 4]:
                    return Response(
                        {'code': 400, 'message': '订单状态不允许退款', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                # 9. 验证订单为平台发单
                if dingdan_obj.fadan_pingtai != 1:
                    return Response(
                        {'code': 400, 'message': '此接口只处理平台发单的退款', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                # 10. 获取订单的重要字段
                jiedan_dashou_id = dingdan_obj.jiedan_dashou_id
                jine = dingdan_obj.jine
                if jine is None:
                    return Response(
                        {'code': 400, 'message': '订单缺少订单金额', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                # 11. 获取老板ID（从平台订单扩展表）
                if not hasattr(dingdan_obj, 'pingtai_kuozhan') or not dingdan_obj.pingtai_kuozhan:
                    return Response(
                        {'code': 400, 'message': '订单老板信息不存在', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )
                laoban_id = dingdan_obj.pingtai_kuozhan.laoban_id

                # 12. 调用微信退款接口（优先使用 wechat_transaction_id）
                transaction_id = getattr(dingdan_obj, 'wechat_transaction_id', None)
                weixin_refund_result = self.call_weixin_refund(
                    out_trade_no=dingdan_id,
                    jine=jine,
                    transaction_id=transaction_id
                )

                if not weixin_refund_result.get('success'):
                    logger.error(f"微信退款失败，订单：{dingdan_id}，错误：{weixin_refund_result.get('msg')}")
                    return Response(
                        {'code': 400, 'message': weixin_refund_result.get('msg', '退款失败')},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                # 13. 更新订单状态为5（已退款）
                dingdan_obj.zhuangtai = 5
                dingdan_obj.save()

                # 14. 更新打手扩展表
                if jiedan_dashou_id:
                    try:
                        dashou_user = UserMain.objects.get(yonghuid=jiedan_dashou_id)
                        dashou_profile = dashou_user.dashou_profile
                        dashou_profile.zhuangtai = 1  # 打手状态设为空闲
                        dashou_profile.tuikuanliang += 1
                        dashou_profile.save()
                    except (UserMain.DoesNotExist, AttributeError):
                        logger.warning(f"平台退款：打手{jiedan_dashou_id}不存在或扩展信息缺失，跳过")

                # 15. 更新老板扩展表
                if laoban_id:
                    try:
                        laoban_user = UserMain.objects.get(yonghuid=laoban_id)
                        laoban_profile = laoban_user.boss_profile
                        laoban_profile.alltui += 1
                        laoban_profile.zonge -= jine
                        if laoban_profile.zonge < 0:
                            laoban_profile.zonge = 0
                        laoban_profile.save()
                    except (UserMain.DoesNotExist, AttributeError):
                        logger.warning(f"平台退款：老板{laoban_id}不存在或扩展信息缺失，跳过")

                # 16. 更新收支记录表（id=1）
                # 12.更新退款统计



                try:

                    from dingdan.utils import update_daily_payout
                    update_daily_payout(jine)


                    szjilu_obj = Szjilu.objects.get(id=1)
                    szjilu_obj.zongsy -= jine
                    szjilu_obj.zongzc += jine
                    szjilu_obj.jrzc += jine
                    szjilu_obj.save()
                except Szjilu.DoesNotExist:
                    logger.error(f"平台退款：收支记录表(id=1)不存在，跳过")
                except Exception as e:
                    logger.error(f"更新收支记录表异常: {str(e)}")

                # 17. 更新退款记录表
                try:
                    tuikuan_jilu, created = Tuikuanjilu.objects.get_or_create(
                        dingdan_id=dingdan_id,
                        defaults={
                            'dashouid': jiedan_dashou_id if jiedan_dashou_id else '',
                            'qingqiuid': laoban_id if laoban_id else '',
                            'chuliid': qianzhanghao,
                            'liyou': tuikuan_liyou if tuikuan_liyou else '给老板退款',
                            'sqzhuangtai': 1,
                            'jine': jine,
                            'dashou_fencheng': dingdan_obj.dashou_fencheng or 0,
                            'jieshao': dingdan_obj.jieshao or '',
                            'beizhu': '给老板退款',
                            'nicheng': dingdan_obj.nicheng or '',
                        }
                    )
                    if not created:
                        tuikuan_jilu.sqzhuangtai = 1
                        if tuikuan_liyou:
                            tuikuan_jilu.liyou = tuikuan_liyou
                        tuikuan_jilu.chuliid = qianzhanghao
                        tuikuan_jilu.save()
                except Exception as e:
                    logger.error(f"更新退款记录表异常: {str(e)}")

                logger.info(f"平台退款成功，订单：{dingdan_id}，退款单号：{weixin_refund_result.get('refund_id')}")

            return Response({'code': 0, 'message': '退款处理成功', 'data': None})

        except Exception as e:
            logger.error(f"平台退款接口异常: {str(e)}", exc_info=True)
            return Response(
                {'code': 500, 'message': '服务器内部错误', 'data': None},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )

    def call_weixin_refund(self, out_trade_no, jine, transaction_id=None):
        """
        调用微信退款接口
        :param out_trade_no: 商户订单号
        :param jine: 退款金额
        :param transaction_id: 微信支付订单号（优先使用）
        :return: {'success': True/False, 'msg': '消息', 'refund_id': '退款单号'}
        """
        try:
            # 检查配置
            required_settings = ['WEIXIN_APPID', 'WEIXIN_MCHID', 'WEIXIN_SHANGHUMIYAO', 'WEIXIN_CERT_PATH', 'WEIXIN_KEY_PATH']
            for setting in required_settings:
                if not hasattr(settings, setting) or not getattr(settings, setting):
                    return {'success': False, 'msg': f'缺少微信支付配置: {setting}'}

            # 生成退款单号
            refund_id = f"TK{int(time.time())}{random.randint(1000, 9999)}"
            total_fee_in_fen = int(float(jine) * 100)

            # 构造请求参数
            refund_data = {
                'appid': settings.WEIXIN_APPID,
                'mch_id': settings.WEIXIN_MCHID,
                'nonce_str': hashlib.md5(str(time.time()).encode()).hexdigest(),
                'out_refund_no': refund_id,
                'total_fee': total_fee_in_fen,
                'refund_fee': total_fee_in_fen,
                'op_user_id': settings.WEIXIN_MCHID,
                'refund_account': 'REFUND_SOURCE_UNSETTLED_FUNDS'
            }
            # 优先使用 transaction_id，否则用 out_trade_no
            if transaction_id:
                refund_data['transaction_id'] = transaction_id
            else:
                refund_data['out_trade_no'] = out_trade_no

            # 生成签名
            sorted_params = sorted(refund_data.items())
            sign_string = '&'.join([f"{k}={v}" for k, v in sorted_params if v])
            sign_string += f"&key={settings.WEIXIN_SHANGHUMIYAO}"
            sign = hashlib.md5(sign_string.encode()).hexdigest().upper()
            refund_data['sign'] = sign

            xml_data = self.dict_to_xml(refund_data)
            url = "https://api.mch.weixin.qq.com/secapi/pay/refund"
            response = requests.post(
                url,
                data=xml_data.encode('utf-8'),
                headers={'Content-Type': 'application/xml'},
                cert=(settings.WEIXIN_CERT_PATH, settings.WEIXIN_KEY_PATH),
                timeout=30
            )

            if response.status_code == 200:
                result = self.xml_to_dict(response.content)
                if result.get('return_code') == 'SUCCESS' and result.get('result_code') == 'SUCCESS':
                    logger.info(f"微信退款成功，订单：{out_trade_no}，退款单号：{refund_id}")
                    return {'success': True, 'msg': '退款申请提交成功', 'refund_id': refund_id}
                else:
                    error_msg = result.get('err_code_des', result.get('return_msg', '退款申请失败'))
                    logger.error(f"微信退款失败，订单：{out_trade_no}，错误：{error_msg}")
                    return {'success': False, 'msg': f'微信退款失败: {error_msg}'}
            else:
                logger.error(f"微信退款接口调用失败，状态码：{response.status_code}")
                return {'success': False, 'msg': '微信退款接口调用失败'}

        except requests.exceptions.Timeout:
            logger.error(f"微信退款接口请求超时，订单：{out_trade_no}")
            return {'success': False, 'msg': '微信退款接口请求超时'}
        except Exception as e:
            logger.error(f"调用微信退款接口异常: {str(e)}")
            return {'success': False, 'msg': f'退款处理异常: {str(e)}'}

    def dict_to_xml(self, dict_data):
        xml = ["<xml>"]
        for k, v in dict_data.items():
            xml.append(f"<{k}>{v}</{k}>")
        xml.append("</xml>")
        return "".join(xml)

    def xml_to_dict(self, xml_data):
        try:
            root = ET.fromstring(xml_data)
            return {child.tag: child.text for child in root}
        except ET.ParseError as e:
            logger.error(f"XML解析失败: {str(e)}")
            return {'return_code': 'FAIL', 'return_msg': 'XML解析失败'}















logger = logging.getLogger(__name__)


class DashouHuoquLeixingView(APIView):
    """
    打手获取商品类型接口 - 抢单页面使用
    接口地址：POST /dingdan/dsqdhqddlx
    功能：返回所有正常的商品类型，已按排序权重排序

    返回格式（与前端原数据格式完全一致）:
    {
        "code": 200,
        "msg": "成功",
        "data": {
            "list": [
                {
                    "id": 1,
                    "jieshao": "王者荣耀",
                    "tupian_url": "leixing/wzry.jpg",
                    "yaoqiuleixing": null,
                    "huiyuan_id": null,
                    "yongjin": null,
                    "paixu": 100,
                    "shenhezhuangtai": 1
                },
                // ... 更多类型
            ]
        }
    }
    """

    # 🔴 使用JWT Token认证
    permission_classes = [IsAuthenticated]

    def post(self, request):
        """
        处理POST请求，返回商品类型列表

        请求参数：无特殊参数，只验证用户身份

        安全验证：
        1. JWT Token验证用户身份
        2. 只返回 shenhezhuangtai=1（正常状态）的类型
        3. 数据已排序：paixu降序 → id升序
        """
        try:
            logger.info(f"打手获取商品类型请求 - 用户ID: {request.user.yonghuid}")

            # 🔴 导入商品类型模型
            from shangpin.models import ShangpinLeixing

            # 🔴 查询所有正常状态的商品类型
            # 条件：shenhezhuangtai=1（正常状态）
            # 排序：先按 paixu 降序（数值大的在前），再按 id 升序
            leixing_queryset = ShangpinLeixing.objects.filter(
                shenhezhuangtai=1  # 🔴 只取正常状态，排除审核专用
            ).order_by('-paixu', 'id')

            # 🔴 构建返回数据列表
            leixing_list = []
            for leixing in leixing_queryset:
                leixing_list.append({
                    "id": leixing.id,
                    "jieshao": leixing.jieshao or "",
                    "tupian_url": leixing.tupian_url or "",
                    "yaoqiuleixing": leixing.yaoqiuleixing,
                    "huiyuan_id": leixing.huiyuan_id,
                    "yongjin": float(leixing.yongjin) if leixing.yongjin else None,
                    "paixu": leixing.paixu or 0,
                    "shenhezhuangtai": leixing.shenhezhuangtai or 1
                })

            # 🔴 记录日志
            logger.info(f"返回商品类型数据：{len(leixing_list)}条，用户: {request.user.yonghuid}")

            # 🔴 返回成功响应
            # 注意：保持与前端原数据格式完全一致
            return Response({
                "code": 200,
                "msg": "成功",
                "data": {
                    "list": leixing_list  # 🔴 保持原字段名 "list"
                }
            }, status=status.HTTP_200_OK)

        except Exception as e:
            # 🔴 异常处理
            logger.error(f"打手获取商品类型失败 - 用户ID: {request.user.yonghuid}, 错误: {str(e)}", exc_info=True)

            return Response({
                "code": 500,
                "msg": f"服务器内部错误: {str(e)}",
                "data": None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)











logger = logging.getLogger(__name__)


class AdJuJueJieSuan(APIView):
    """
    后台拒绝结算接口（平台发单）
    权限: JWT Token认证 + 管理员身份验证
    前端调用: POST /dingdan/adddjjjs
    参数: {
        "zhanghao": "管理员账号(手机号)",
        "dingdan_id": "订单ID",
        "tkly": "拒绝结算理由（必填）"
    }
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        try:
            # 1. 获取参数
            qianzhanghao = request.data.get('zhanghao', '').strip()
            dingdan_id = request.data.get('dingdan_id', '').strip()
            tkly = request.data.get('tkly', '').strip()

            if not all([qianzhanghao, dingdan_id, tkly]):
                return Response(
                    {'code': 400, 'message': '参数不完整（需要zhanghao, dingdan_id, tkly）', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 2. JWT用户验证
            dangqianyonghu = request.user

            # 3. 验证手机号匹配（管理员账号通常为手机号）
            if str(dangqianyonghu.phone) != qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 4. 验证用户类型为管理员
            if dangqianyonghu.user_type != 'admin':
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 5. 查询订单
            try:
                dingdan = Dingdan.objects.get(dingdan_id=dingdan_id)
            except Dingdan.DoesNotExist:
                return Response(
                    {'code': 404, 'message': '订单不存在', 'data': None},
                    status=status.HTTP_404_NOT_FOUND
                )

            # 6. 校验订单条件：平台发单（1）且状态为2或8
            if dingdan.fadan_pingtai != 1 or dingdan.zhuangtai not in [2, 8]:
                return Response(
                    {'code': 400, 'message': '仅平台发单且状态为进行中(2)或结算中(8)的订单可拒绝结算', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            jiedan_dashou_id = dingdan.jiedan_dashou_id
            if not jiedan_dashou_id:
                return Response(
                    {'code': 400, 'message': '订单暂无接单打手', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            with transaction.atomic():
                # 7. 更新订单状态为5（已退款），并保存拒绝理由
                dingdan.zhuangtai = 5
                dingdan.tkly = tkly
                dingdan.save()

                # 8. 更新打手扩展表
                try:
                    dashou_user = UserMain.objects.get(yonghuid=jiedan_dashou_id)
                    dashou_profile = dashou_user.dashou_profile
                    dashou_profile.zhuangtai = 1          # 打手状态设为正常
                    dashou_profile.tuikuanliang += 1      # 退款订单总量+1
                    dashou_profile.save()
                except (UserMain.DoesNotExist, AttributeError) as e:
                    logger.warning(f"拒绝结算：打手{jiedan_dashou_id}信息更新失败 - {str(e)}")

            return Response({'code': 0, 'message': '拒绝结算成功', 'data': None})

        except Exception as e:
            logger.error(f"拒绝结算接口异常: {str(e)}", exc_info=True)
            return Response(
                {'code': 500, 'message': '服务器内部错误', 'data': None},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )


class AdZhuanYiDaTing(APIView):
    """
    后台转移大厅接口
    权限: JWT Token认证 + 管理员身份验证
    前端调用: POST /dingdan/adddzydt
    参数: {
        "zhanghao": "管理员账号(手机号)",
        "dingdan_id": "订单ID"
    }
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        try:
            qianzhanghao = request.data.get('zhanghao', '').strip()
            dingdan_id = request.data.get('dingdan_id', '').strip()

            if not all([qianzhanghao, dingdan_id]):
                return Response(
                    {'code': 400, 'message': '参数不完整（需要zhanghao, dingdan_id）', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            dangqianyonghu = request.user

            if str(dangqianyonghu.phone) != qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            if dangqianyonghu.user_type != 'admin':
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            try:
                dingdan = Dingdan.objects.get(dingdan_id=dingdan_id)
            except Dingdan.DoesNotExist:
                return Response(
                    {'code': 404, 'message': '订单不存在', 'data': None},
                    status=status.HTTP_404_NOT_FOUND
                )

            # 校验订单状态：允许2、8、4
            if dingdan.zhuangtai not in [2, 8, 4]:
                return Response(
                    {'code': 400, 'message': '仅状态为进行中(2)、结算中(8)或退款审核(4)的订单可转移大厅', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            jiedan_dashou_id = dingdan.jiedan_dashou_id

            with transaction.atomic():
                # 更新订单：状态改为1（下单中），清空接单打手ID
                dingdan.zhuangtai = 1
                dingdan.jiedan_dashou_id = None
                dingdan.save()

                # 如果有接单打手，更新其扩展表
                if jiedan_dashou_id:
                    try:
                        dashou_user = UserMain.objects.get(yonghuid=jiedan_dashou_id)
                        dashou_profile = dashou_user.dashou_profile
                        dashou_profile.zhuangtai = 1
                        dashou_profile.tuikuanliang += 1
                        dashou_profile.save()
                    except (UserMain.DoesNotExist, AttributeError) as e:
                        logger.warning(f"转移大厅：打手{jiedan_dashou_id}信息更新失败 - {str(e)}")

            return Response({'code': 0, 'message': '转移大厅成功', 'data': None})

        except Exception as e:
            logger.error(f"转移大厅接口异常: {str(e)}", exc_info=True)
            return Response(
                {'code': 500, 'message': '服务器内部错误', 'data': None},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )


class AdQuXiaoZhiDing(APIView):
    """
    后台取消指定接口
    权限: JWT Token认证 + 管理员身份验证
    前端调用: POST /dingdan/adddqxzd
    参数: {
        "zhanghao": "管理员账号(手机号)",
        "dingdan_id": "订单ID"
    }
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        try:
            qianzhanghao = request.data.get('zhanghao', '').strip()
            dingdan_id = request.data.get('dingdan_id', '').strip()

            if not all([qianzhanghao, dingdan_id]):
                return Response(
                    {'code': 400, 'message': '参数不完整（需要zhanghao, dingdan_id）', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            dangqianyonghu = request.user

            if str(dangqianyonghu.phone) != qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            if dangqianyonghu.user_type != 'admin':
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            try:
                dingdan = Dingdan.objects.get(dingdan_id=dingdan_id)
            except Dingdan.DoesNotExist:
                return Response(
                    {'code': 404, 'message': '订单不存在', 'data': None},
                    status=status.HTTP_404_NOT_FOUND
                )

            # 校验订单状态：必须为7（指定中）
            if dingdan.zhuangtai != 7:
                return Response(
                    {'code': 400, 'message': '仅状态为指定中(7)的订单可取消指定', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            with transaction.atomic():
                # 更新订单：状态改为1（下单中），清空指定ID
                dingdan.zhuangtai = 1
                dingdan.zhiding_id = None
                dingdan.save()

            return Response({'code': 0, 'message': '取消指定成功', 'data': None})

        except Exception as e:
            logger.error(f"取消指定接口异常: {str(e)}", exc_info=True)
            return Response(
                {'code': 500, 'message': '服务器内部错误', 'data': None},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )















from peizhi.models import Club ,OrderTypeMapping

logger = logging.getLogger(__name__)

'''class PartnerSyncOrderView(APIView):
    """
    接收对方平台派单通知接口
    对方平台商家派单成功后，异步调用此接口，将订单信息同步过来。
    请求方式: POST
    接口地址: /dingdan/partner_sync_order
    """
    throttle_classes = [AnonRateThrottle]
    permission_classes = [AllowAny]
    parser_classes = [JSONParser]

    def post(self, request):
        # 1. 验证 token
        token = request.data.get('token')
        if token != settings.CROSS_PLATFORM_TOKEN:
            logger.warning(f"跨平台派单 token 无效: {token}")
            return Response({'code': 403, 'message': 'Invalid token'}, status=status.HTTP_403_FORBIDDEN)

        # 2. 获取必要参数
        our_club_id = request.data.get('our_club_id')          # 对方平台发送的我方俱乐部ID（即对方在 Club 表中 partner_club_id）
        partner_club_id = request.data.get('partner_club_id')  # 对方平台的俱乐部ID（对方自己的ID）
        partner_order_id = request.data.get('partner_order_id')
        jine = request.data.get('jine')
        dashou_fencheng = request.data.get('dashou_fencheng')
        jieshao = request.data.get('jieshao')
        beizhu = request.data.get('beizhu', '')
        create_time_str = request.data.get('create_time')
        nicheng = request.data.get('nicheng')
        leixing_id = request.data.get('leixing_id')            # 对方平台的商品类型ID

        # 必需字段校验
        required_fields = [our_club_id, partner_club_id, partner_order_id, jine, dashou_fencheng,
                           jieshao, create_time_str, nicheng, leixing_id]
        if not all(required_fields):
            logger.error(f"跨平台派单参数缺失: {request.data}")
            return Response({'code': 400, 'message': 'Missing required parameters'}, status=status.HTTP_400_BAD_REQUEST)

        # 3. 验证我方俱乐部是否存在且同意接收订单
        # 注意：our_club_id 是对方发送过来的，代表我方在对方系统中的ID，所以用 partner_club_id 匹配
        try:
            my_club = Club.objects.get(partner_club_id=our_club_id)
        except Club.DoesNotExist:
            logger.warning(f"我方俱乐部不存在，partner_club_id={our_club_id}")
            return Response({'code': 404, 'message': 'Club not found'}, status=status.HTTP_404_NOT_FOUND)

        if not my_club.is_receive_enabled:
            logger.warning(f"我方俱乐部 {my_club.club_id} 未同意接收订单")
            return Response({'code': 403, 'message': 'Receiving not allowed'}, status=status.HTTP_403_FORBIDDEN)

        # 4. 查找订单类型映射
        try:
            mapping = OrderTypeMapping.objects.get(
                partner_club_id=our_club_id,
                partner_type_id=leixing_id
            )
            our_type_id = mapping.our_type_id
        except OrderTypeMapping.DoesNotExist:
            logger.error(f"未找到订单类型映射: 对方俱乐部={our_club_id}, 对方类型ID={leixing_id}")
            return Response({'code': 400, 'message': 'Order type mapping not found'}, status=status.HTTP_400_BAD_REQUEST)

        # 5. 获取我方商品类型信息（用于获取会员ID、佣金等）
        try:
            our_leixing = ShangpinLeixing.objects.get(id=our_type_id)
        except ShangpinLeixing.DoesNotExist:
            logger.error(f"我方商品类型不存在: {our_type_id}")
            return Response({'code': 400, 'message': 'Local product type not found'}, status=status.HTTP_400_BAD_REQUEST)

        # 6. 幂等检查：如果已存在相同 partner_order_id 的订单，直接返回
        existing = Dingdan.objects.filter(partner_order_id=partner_order_id).first()
        if existing:
            logger.info(f"跨平台派单幂等返回: partner_order_id={partner_order_id} 已存在")
            return Response({
                'code': 0,
                'data': {'local_order_id': existing.dingdan_id}
            })

        # 7. 生成我方订单ID
        def generate_dingdan_id():
            import time, random, os
            timestamp = int(time.time() * 1000)
            process_id = os.getpid() % 1000
            random_num = random.randint(1000, 9999)
            return f"SJ{timestamp}{process_id:03d}{random_num}"

        # 8. 获取代理商家头像（用于订单图片）
        agent_user = UserMain.objects.filter(yonghuid=settings.AGENT_SHANGJIA_ID).first()
        agent_avatar = agent_user.avatar if agent_user else ''

        # 9. 事务创建订单
        try:
            with transaction.atomic():
                new_id = generate_dingdan_id()
                # 创建主订单
                dingdan = Dingdan.objects.create(
                    dingdan_id=new_id,
                    zhuangtai=1,                     # 普通订单（默认）
                    fadan_pingtai=2,                 # 商家发单
                    jine=jine,
                    dashou_fencheng=dashou_fencheng,
                    jieshao=jieshao,
                    beizhu=beizhu,
                    create_time=create_time_str,
                    yaoqiuleixing=our_leixing.yaoqiuleixing,
                    nicheng=nicheng,
                    huiyuan_id=our_leixing.huiyuan_id,
                    yongjin=our_leixing.yongjin,
                    leixing_id=our_type_id,
                    partner_order_id=partner_order_id,
                    is_cross=1,
                    dispatch_type=2,                 # 对方派给我方
                    partner_club_id=our_club_id, # 对方的俱乐部ID
                    tupian=agent_avatar,             # 使用代理商家头像作为订单图片
                )
                # 创建商家扩展表（使用代理商家）
                DingdanShangjia.objects.create(
                    dingdan=dingdan,
                    shangjia_id=settings.AGENT_SHANGJIA_ID,
                    sjnicheng='跨平台代理'
                )
            logger.info(f"跨平台订单同步成功: partner_order_id={partner_order_id}, local_id={new_id}")
            return Response({
                'code': 0,
                'data': {'local_order_id': new_id}
            },status=200)
        except Exception as e:
            logger.error(f"跨平台订单同步失败: {str(e)}", exc_info=True)
            return Response({'code': 500, 'message': 'Internal error'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)'''




class PartnerSyncOrderView(APIView):
    """
    接收对方平台派单通知接口
    对方平台商家派单成功后，异步调用此接口，将订单信息同步过来。
    """
    throttle_classes = [AnonRateThrottle]
    permission_classes = [AllowAny]
    parser_classes = [JSONParser]

    def post(self, request):
        # 1. 验证 token
        token = request.data.get('token')
        if token != settings.CROSS_PLATFORM_TOKEN:
            logger.warning(f"跨平台派单 token 无效: {token}")
            return Response({'code': 403, 'message': 'Invalid token'}, status=status.HTTP_403_FORBIDDEN)

        # 2. 获取必要参数
        our_club_id = request.data.get('our_club_id')          # 对方平台发送的我方俱乐部ID（即我方在对方表中的 partner_club_id）
        partner_club_id = request.data.get('partner_club_id')  # 对方平台的俱乐部ID（对方自己的ID）
        partner_order_id = request.data.get('partner_order_id')
        jine = request.data.get('jine')
        dashou_fencheng = request.data.get('dashou_fencheng')
        jieshao = request.data.get('jieshao')
        beizhu = request.data.get('beizhu', '')
        create_time_str = request.data.get('create_time')
        nicheng = request.data.get('nicheng')
        leixing_id = request.data.get('leixing_id')            # 对方平台的商品类型ID
        partner_yonghu_id = request.data.get('user_id')  # 对方下单用户ID

        # 必需字段校验
        required_fields = [our_club_id, partner_club_id, partner_order_id, jine, dashou_fencheng,
                           jieshao, create_time_str, nicheng, leixing_id]
        if not all(required_fields):
            logger.error(f"跨平台派单参数缺失: {request.data}")
            return Response({'code': 400, 'message': 'Missing required parameters'}, status=status.HTTP_400_BAD_REQUEST)

        # 3. 验证我方俱乐部是否存在且同意接收订单
        try:
            my_club = Club.objects.get(partner_club_id=our_club_id)
        except Club.DoesNotExist:
            logger.warning(f"我方俱乐部不存在，partner_club_id={our_club_id}")
            return Response({'code': 404, 'message': 'Club not found'}, status=status.HTTP_404_NOT_FOUND)

        if not my_club.is_receive_enabled:
            logger.warning(f"我方俱乐部 {my_club.club_id} 未同意接收订单")
            return Response({'code': 403, 'message': 'Receiving not allowed'}, status=status.HTTP_403_FORBIDDEN)

        # 4. 查找订单类型映射
        try:
            mapping = OrderTypeMapping.objects.get(
                partner_club_id=our_club_id,      # 对方在我方的标识
                partner_type_id=leixing_id
            )
            our_type_id = mapping.our_type_id
        except OrderTypeMapping.DoesNotExist:
            logger.error(f"未找到订单类型映射: 对方俱乐部={our_club_id}, 对方类型ID={leixing_id}")
            return Response({'code': 400, 'message': 'Order type mapping not found'}, status=status.HTTP_400_BAD_REQUEST)

        # 5. 获取我方商品类型信息（用于获取会员ID、佣金等）
        try:
            our_leixing = ShangpinLeixing.objects.get(id=our_type_id)
        except ShangpinLeixing.DoesNotExist:
            logger.error(f"我方商品类型不存在: {our_type_id}")
            return Response({'code': 400, 'message': 'Local product type not found'}, status=status.HTTP_400_BAD_REQUEST)

        # 6. 幂等检查：如果已存在相同 partner_order_id 的订单，直接返回（附带 status='existed'）
        existing = Dingdan.objects.filter(partner_order_id=partner_order_id).first()
        if existing:
            logger.info(f"跨平台派单幂等返回: partner_order_id={partner_order_id} 已存在")
            return Response({
                'code': 0,
                'data': {
                    'local_order_id': existing.dingdan_id,
                    'status': 'existed'          # 明确告知已存在
                }
            })

        # 7. 生成我方订单ID（确保唯一性）
        def generate_dingdan_id():
            timestamp = int(time.time() * 1000)
            process_id = os.getpid() % 1000
            random_num = random.randint(1000, 9999)
            return f"SJ{timestamp}{process_id:03d}{random_num}"

        # 8. 获取代理商家头像（用于订单图片）
        agent_user = UserMain.objects.filter(yonghuid=settings.AGENT_SHANGJIA_ID).first()
        agent_avatar = agent_user.avatar if agent_user else ''

        # 9. 计算我方实际打手分成金额：对方传来的打手分成 × 我方接收费率
        try:
            actual_dashou_fencheng = Decimal(dashou_fencheng) * my_club.receive_rate
        except Exception:
            actual_dashou_fencheng = Decimal(dashou_fencheng)

        # 10. 事务创建订单
        try:
            with transaction.atomic():
                new_id = generate_dingdan_id()
                # 创建主订单
                dingdan = Dingdan.objects.create(
                    dingdan_id=new_id,
                    zhuangtai=1,                     # 普通订单（待接单）
                    fadan_pingtai=2,                 # 商家发单
                    jine=jine,                       # 原始订单金额
                    dashou_fencheng=actual_dashou_fencheng,  # 调整后的打手分成
                    jieshao=jieshao,
                    beizhu=beizhu,
                    create_time=create_time_str,
                    yaoqiuleixing=our_leixing.yaoqiuleixing,
                    nicheng=nicheng,
                    huiyuan_id=our_leixing.huiyuan_id,
                    yongjin=our_leixing.yongjin,
                    leixing_id=our_type_id,
                    partner_order_id=partner_order_id,     # 存储对方订单ID
                    is_cross=1,
                    dispatch_type=2,                       # 对方派单
                    partner_club_id=our_club_id,       # 对方俱乐部ID
                    tupian=agent_avatar,                   # 使用代理商家头像作为订单图片
                )
                # 创建商家扩展表（使用代理商家）
                DingdanShangjia.objects.create(
                    dingdan=dingdan,
                    shangjia_id=settings.AGENT_SHANGJIA_ID,
                    sjnicheng='跨平台代理',
                    partner_yonghu_id=partner_yonghu_id or '',
                )

            # 成功创建后更新每日派单统计（方向=对方派单）
            try:
                update_daily_dispatch_stat(
                    direction=2,  # 对方派单
                    partner_club_id=our_club_id,
                    dispatch_amount=Decimal(jine),  # 统计使用原始订单金额

                )
            except Exception as e:
                logger.error(f"更新派单统计失败: {e}", exc_info=True)

            logger.info(f"跨平台订单同步成功: partner_order_id={partner_order_id}, local_id={new_id}")
            return Response({
                'code': 0,
                'data': {
                    'local_order_id': new_id,
                    'status': 'created'
                }
            })

        except Exception as e:
            logger.error(f"跨平台订单同步失败: {str(e)}", exc_info=True)
            return Response({'code': 500, 'message': 'Internal error'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)






from dingdan.utils import update_daily_dispatch_stat

logger = logging.getLogger(__name__)






class PartnerCheckClaimView(APIView):
    """
    接收对方平台抢单询问（对方打手抢我方派出的订单）
    如果允许抢单：
        1. 订单状态改为2（已接单）
        2. 记录对方打手ID、对方俱乐部ID、对方订单ID
        3. 更新派单成交统计（success_count/success_amount）
    """
    throttle_classes = [AnonRateThrottle]
    permission_classes = [AllowAny]
    parser_classes = [JSONParser]

    def post(self, request):
        token = request.data.get('token')
        if token != settings.CROSS_PLATFORM_TOKEN:
            logger.warning(f"token无效: {token}")
            return Response({'code': 403, 'message': 'Invalid token'}, status=status.HTTP_403_FORBIDDEN)

        wofangdingdan_id = request.data.get('wofangdingdan_id')
        partner_order_id = request.data.get('partner_order_id')
        our_club_id = request.data.get('our_club_id')
        dashou_id = request.data.get('dashou_id')
        sj_id = request.data.get('sj_id')

        if not all([wofangdingdan_id, partner_order_id, our_club_id, dashou_id, sj_id]):
            logger.error(f"参数缺失: {request.data}")
            return Response({'code': 400, 'message': 'Missing parameters'})

        try:
            with transaction.atomic():
                # 查询我方俱乐部配置
                try:
                    club = Club.objects.select_for_update().get(partner_club_id=our_club_id)
                except Club.DoesNotExist:
                    logger.warning(f"俱乐部配置不存在 partner_club_id={our_club_id}")
                    return Response({'code': 0, 'data': {'can_claim': False}})

                if not club.is_interop_enabled:
                    logger.warning(f"俱乐部 {club.club_id} 未开启互通")
                    return Response({'code': 0, 'data': {'can_claim': False}})

                # 锁定订单
                try:
                    order = Dingdan.objects.select_for_update().get(dingdan_id=wofangdingdan_id)
                except Dingdan.DoesNotExist:
                    logger.warning(f"订单不存在: {wofangdingdan_id}")
                    return Response({'code': 404, 'message': 'Order not found'}, status=status.HTTP_404_NOT_FOUND)

                # 只有状态1可抢
                if order.zhuangtai != 1:
                    logger.info(f"订单 {order.dingdan_id} 状态 {order.zhuangtai} 不可抢")
                    return Response({'code': 0, 'data': {'can_claim': False}})

                # 商品类型检查
                try:
                    leixing = ShangpinLeixing.objects.get(id=order.leixing_id)
                except ShangpinLeixing.DoesNotExist:
                    logger.warning(f"商品类型不存在: {order.leixing_id}")
                    return Response({'code': 0, 'data': {'can_claim': False}})

                if not leixing.is_cross_enabled:
                    logger.warning(f"商品类型 {leixing.jieshao} 未开启跨平台")
                    return Response({'code': 0, 'data': {'can_claim': False}})

                # 执行抢单：状态改为2（已接单）
                order.zhuangtai = 2
                order.jiedan_dashou_id = dashou_id
                order.partner_club_id = our_club_id
                order.partner_order_id = partner_order_id
                if order.is_cross != 1:
                    order.is_cross = 1
                # dispatch_type 保持原值（1-我方派单），不变
                order.save()

                # 更新派单成交统计（我方派单被成功接单）
                update_daily_dispatch_stat(
                    direction=1,
                    partner_club_id=our_club_id,
                    claimed_amount=order.jine,

                )

                logger.info(f"对方抢单成功: 订单 {order.dingdan_id}, 对方打手 {dashou_id}")
                return Response({'code': 0, 'data': {'can_claim': True}})

        except Exception as e:
            logger.error(f"异常: {e}", exc_info=True)
            return Response({'code': 500, 'message': 'Internal error'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


'''class PartnerCheckClaimView(APIView):
    """
    接收对方平台抢单询问接口
    对方平台打手抢单前，调用此接口询问订单是否可抢。
    请求方式: POST
    接口地址: /dingdan/partner_check_claim
    请求参数:
        token: 认证令牌
        partner_order_id: 对方平台订单ID（即我方记录的 partner_order_id）
        partner_club_id: 对方俱乐部ID（对方在我方系统中的标识）
        dashou_id: 对方平台打手ID
        sj_id: 对方平台商家ID（带前缀，如 SjAGENT001）
    返回:
        code: 0成功
        data: {
            can_claim: true/false
        }
    注意：此接口会原子地检查并更新订单状态，必须使用行锁。
    """
    throttle_classes = [AnonRateThrottle]
    permission_classes = [AllowAny]
    parser_classes = [JSONParser]

    def post(self, request):
        # 1. 验证 token
        token = request.data.get('token')
        if token != settings.CROSS_PLATFORM_TOKEN:
            logger.warning(f"跨平台抢单询问 token 无效: {token}")
            return Response({'code': 403, 'message': 'Invalid token'}, status=status.HTTP_403_FORBIDDEN)

        # 2. 获取必要参数
        duifangdingdan_id = request.data.get('wofangdingdan_id')
        partner_order_id = request.data.get('partner_order_id')    # 我方订单ID
        partner_club_id = request.data.get('our_club_id')      # 对方俱乐部ID
        dashou_id = request.data.get('dashou_id')                  # 对方打手ID
        sj_id = request.data.get('sj_id')                          # 对方商家ID（带前缀，如 SjAGENT001）

        if not all([partner_order_id, partner_club_id, dashou_id, sj_id]):
            logger.error(f"跨平台抢单询问参数缺失: {request.data}")
            return Response({'code': 400, 'message': 'Missing parameters'}, status=status.HTTP_400_BAD_REQUEST)

        try:
            with transaction.atomic():
                # 3. 查询我方俱乐部配置（通过对方的 partner_club_id）
                try:
                    club = Club.objects.select_for_update().get(partner_club_id=partner_club_id)
                except Club.DoesNotExist:
                    logger.warning(f"跨平台抢单询问: 我方俱乐部配置不存在 partner_club_id={partner_club_id}")
                    return Response({'code': 404, 'message': 'Club not found'}, status=status.HTTP_404_NOT_FOUND)

                # 检查俱乐部是否已开启平台互通（我方同意接收对方订单）
                if not club.is_interop_enabled:
                    logger.warning(f"俱乐部 {club.club_id} 未开启接收跨平台订单，拒绝抢单")
                    return Response({'code': 0, 'data': {'can_claim': False}})

                # 4. 查询订单并锁定
                try:
                    order = Dingdan.objects.select_for_update().get(dingdan_id=partner_order_id)
                except Dingdan.DoesNotExist:
                    logger.warning(f"跨平台抢单询问: 订单不存在 dingdan_id={partner_order_id}")
                    return Response({'code': 404, 'message': 'Order not found'}, status=status.HTTP_404_NOT_FOUND)

                # 5. 检查订单状态（必须为1）
                if order.zhuangtai != 1:
                    logger.info(f"跨平台抢单失败: 订单状态 {order.zhuangtai}，不可抢")
                    return Response({'code': 0, 'data': {'can_claim': False}})

                # 6. 检查订单对应的商品类型是否支持跨平台抢单
                try:
                    leixing = ShangpinLeixing.objects.get(id=order.leixing_id)
                except ShangpinLeixing.DoesNotExist:
                    logger.warning(f"订单 {order.dingdan_id} 的商品类型 {order.leixing_id} 不存在")
                    return Response({'code': 0, 'data': {'can_claim': False}})

                if not leixing.is_cross_enabled:
                    logger.warning(f"商品类型 {leixing.jieshao} 未开启跨平台抢单")
                    return Response({'code': 0, 'data': {'can_claim': False}})

                # 7. 所有检查通过，执行抢单操作
                # 更新订单主表
                order.zhuangtai = 2                     # 已接单
                order.jiedan_dashou_id = dashou_id       # 对方打手ID
                order.is_cross = 1                       # 标记为跨平台订单
                order.dispatch_type = 1                  # 我方派单，对方抢单
                order.partner_club_id = partner_club_id  # 记录对方俱乐部ID
                order.partner_order_id = duifangdingdan_id#记录对方订单id
                # 存储对方商家ID（带前缀）到商家扩展表的 shangjia_id（如果原来有则更新）
                # 注意：商家扩展表已存在，需要更新或创建？原订单可能已有 shangjia_kuozhan，我们直接更新
                order.save()

                # 8. 记录每日派单统计（使用新统计函数，不再更新 Club 表）
                fencheng = order.dashou_fencheng or Decimal('0.00')
                amount = fencheng * club.dashou_rate
                update_daily_dispatch_stat(
                    dispatch_date=timezone.now().date(),
                    direction=2,  # 对方派单
                    partner_club_id=partner_club_id,
                    amount=amount,
                    count=1
                )
                # 9. 返回成功，告知对方可以抢单
                logger.info(f"跨平台抢单成功: 订单 {order.dingdan_id}, 对方打手 {dashou_id}, 俱乐部 {club.club_id}")
                return Response({'code': 0, 'data': {'can_claim': True}})




        except Exception as e:
            logger.error(f"跨平台抢单询问异常: {str(e)}", exc_info=True)
            return Response({'code': 500, 'message': 'Internal error'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)'''









'''class PartnerNotifyClaimView(APIView):
    """
    接收对方平台抢单成功通知接口
    对方平台打手抢单成功后，调用此接口，我方处理本地订单。
    请求方式: POST
    接口地址: /dingdan/partner_notify_claim
    请求参数:
        token: 认证令牌，需与settings.CROSS_PLATFORM_TOKEN一致
        order_id: 对方平台的订单ID（即我方记录的 partner_order_id）
    返回:
        code: 0成功，其他失败
        message: 描述信息
    """
    throttle_classes = [AnonRateThrottle]
    permission_classes = [AllowAny]
    parser_classes = [JSONParser]

    def post(self, request):
        # 1. 验证token
        token = request.data.get('token')
        if token != settings.CROSS_PLATFORM_TOKEN:
            logger.warning(f"跨平台抢单通知 token 无效: {token}")
            return Response({'code': 403, 'message': 'Invalid token'}, status=status.HTTP_403_FORBIDDEN)

        order_id = request.data.get('local_order_id')  # 对方平台的订单ID（即我方的 partner_order_id）
        if not order_id:
            logger.error("跨平台抢单通知参数缺失: order_id")
            return Response({'code': 400, 'message': 'Missing order_id'}, status=status.HTTP_400_BAD_REQUEST)

        try:
            with transaction.atomic():
                # 2. 根据 partner_order_id 查找订单
                order = Dingdan.objects.select_for_update().get(partner_order_id=order_id)

                # 3. 根据订单状态处理
                if order.zhuangtai == 1:
                    # 订单未被抢，直接删除（包括关联的商家扩展表）
                    # 先删除扩展表
                    DingdanShangjia.objects.filter(dingdan=order).delete()
                    # 再删除主订单
                    order.delete()
                    logger.info(f"跨平台抢单通知：订单状态为1，已删除，partner_order_id={order_id}")
                    return Response({'code': 0, 'message': 'Order deleted'})
                else:
                    # 订单状态不是1（已被抢或异常），改为状态15（异常订单）
                    order.zhuangtai = 15
                    order.save()
                    logger.info(f"跨平台抢单通知：订单状态异常，已改为15，partner_order_id={order_id}")
                    return Response({'code': 0, 'message': 'Order marked as abnormal'})

        except Dingdan.DoesNotExist:
            logger.warning(f"跨平台抢单通知：订单不存在 partner_order_id={order_id}")
            return Response({'code': 404, 'message': 'Order not found'}, status=status.HTTP_404_NOT_FOUND)
        except Exception as e:
            logger.error(f"跨平台抢单通知异常: {str(e)}", exc_info=True)
            return Response({'code': 500, 'message': 'Internal error'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)'''





class PartnerNotifyClaimView(APIView):
    """
    接收对方平台抢单成功通知（对方派单被他们自己的打手抢了）
    我方根据 partner_order_id 找到订单，如果状态为1则改为20，不更新任何统计。
    """
    throttle_classes = [AnonRateThrottle]
    permission_classes = [AllowAny]
    parser_classes = [JSONParser]

    def post(self, request):
        token = request.data.get('token')
        if token != settings.CROSS_PLATFORM_TOKEN:
            logger.warning(f"token无效: {token}")
            return Response({'code': 403, 'message': 'Invalid token'}, status=status.HTTP_403_FORBIDDEN)

        partner_order_id = request.data.get('partner_order_id')
        if not partner_order_id:
            logger.error("缺少 partner_order_id")
            return Response({'code': 400, 'message': 'Missing partner_order_id'}, status=status.HTTP_400_BAD_REQUEST)

        try:
            with transaction.atomic():
                order = Dingdan.objects.select_for_update().get(partner_order_id=partner_order_id)
                # 只有状态为1（未被抢）时才改为20
                if order.zhuangtai == 1:
                    order.zhuangtai = 20
                    order.save()
                    logger.info(f"订单 {order.dingdan_id} 状态改为20（被其他俱乐部抢走）")
                else:
                    logger.info(f"订单 {order.dingdan_id} 当前状态 {order.zhuangtai}，无需修改")
                return Response({'code': 0, 'message': 'OK'})
        except Dingdan.DoesNotExist:
            logger.warning(f"订单不存在 partner_order_id={partner_order_id}")
            return Response({'code': 404, 'message': 'Order not found'}, status=status.HTTP_404_NOT_FOUND)
        except Exception as e:
            logger.error(f"异常: {e}", exc_info=True)
            return Response({'code': 500, 'message': 'Internal error'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

'''class PartnerCheckClaimView(APIView):
    """
    接收对方平台抢单询问接口
    对方平台打手抢单前，调用此接口询问订单是否可抢。
    请求方式: POST
    接口地址: /dingdan/partner_check_claim
    请求参数:
        token: 认证令牌
        partner_order_id: 对方平台订单ID（即我方记录的 partner_order_id）
        dashou_id: 对方平台打手ID
    返回:
        code: 0成功
        data: {
            can_claim: true/false  // true表示我方允许抢单，且已更新订单状态
        }
    注意：此接口会原子地检查并更新订单状态，必须使用行锁。
    """
    throttle_classes = [AnonRateThrottle]
    permission_classes = [AllowAny]
    parser_classes = [JSONParser]

    def post(self, request):
        # 1. 验证token
        token = request.data.get('token')
        if token != settings.CROSS_PLATFORM_TOKEN:
            logger.warning(f"跨平台抢单询问 token 无效: {token}")
            return Response({'code': 403, 'message': 'Invalid token'}, status=status.HTTP_403_FORBIDDEN)

        partner_order_id = request.data.get('partner_order_id')
        dashou_id = request.data.get('dashou_id')

        if not partner_order_id or not dashou_id:
            logger.error(f"跨平台抢单询问参数缺失: {request.data}")
            return Response({'code': 400, 'message': 'Missing parameters'}, status=status.HTTP_400_BAD_REQUEST)

        try:
            with transaction.atomic():
                # 使用 select_for_update 锁定订单行，防止并发
                order = Dingdan.objects.select_for_update().get(dingdan_id=partner_order_id)

                # 检查订单状态是否为1（待抢）
                if order.zhuangtai == 1:
                    # 允许抢单，更新订单
                    order.zhuangtai = 2
                    order.jiedan_dashou_id = dashou_id
                    order.is_cross = 1  # 标记为被跨平台抢单
                    order.save()
                    logger.info(f"跨平台抢单成功: dingdan_id={partner_order_id}, 被对方打手 {dashou_id} 抢走")
                    return Response({'code': 0, 'data': {'can_claim': True}})
                else:
                    # 订单已被抢，不可抢
                    logger.info(f"跨平台抢单失败: dingdan_id={partner_order_id}, 当前状态 {order.zhuangtai}")
                    return Response({'code': 0, 'data': {'can_claim': False}})
        except Dingdan.DoesNotExist:
            logger.warning(f"跨平台抢单询问: 订单不存在 dingdan_id={partner_order_id}")
            return Response({'code': 404, 'message': 'Order not found'}, status=status.HTTP_404_NOT_FOUND)
        except Exception as e:
            logger.error(f"跨平台抢单询问异常: {str(e)}", exc_info=True)
            return Response({'code': 500, 'message': 'Internal error'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)'''










class PartnerRefundNotifyView(APIView):
    """
    接收对方平台退款通知接口
    对方平台商家申请退款时，调用此接口通知我方，我方将本地对应订单改为退款状态。
    请求方式: POST
    接口地址: /dingdan/partner_refund_notify
    请求参数:
        token: 认证令牌，需与settings.CROSS_PLATFORM_TOKEN一致
        order_id: 对方平台的订单ID（即我方记录的 partner_order_id）
    返回:
        code: 0成功，其他失败
        message: 描述信息
    """
    throttle_classes = [AnonRateThrottle]
    permission_classes = [AllowAny]
    parser_classes = [JSONParser]

    def post(self, request):
        # 1. 验证token
        token = request.data.get('token')
        if token != settings.CROSS_PLATFORM_TOKEN:
            logger.warning(f"跨平台退款通知 token 无效: {token}")
            return Response({'code': 403, 'message': 'Invalid token'}, status=status.HTTP_403_FORBIDDEN)

        order_id = request.data.get('order_id')  # 对方平台的订单ID（即我方的 partner_order_id）
        if not order_id:
            logger.error("跨平台退款通知参数缺失: order_id")
            return Response({'code': 400, 'message': 'Missing order_id'}, status=status.HTTP_400_BAD_REQUEST)

        try:
            with transaction.atomic():
                # 2. 根据 partner_order_id 查找订单（必须存在且为跨平台订单）
                order = Dingdan.objects.select_for_update().get(partner_order_id=order_id, is_cross=1)
                # 如果订单已完成，不允许退款
                if order.zhuangtai == 3:
                    logger.warning(f"跨平台退款通知：订单 {order_id} 已完成，不可退款")
                    return Response({'code': 400, 'message': 'Order already completed, cannot refund'},
                                    status=status.HTTP_400_BAD_REQUEST)

                # 3. 如果订单状态不是5，则改为5（已退款），并更新打手信息
                if order.zhuangtai != 5:
                    # 记录原打手ID
                    old_dashou_id = order.jiedan_dashou_id
                    if old_dashou_id:
                        try:
                            # 查询打手用户主表
                            dashou_user = UserMain.objects.get(yonghuid=old_dashou_id)
                            # 通过反向关系获取打手扩展表
                            if hasattr(dashou_user, 'dashou_profile'):
                                dashou_profile = dashou_user.dashou_profile
                                dashou_profile.zhuangtai = 1  # 恢复打手状态
                                dashou_profile.tuikuanliang += 1  # 退款订单量+1
                                dashou_profile.save()
                                logger.info(f"退款通知：打手 {old_dashou_id} 状态已恢复，退款订单+1")
                        except UserMain.DoesNotExist:
                            logger.warning(f"退款通知：打手用户不存在 {old_dashou_id}")
                        except Exception as e:
                            logger.error(f"退款通知：更新打手信息失败 {str(e)}")

                    # 更新订单状态为5
                    order.zhuangtai = 5
                    # 可选：清空接单打手ID
                    #order.jiedan_dashou_id = None
                    order.save()
                    logger.info(f"跨平台退款通知成功：订单 {order_id} 已改为退款状态")
                else:
                    logger.info(f"跨平台退款通知：订单 {order_id} 已是退款状态，无需重复处理")

                return Response({'code': 0, 'message': 'Refund processed successfully'})

        except Dingdan.DoesNotExist:
            logger.warning(f"跨平台退款通知：订单不存在或不是跨平台订单，partner_order_id={order_id}")
            return Response({'code': 404, 'message': 'Order not found'}, status=status.HTTP_404_NOT_FOUND)
        except Exception as e:
            logger.error(f"跨平台退款通知异常: {str(e)}", exc_info=True)
            return Response({'code': 500, 'message': 'Internal error'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)






class DashouXiugaiView(APIView):
    """
    打手修改订单交付内容接口
    请求方式：POST
    请求路径：/dingdan/dsxiugaidd
    权限：需携带有效JWT Token，且用户为打手身份
    请求参数：
        dingdan_id      : 订单ID（必填）
        liuyan          : 新的留言内容（可选，最长50字）
        deleted_images  : 要删除的图片URL列表（数组，每个元素为完整COS URL）
        new_images      : 新增的图片URL列表（数组，每个元素为完整COS URL）
    返回：
        成功：{"code":0,"msg":"修改成功","data":null}
        失败：返回相应错误码和提示
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        # 获取请求数据
        data = request.data
        dingdan_id = data.get('dingdan_id', '')
        liuyan = data.get('liuyan', '')
        deleted_images = data.get('deleted_images', [])
        new_images = data.get('new_images', [])

        # ---------- 参数校验 ----------
        if not dingdan_id:
            return Response({'code': 1, 'msg': '订单ID不能为空', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST)

        if not isinstance(deleted_images, list):
            return Response({'code': 2, 'msg': 'deleted_images 必须为数组', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST)

        if not isinstance(new_images, list):
            return Response({'code': 3, 'msg': 'new_images 必须为数组', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST)

        if liuyan and len(liuyan) > 50:
            return Response({'code': 4, 'msg': '留言最多50个字', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST)

        # ---------- 用户身份验证 ----------
        current_user = request.user
        yonghuid = current_user.yonghuid

        # 检查是否为打手
        try:
            dashou_profile = current_user.dashou_profile  # 假设User模型有related_name='dashou_profile'
        except UserDashou.DoesNotExist:
            return Response({'code': 5, 'msg': '用户不是打手身份', 'data': None},
                            status=status.HTTP_403_FORBIDDEN)

        # ---------- 订单查询及权限验证 ----------
        try:
            # 订单必须属于该打手，且状态为4（退款中）或8（结算中）
            dingdan = Dingdan.objects.get(
                dingdan_id=dingdan_id,
                jiedan_dashou_id=yonghuid,
                zhuangtai__in=[4, 8]  # 只允许修改退款中或结算中的订单
            )
        except Dingdan.DoesNotExist:
            return Response({'code': 6, 'msg': '订单不存在或没有修改权限', 'data': None},
                            status=status.HTTP_403_FORBIDDEN)

        # ---------- 执行修改（使用事务保证原子性） ----------
        try:
            with transaction.atomic():
                # 1. 处理删除的图片：从 Dashoutupian 表中删除记录
                if deleted_images:
                    # 根据订单ID、打手ID和图片URL删除记录
                    delete_count, _ = Dashoutupian.objects.filter(
                        dingdan_id=dingdan_id,
                        dashou=yonghuid,
                        tupian__in=deleted_images
                    ).delete()
                    # 可选：记录删除数量
                    logger.info(f"订单 {dingdan_id} 删除图片 {delete_count} 张")

                # 2. 处理新增的图片：插入新记录
                if new_images:
                    # 批量创建
                    new_records = []
                    for url in new_images:
                        new_records.append(Dashoutupian(
                            dingdan_id=dingdan_id,
                            dashou=yonghuid,
                            tupian=url,
                            create_time=timezone.now()
                        ))
                    Dashoutupian.objects.bulk_create(new_records)
                    logger.info(f"订单 {dingdan_id} 新增图片 {len(new_records)} 张")

                # 3. 更新订单留言（如果发生变化）
                # 注意：即使留言为空字符串，也允许更新，表示清空留言
                if 'liuyan' in data:  # 判断是否传了liuyan字段（可能为空字符串）
                    dingdan.dashou_liuyan = liuyan
                    dingdan.update_time = timezone.now()
                    dingdan.save(update_fields=['dashou_liuyan', 'update_time'])

            # 全部成功，返回成功响应
            return Response({
                'code': 0,
                'msg': '修改成功',
                'data': None
            }, status=status.HTTP_200_OK)

        except Exception as e:
            logger.error(f"修改订单失败: {str(e)}", exc_info=True)
            return Response({
                'code': 7,
                'msg': '服务器内部错误',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)








from django.core.exceptions import ObjectDoesNotExist
from dingdan.tongzhi_tasks import  dingdan_guangbo

class ZxsjghdsView(APIView):
    """
    商家更换打手接口
    路径：POST /dingdan/zxsjghds
    权限：仅限已认证商家（通过JWT）
    功能：
        1. 将原订单状态改为已退款(5)，释放接单打手（若有）
        2. 更新打手统计（退款量、状态、每日统计）
        3. 写入退款记录
        4. 若为跨平台订单，通知对方平台退款（必须成功）
        5. 基于原订单生成新订单（状态直接为1），复制核心数据
        6. 不操作商家余额、退款次数等（替换订单）
    """

    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        # ========== 1. 获取当前商家用户 ==========
        current_user = request.user
        try:
            yonghuid = current_user.yonghuid
        except AttributeError:
            return Response({'code': 1, 'msg': '用户认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # ========== 2. 提取订单ID ==========
        dingdan_id = request.data.get('dingdan_id', '').strip()
        if not dingdan_id:
            return Response({'code': 2, 'msg': '订单ID不能为空'}, status=status.HTTP_400_BAD_REQUEST)

        # ========== 3. 查询订单并校验权限 ==========
        try:
            # 关联查询商家扩展表，确保当前商家是该订单的发布者
            shangjia_kuozhan = DingdanShangjia.objects.select_related('dingdan').get(
                dingdan__dingdan_id=dingdan_id,
                shangjia_id=yonghuid
            )
        except DingdanShangjia.DoesNotExist:
            return Response({'code': 3, 'msg': '订单不存在或您无权操作'}, status=status.HTTP_403_FORBIDDEN)

        old_order = shangjia_kuozhan.dingdan

        # ========== 4. 状态校验（仅允许进行中或结算中） ==========
        if old_order.zhuangtai not in [2, 8]:
            return Response({'code': 4, 'msg': '当前订单状态不允许更换打手'}, status=status.HTTP_400_BAD_REQUEST)

        # ========== 5. 收集订单关键数据（用于新订单复制） ==========
        # 这些字段将在退款处理后用于创建新订单
        jine = old_order.jine
        dashou_fencheng = old_order.dashou_fencheng
        leixing_id = old_order.leixing_id
        yaoqiuleixing = old_order.yaoqiuleixing
        huiyuan_id = old_order.huiyuan_id
        yongjin = old_order.yongjin
        jieshao = old_order.jieshao
        nicheng = old_order.nicheng
        beizhu = old_order.beizhu
        user1_id = old_order.user1_id
        tupian = old_order.tupian
        fadan_pingtai = old_order.fadan_pingtai

        # 跨平台相关
        is_cross = old_order.is_cross
        partner_club_id = old_order.partner_club_id
        partner_order_id = old_order.partner_order_id
        need_notify_partner = is_cross and partner_club_id and partner_order_id

        dashou_id = old_order.jiedan_dashou_id  # 可能为空

        # ========== 6. 退款处理（事务块1：退款原订单 + 打手统计 + 跨平台通知） ==========
        try:
            with transaction.atomic():
                # 6.1 订单状态更新为已退款
                old_order.zhuangtai = 5
                old_order.save(update_fields=['zhuangtai'])

                # 6.2 释放打手
                if dashou_id:
                    try:
                        dashou_user = UserMain.objects.get(yonghuid=dashou_id)
                        dashou_profile = dashou_user.dashou_profile
                        dashou_profile.tuikuanliang = (dashou_profile.tuikuanliang or 0) + 1
                        dashou_profile.zhuangtai = 1  # 空闲
                        dashou_profile.save(update_fields=['tuikuanliang', 'zhuangtai'])
                    except (UserMain.DoesNotExist, ObjectDoesNotExist):
                        logger.warning(f"打手 {dashou_id} 不存在或扩展表缺失，跳过更新")

                # 6.3 更新退款记录
                Tuikuanjilu.objects.update_or_create(
                    dingdan_id=dingdan_id,
                    defaults={
                        'dashouid': dashou_id or '',
                        'qingqiuid': yonghuid,                # 申请人为当前商家
                        'chuliid': yonghuid,                  # 处理人也是商家自己
                        'liyou': '商家更换打手',
                        'sqzhuangtai': 1,                     # 状态 1=成功
                        'jine': jine or 0,
                        'dashou_fencheng': dashou_fencheng or 0,
                        'jieshao': jieshao or '',
                        'beizhu': '更换打手系统自动退款',
                        'nicheng': nicheng or '',
                    }
                )

                # 6.4 打手每日统计（退款行为）
                if dashou_id:
                    try:
                        from houtai.utils import update_dashou_daily_by_action
                        update_dashou_daily_by_action(
                            yonghuid=dashou_id,
                            amount=dashou_fencheng,
                            action=3  # 3=退款
                        )
                    except Exception as e:
                        logger.error(f"更新打手每日统计失败: {e}")
                        # 统计失败不应阻断主流程，但可记录

                # 6.5 跨平台退款通知
                if need_notify_partner:
                    try:
                        from peizhi.models import ClubConfig, Club
                        my_club_config = ClubConfig.objects.filter(is_self=1).first()
                        if not my_club_config:
                            raise Exception("我方俱乐部配置不存在")
                        self_club_id = my_club_config.club_id
                        club_rel = Club.objects.get(club_id=self_club_id, partner_club_id=partner_club_id)
                        partner_domain = club_rel.partner_domain.rstrip('/')

                        notify_url = f"{partner_domain}/houtai/dfddtk"
                        payload = {
                            'order_id': partner_order_id,
                            'club_id': self_club_id,
                            'status': 5,
                            'reason': '商家更换打手退款'
                        }
                        resp = requests.post(notify_url, json=payload, timeout=5)
                        if resp.status_code != 200:
                            transaction.set_rollback(True)
                            logger.error(f"对方平台接口HTTP错误: {resp.status_code}")
                            return Response({'code': 500, 'msg': '通知对方平台失败'})
                        resp_json = resp.json()
                        if resp_json.get('code') != 0:
                            transaction.set_rollback(True)
                            logger.error(f"对方平台退款通知失败: {resp_json.get('msg')}")
                            return Response({'code': 500, 'msg': f"对方平台通知失败: {resp_json.get('msg')}"})

                        # 更新跨平台扩展数据
                        from dingdan.models import  CrossPlatformOrderData
                        CrossPlatformOrderData.objects.update_or_create(
                            dingdan_id=dingdan_id,
                            defaults={
                                'partner_order_id': partner_order_id,
                                'partner_club_id': partner_club_id,
                                'partner_order_status': 5,
                            }
                        )
                    except Exception as e:
                        transaction.set_rollback(True)
                        logger.error(f"通知对方平台异常: {e}")
                        return Response({'code': 500, 'msg': f'通知对方平台失败: {str(e)}'})

        except Exception as e:
            logger.error(f"退款处理事务失败: {e}", exc_info=True)
            return Response({'code': 500, 'msg': '退款处理失败'})

        # ========== 7. 生成新订单（事务块2） ==========
        try:
            with transaction.atomic():
                # 7.1 生成新的订单ID
                def generate_dingdan_id():
                    timestamp = int(time.time() * 1000)
                    process_id = os.getpid() % 1000
                    random_num = random.randint(1000, 9999)
                    return f"SJ{timestamp}{process_id:03d}{random_num}"

                new_dingdan_id = generate_dingdan_id()
                # 确保唯一
                while Dingdan.objects.filter(dingdan_id=new_dingdan_id).exists():
                    new_dingdan_id = generate_dingdan_id()

                # 7.2 创建新订单（复制数据，状态为 1）
                new_order = Dingdan.objects.create(
                    dingdan_id=new_dingdan_id,
                    zhuangtai=1,                     # 已下单
                    fadan_pingtai=fadan_pingtai,
                    jine=jine,
                    dashou_fencheng=dashou_fencheng,
                    leixing_id=leixing_id,
                    yaoqiuleixing=yaoqiuleixing,
                    huiyuan_id=huiyuan_id,
                    yongjin=yongjin,
                    jieshao=jieshao,
                    nicheng=nicheng,
                    beizhu=beizhu,
                    user1_id=user1_id,               # 商家标识
                    tupian=tupian,
                    # 不继承：zhiding_id, jiedan_dashou_id, dashou_liuyan 等
                )

                # 7.3 创建商家扩展表（关联新订单）
                DingdanShangjia.objects.create(
                    dingdan=new_order,
                    shangjia_id=yonghuid,
                    sjnicheng=shangjia_kuozhan.sjnicheng or '',
                )

                # 7.4 异步通知打手（广播新订单）
                try:
                    order_info = {
                        'dingdan_id': new_dingdan_id,
                        'game_type': self._get_game_type_name(leixing_id),
                        'amount': str(jine),
                        'order_desc': (jieshao or '')[:50],
                    }
                    dingdan_guangbo.delay(order_info)
                except Exception as e:
                    logger.error(f"广播通知失败: {e}")

                # 7.5 跨平台同步（如果适用）
                try:
                    sync_order_to_partners(new_dingdan_id)
                except Exception as e:
                    logger.error(f"跨平台同步失败: {e}")

                # 注意：此处不更新商家余额、发布量等统计，因为是替换订单

                logger.info(f"商家{yonghuid}更换打手成功，旧订单{dingdan_id}已退款，新订单{new_dingdan_id}")

                return Response({
                    'code': 0,
                    'msg': '更换成功',
                    'data': {
                        'xin_dingdan_id': new_dingdan_id,
                    }
                })

        except Exception as e:
            logger.error(f"生成新订单事务失败: {e}", exc_info=True)
            return Response({'code': 500, 'msg': '生成新订单失败'})

    def _get_game_type_name(self, leixing_id):
        """根据类型ID获取游戏类型名称"""
        try:
            gt = ShangpinLeixing.objects.filter(id=leixing_id).first()
            return gt.jieshao if gt else '游戏订单'
        except Exception:
            return '游戏订单'



# ===================== 视图：商家罚款申请 =====================
# 文件路径：dingdan/views.py 或单独文件，根据项目结构放置




class ShangjiaFakuanApplyView(APIView):
    """
    商家罚款申请接口
    路径：POST /dingdan/sjfksq
    权限：JWT认证的商家用户
    参数：
        dingdan_id        - 订单ID (必填)
        chufa_liyou       - 罚款原因 (必填)
        fakuanjine        - 罚款金额，元 (必填)
        yingxiang_qiangdan - 是否影响抢单 1是 0否 (必填)
    说明：
        1. 自动从订单中获取被打手ID，防止商家篡改目标。
        2. 同一订单同一打手不允许重复罚款。
        3. 跨平台订单若为我方派单，则通知对方平台处罚；否则本地生成罚单。
    """

    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        # ========== 1. 身份验证 ==========
        current_user = request.user
        try:
            shangjia_id = current_user.yonghuid  # 商家的用户ID
        except AttributeError:
            return Response({'code': 1, 'msg': '用户认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # ========== 2. 参数提取与校验 ==========
        dingdan_id = request.data.get('dingdan_id', '').strip()
        chufa_liyou = request.data.get('chufa_liyou', '').strip()
        fakuanjine = request.data.get('fakuanjine', 0)
        yingxiang_qiangdan = int(request.data.get('yingxiang_qiangdan', 1))

        if not dingdan_id or not chufa_liyou or not fakuanjine:
            return Response({'code': 2, 'msg': '参数不完整'}, status=status.HTTP_400_BAD_REQUEST)

        try:
            fakuanjine = float(fakuanjine)
            if fakuanjine <= 0:
                raise ValueError
        except (ValueError, TypeError):
            return Response({'code': 2, 'msg': '罚款金额格式错误'}, status=status.HTTP_400_BAD_REQUEST)

        # ========== 3. 获取订单，校验归属商家 ==========
        try:
            # 关联查询商家扩展表，确保订单属于当前商家
            shangjia_kuozhan = DingdanShangjia.objects.select_related('dingdan').get(
                dingdan__dingdan_id=dingdan_id,
                shangjia_id=shangjia_id
            )
            order = shangjia_kuozhan.dingdan
        except DingdanShangjia.DoesNotExist:
            return Response({'code': 3, 'msg': '订单不存在或您无权操作'}, status=status.HTTP_403_FORBIDDEN)

        # ========== 4. 获取被打手ID ==========
        dashou_id = order.jiedan_dashou_id
        if not dashou_id:
            return Response({'code': 4, 'msg': '该订单暂无接单打手，无法罚款'}, status=status.HTTP_400_BAD_REQUEST)

        # ========== 5. 重复罚款检查 ==========
        if Fadan.objects.filter(beichufa_id=dashou_id, guanliandingdan_id=dingdan_id).exists():
            return Response({'code': 5, 'msg': '该打手在此订单已被罚款，不能重复申请'}, status=status.HTTP_400_BAD_REQUEST)

        # ========== 6. 跨平台信息 ==========
        is_cross = order.is_cross
        partner_order_id = order.partner_order_id or ''
        partner_club_id = order.partner_club_id or ''
        dispatch_type = order.dispatch_type or 0  # 1=我方派单，2=对方派单

        # 是否需要通知对方平台：我方派单且存在对方订单ID
        need_notify_partner = is_cross and partner_order_id and dispatch_type == 1

        # ========== 7. 本地创建罚单（可重用） ==========
        def create_local_fadan():
            Fadan.objects.create(
                beichufa_id=dashou_id,
                shenqing_chufa=shangjia_id,  # 申请人为当前商家
                shenfen=1,                    # 被打者身份：1=打手
                chufaliyou=chufa_liyou,
                fakuanjine=fakuanjine,
                guanliandingdan_id=dingdan_id,
                zhuangtai=1,                 # 待缴纳
                yingxiang_qiangdan=yingxiang_qiangdan,
                shenqingren_shenfen=5,        # 申请人是商家
                partner_club_id='',
            )

        # ========== 8. 本地处罚分支 ==========
        if not need_notify_partner:
            with transaction.atomic():
                create_local_fadan()
            logger.info(f"商家{shangjia_id}对订单{dingdan_id}打手{dashou_id}罚款成功，金额{fakuanjine}")
            return Response({'code': 0, 'msg': '罚款申请已提交'})

        # ========== 9. 跨平台通知分支 ==========
        try:
            # 9.1 获取我方俱乐部ID
            my_club = ClubConfig.objects.filter(is_self=1).first()
            if not my_club:
                return Response({'code': 500, 'msg': '系统配置错误'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
            self_club_id = my_club.club_id

            # 9.2 获取对方平台域名
            club_rel = Club.objects.get(club_id=self_club_id, partner_club_id=partner_club_id)
            partner_domain = club_rel.partner_domain.rstrip('/')
        except ObjectDoesNotExist:
            return Response({'code': 500, 'msg': '对方平台信息未配置'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        # 9.3 构造通知参数
        notify_url = f"{partner_domain}/houtai/kffkdssq_notify"  # 与后台接口保持一致
        payload = {
            'order_id': partner_order_id,
            'club_id': self_club_id,
            'chufaliyou': chufa_liyou,
            'fakuanjine': fakuanjine,
            'yingxiang_qiangdan': yingxiang_qiangdan,
            'shenqingren_shenfen': 5,  # 商家身份
            'operator': shangjia_id,   # 操作人ID
        }

        # 9.4 带重试的通知
        timeout = 3
        retries = 2
        success = False
        for attempt in range(retries):
            try:
                resp = requests.post(notify_url, json=payload, timeout=timeout)
                if resp.status_code == 200:
                    resp_data = resp.json()
                    if resp_data.get('code') == 0:
                        success = True
                        break
                    else:
                        logger.warning(f"对方平台罚款通知失败，响应: {resp_data}")
                else:
                    logger.warning(f"对方平台HTTP错误: {resp.status_code}")
            except Exception as e:
                logger.warning(f"通知对方平台异常，第{attempt+1}次尝试: {e}")
                continue

        if not success:
            return Response({'code': 500, 'msg': '通知对方平台失败，请稍后重试'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        # 9.5 通知成功后，本地也创建罚单（标记跨平台）
        with transaction.atomic():
            Fadan.objects.create(
                beichufa_id=dashou_id,
                shenqing_chufa=shangjia_id,
                shenfen=1,
                chufaliyou=chufa_liyou,
                fakuanjine=fakuanjine,
                guanliandingdan_id=dingdan_id,
                zhuangtai=1,
                yingxiang_qiangdan=yingxiang_qiangdan,
                shenqingren_shenfen=5,
                partner_club_id=partner_club_id,  # 记录对方俱乐部ID
            )

        logger.info(f"商家{shangjia_id}跨平台罚款成功: {dingdan_id}")
        return Response({'code': 0, 'msg': '罚款已提交至对方平台'})













class ShangjiaFakuaiXiugaiView(APIView):
    """
    商家端统一修改接口：罚款修改/撤销/再次申请，订单退款撤销/修改理由
    URL: /dingdan/sjfkxgycx
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        user = request.user
        # 验证商家身份
        try:
            shangjia = user.shop_profile
        except UserShangjia.DoesNotExist:
            return Response({'code': 403, 'msg': '您不是商家'}, status=status.HTTP_403_FORBIDDEN)
        if shangjia.zhuangtai != 1:
            return Response({'code': 403, 'msg': '商家状态异常'}, status=status.HTTP_403_FORBIDDEN)

        operation = request.data.get('operation')
        dingdan_id = request.data.get('dingdan_id')
        if not dingdan_id:
            return Response({'code': 400, 'msg': '缺少订单ID'}, status=status.HTTP_400_BAD_REQUEST)

        # 验证订单属于该商家
        try:
            dingdan = Dingdan.objects.select_related('shangjia_kuozhan').get(dingdan_id=dingdan_id)
        except Dingdan.DoesNotExist:
            return Response({'code': 404, 'msg': '订单不存在'}, status=status.HTTP_404_NOT_FOUND)
        if not hasattr(dingdan, 'shangjia_kuozhan') or dingdan.shangjia_kuozhan.shangjia_id != user.yonghuid:
            return Response({'code': 403, 'msg': '无权操作此订单'}, status=status.HTTP_403_FORBIDDEN)

        # 处理订单相关操作
        if operation == 'cancel_refund':
            return self._cancel_refund(dingdan, request.data.get('liyou', ''))
        elif operation == 'modify_refund_reason':
            return self._modify_refund_reason(dingdan, request.data.get('liyou', ''))

        # 处理罚款相关操作
        fadan_id = request.data.get('fadan_id')
        if not fadan_id:
            return Response({'code': 400, 'msg': '缺少罚单ID'}, status=status.HTTP_400_BAD_REQUEST)
        try:
            fadan = Fadan.objects.get(id=fadan_id)
        except Fadan.DoesNotExist:
            return Response({'code': 404, 'msg': '罚单不存在'}, status=status.HTTP_404_NOT_FOUND)
        if fadan.guanliandingdan_id != dingdan_id:
            return Response({'code': 403, 'msg': '罚单与订单不匹配'}, status=status.HTTP_403_FORBIDDEN)

        if operation == 'modify_penalty':
            return self._modify_penalty(fadan, request.data.get('liyou', ''), request.data.get('jine'))
        elif operation == 'cancel_penalty':
            return self._cancel_penalty(fadan, request.data.get('liyou', ''))
        elif operation == 'resubmit_penalty':
            return self._resubmit_penalty(fadan, request.data.get('liyou', ''), request.data.get('jine'))
        else:
            return Response({'code': 400, 'msg': '无效的操作类型'}, status=status.HTTP_400_BAD_REQUEST)

    def _cancel_refund(self, dingdan, liyou):
        """撤销退款申请（状态4 → 状态8，清空退款理由）"""
        if dingdan.zhuangtai != 4:
            return Response({'code': 400, 'msg': '只有退款中的订单可以撤销退款申请'})
        with transaction.atomic():
            dingdan.zhuangtai = 8
            dingdan.tkly = ''   # 清空退款理由
            dingdan.save()
            # 记录撤销理由可存入日志（如需要可另建日志表，此处简单处理）
            logger.info(f"商家撤销退款订单 {dingdan.dingdan_id}，理由: {liyou}")
        return Response({'code': 0, 'msg': '已撤销退款申请'})

    def _modify_refund_reason(self, dingdan, liyou):
        """修改退款理由（仅状态4时）"""
        if dingdan.zhuangtai != 4:
            return Response({'code': 400, 'msg': '只有退款中的订单可以修改退款理由'})
        if not liyou.strip():
            return Response({'code': 400, 'msg': '退款理由不能为空'})
        dingdan.tkly = liyou[:500]
        dingdan.save()
        return Response({'code': 0, 'msg': '退款理由修改成功'})

    def _modify_penalty(self, fadan, liyou, jine_str):
        """修改罚款（仅状态1待缴纳 或 3申诉中）"""
        if fadan.zhuangtai not in (1, 3):
            return Response({'code': 400, 'msg': '当前罚单状态不可修改'})
        if not liyou.strip():
            return Response({'code': 400, 'msg': '罚款理由不能为空'})
        try:
            jine = Decimal(jine_str)
            if jine <= 0:
                raise ValueError
        except:
            return Response({'code': 400, 'msg': '罚款金额必须为正数'})
        with transaction.atomic():
            fadan.chufaliyou = liyou[:500]
            fadan.fakuanjine = jine
            # 如果之前是驳回状态修改，需要重置状态为待缴纳？不，修改不应改变状态
            fadan.save()
        return Response({'code': 0, 'msg': '罚款修改成功'})

    def _cancel_penalty(self, fadan, liyou):
        """撤销罚款（状态1或3 → 状态4 已驳回）"""
        if fadan.zhuangtai not in (1, 3):
            return Response({'code': 400, 'msg': '当前罚单状态不可撤销'})
        if not liyou.strip():
            return Response({'code': 400, 'msg': '驳回理由不能为空'})
        with transaction.atomic():
            fadan.zhuangtai = 4   # 已驳回
            fadan.bohuiliyou = liyou[:500]
            fadan.save()
        return Response({'code': 0, 'msg': '罚款已撤销（驳回）'})

    def _resubmit_penalty(self, fadan, liyou, jine_str):
        """再次申请罚款（状态4 → 状态1，修改理由和金额）"""
        if fadan.zhuangtai != 4:
            return Response({'code': 400, 'msg': '只有已驳回的罚单可再次申请'})
        if not liyou.strip():
            return Response({'code': 400, 'msg': '罚款理由不能为空'})
        try:
            jine = Decimal(jine_str)
            if jine <= 0:
                raise ValueError
        except:
            return Response({'code': 400, 'msg': '罚款金额必须为正数'})
        with transaction.atomic():
            fadan.zhuangtai = 1   # 待缴纳
            fadan.chufaliyou = liyou[:500]
            fadan.fakuanjine = jine
            fadan.bohuiliyou = ''  # 清空驳回理由
            fadan.save()
        return Response({'code': 0, 'msg': '已重新申请罚款'})