"""orders.views.payment - auto-generated by split script."""
# ==================== 标准库 ====================
import hmac
import os
import json
import time
import random
import string
import traceback
import threading
import requests
import hashlib
import xml.etree.ElementTree as ET
import xmltodict
import logging
from decimal import Decimal

from django.conf import settings
from django.db import models, transaction
from gvsdsdk.fluent import db, func, FQ
from django.db.models import F, Q, OuterRef, Subquery
from django.core.cache import cache
from django.core.exceptions import ObjectDoesNotExist
from django.http import HttpResponse
from django.shortcuts import render
from django.utils import timezone

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import permissions, status
from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.parsers import JSONParser
from rest_framework.throttling import AnonRateThrottle
from rest_framework_simplejwt.authentication import JWTAuthentication

from tencentcloud.common import credential
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfile
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
from tencentcloud.sts.v20180813 import sts_client, models

from utils.weixin_broadcast import WeixinBroadcastSender
from utils.money import yuan_to_fen
from utils.chat_utils import (
    _send_group_message, _subscribe_users_to_group, establish_order_chat,
    prepare_order_group_chat, resolve_pair_group_id,
    parse_pair_from_group_id, resolve_pair_from_order, check_pair_chat_permission,
    query_pair_orders, order_to_chat_dict,
)
from utils.fadan_utils import check_fadan_qiangdan_eligible

from orders.utils import (
    calc_shangjia_order_fencheng,
    update_daily_payout,
    settle_shangjia_order_guanshi_fenhong
)
from shop.utils import calculate_pingtai_and_dianpu_shouyi, validate_shangpin_and_dianpu, update_dianpu_daily_stat
from products.utils import update_shangpin_daily_stat
from backend.utils import update_shangjia_daily, update_dashou_daily_by_action, pick_leixing_id, datetime_aliases, fmt_datetime
from rank.services import record_dashou_biaoxian
from rank.utils import check_dashou_biaoqian_required

from orders.notice_tasks import dingdan_guangbo

from ..models import (
    Order, MerchantOrderExt, PlatformOrderExt, PlayerDeliveryImage,
    PenaltyRecord, PenaltyEvidenceImage, Penalty, PenaltyAppealImage, PenaltyBonus, PenaltyBonusRate,
    CommissionRate, PlayerRating, RefundRecord,
)
from jituan.services.club_config import get_commission_rate, get_commission_rate_object
from jituan.services.club_context import resolve_club_id_from_request
from jituan.services.club_user import get_payment_openid
from jituan.services.club_penalty import resolve_penalty_club_id, resolve_penalty_record_club_id
from users.fadan_fenhong_utils import lock_penalty_bonus
from users.fadan_fenhong_utils import lock_penalty_bonus
from products.models import Shangpin, ShangpinLeixing, Huiyuangoumai
from users.models import UserDashou, UserShangjia, UserBoss
from users.business_models import User
from rank.models import DashouBiaoxian, Chenghao, DingdanBiaoqian, YonghuChenghao
from config.models import (
    ShangjiaLianjie
)



logger = logging.getLogger(__name__)

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 = Order.query.select_for_update().filter(OrderID=dingdanid).first()
                if not dingdan:
                    return Response({'code': 2, 'msg': '订单不存在', 'data': None})

                if dingdan.User1ID != f"Boss{request.user.UserUID}":
                    return Response({'code': 3, 'msg': '无权操作此订单', 'data': None})

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

                # 删除扩展表和主表
                PlatformOrderExt.query.filter(Order=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})



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 ''

            from jituan.services.wechat_pay import club_id_from_order, verify_wechat_v2_signature
            notify_club_id = club_id_from_order(out_trade_no)

            # 3. 签名验证
            if not verify_wechat_v2_signature(xml_data, notify_club_id):
                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 = Order.query.select_for_update().select_related(
                'pingtai_kuozhan', 'shangjia_kuozhan'
            ).filter(OrderID=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.Status}")

        # 幂等：已支付则补试收支记账（防止首次入账失败后再也无法统计）
        if dingdan.Status != 9:
            logger.info(f"订单 {out_trade_no} 已处理过，状态={dingdan.Status}，补试收支记账")
            try:
                from jituan.services.szjilu_accounting import repair_wechat_income_if_missing
                repair_wechat_income_if_missing(
                    dingdan.Amount, getattr(dingdan, 'ClubID', None), biz_ref=f'order:{dingdan.OrderID}',
                )
            except Exception as e:
                logger.error(f'订单补记收支失败 {out_trade_no}: {e}', exc_info=True)
            return

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

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

        dingdan.save()

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

        # 删除同一用户同一商品的其他未支付订单（改为逻辑删除，状态25）
        try:
            abandoned_count = Order.query.filter(
                User1ID=dingdan.User1ID,
                ProductID=dingdan.ProductID,
                Status=9
            ).exclude(OrderID=out_trade_no).update(Status=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.BossID
            if laoban_id:
                user_main = User.query.filter(UserUID=laoban_id).select_related('BossProfile').first()
                if user_main and hasattr(user_main, 'BossProfile'):
                    boss = user_main.BossProfile
                    boss.zonge = (boss.zonge or 0) + (dingdan.Amount 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.ProductID:
                Shangpin.query.filter(id=dingdan.ProductID).update(
                    kucun=F('kucun') - 1
                )
                logger.info(f"商品 {dingdan.ProductID} 库存减1")
        except Exception as e:
            logger.error(f"更新商品库存异常: {e}")


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

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

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


        # 更新收支记录（总累计）；统计失败不得回滚订单支付
        try:
            from jituan.services.szjilu_accounting import repair_wechat_income_if_missing
            repair_wechat_income_if_missing(
                dingdan.Amount, getattr(dingdan, 'ClubID', None), biz_ref=f'order:{dingdan.OrderID}',
            )
        except Exception as e:
            logger.error(f'订单收支统计失败 {out_trade_no}: {e}', exc_info=True)

        # 构建通知数据（你的 _get_game_type_name 方法保留在视图里直接用）
        order_info = {
            'OrderID': dingdan.OrderID,
            'game_type': self._get_game_type_name(dingdan.ProductTypeID),
            'amount': str(dingdan.Amount),
            'order_desc': (dingdan.Description 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 = Order.query.select_for_update().filter(OrderID=out_trade_no).first()
            if not dingdan:
                logger.warning(f"订单不存在: {out_trade_no}")
                return

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

            # 仅当订单状态为9（未支付）时才标记失败，不直接删除
            if dingdan.Status == 9:
                dingdan.Status = 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, club_id=None):
        """szjilu 已废弃，财务只写 daily_income_stat，此处不再操作。"""
        pass

    def _broadcast_async(self, dingdan):
        """异步广播通知"""
        try:
            def task():
                try:
                    order_info = {
                        'OrderID': dingdan.OrderID,
                        'game_type': self._get_game_type_name(dingdan.ProductTypeID),
                        'amount': str(dingdan.Amount),
                        'order_desc': (dingdan.Description 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:
            gt = ShangpinLeixing.query.filter(id=leixing_id).first()
            return gt.jieshao if gt else '游戏订单'
        except Exception as e:
            logger.error(f"获取游戏类型名称异常: {e}")
            return '游戏订单'


class AlipayPayNotifyView(WechatPayNotifyView):
    """支付宝支付异步回调接口 - 接收支付宝官方支付结果通知。
    继承 WechatPayNotifyView 以复用 _handle_success/_handle_failure 履约逻辑。
    """
    def post(self, request):
        try:
            # 详细记录原始请求（调试回调是否到达）
            logger.warning(f"[ALIPAY_NOTIFY_DEBUG] 收到回调, method={request.method}, content_type={request.content_type}")
            logger.warning(f"[ALIPAY_NOTIFY_DEBUG] POST keys={list(request.POST.keys())}")

            # 支付宝回调为 form-urlencoded
            # 注意：必须用 .dict() 而不是 dict()！
            #   dict(request.POST) 会返回 {key: [value_list]}（值是列表）
            #   request.POST.dict() 返回 {key: value}（值是字符串），符合验签需求
            params = request.POST.dict() if request.POST else {}
            if not params:
                logger.warning("[ALIPAY_NOTIFY_DEBUG] 支付宝回调: 收到空数据")
                return HttpResponse('fail', content_type='text/plain')

            out_trade_no = params.get('out_trade_no', '')
            trade_no = params.get('trade_no', '')
            trade_status = params.get('trade_status', '')

            logger.warning(f"[ALIPAY_NOTIFY_DEBUG] out_trade_no={out_trade_no}, trade_no={trade_no}, trade_status={trade_status}")
            logger.warning(f"[ALIPAY_NOTIFY_DEBUG] params keys={list(params.keys())}")

            # 验签
            from jituan.services.alipay_pay import verify_notify_params, club_id_from_order
            notify_club_id = club_id_from_order(out_trade_no)
            logger.warning(f"[ALIPAY_NOTIFY_DEBUG] notify_club_id={notify_club_id}")

            verify_result = verify_notify_params(params, notify_club_id)
            logger.warning(f"[ALIPAY_NOTIFY_DEBUG] verify_result={verify_result}")

            if not verify_result:
                logger.warning(f"[ALIPAY_NOTIFY_DEBUG] 支付宝验签失败: out_trade_no={out_trade_no}")
                return HttpResponse('fail', content_type='text/plain')

            # 处理支付结果
            if trade_status in ('TRADE_SUCCESS', 'TRADE_FINISHED'):
                logger.warning(f"[ALIPAY_NOTIFY_DEBUG] 调用 _handle_success")
                # 充值单误打进订单回调：转交 Czjilu 履约，禁止空 success 吞掉通知
                from products.czjilu_types import looks_like_czjilu_out_trade_no
                from products.models import Czjilu
                if looks_like_czjilu_out_trade_no(out_trade_no) or Czjilu.query.filter(dingdan_id=out_trade_no).exists():
                    logger.error(
                        '[ALIPAY_NOTIFY_DEBUG] 充值单误入订单回调，改走 Czjilu 履约: %s',
                        out_trade_no,
                    )
                    from products.views.alipay_czjilu_notify import _fulfill_czjilu_by_leixing
                    cz = Czjilu.query.filter(dingdan_id=out_trade_no).first()
                    if not cz:
                        logger.error('[ALIPAY_NOTIFY_DEBUG] Czjilu 不存在仍回 fail: %s', out_trade_no)
                        return HttpResponse('fail', content_type='text/plain')
                    if cz.zhuangtai == 3:
                        return HttpResponse('success', content_type='text/plain')
                    from products.czjilu_types import is_czjilu_fulfillable_status
                    if not is_czjilu_fulfillable_status(cz.zhuangtai):
                        logger.warning(
                            '[ALIPAY_NOTIFY_DEBUG] Czjilu 终态不再履约 %s zhuangtai=%s',
                            out_trade_no, cz.zhuangtai,
                        )
                        return HttpResponse('success', content_type='text/plain')
                    try:
                        paid_amount = params.get('total_amount') or cz.jine
                        _fulfill_czjilu_by_leixing(out_trade_no, cz.leixing, paid_amount, source='order_notify_redirect')
                    except Exception as redirect_exc:
                        logger.error(
                            '[ALIPAY_NOTIFY_DEBUG] 充值单转履约失败 %s: %s',
                            out_trade_no, redirect_exc, exc_info=True,
                        )
                        return HttpResponse('fail', content_type='text/plain')
                    return HttpResponse('success', content_type='text/plain')

                # 老板订单：不存在则 fail，让支付宝重试（禁止假 success）
                from orders.models import Order
                if not Order.query.filter(OrderID=out_trade_no).exists():
                    logger.error(f"[ALIPAY_NOTIFY_DEBUG] 订单不存在，回 fail 以便重试: {out_trade_no}")
                    return HttpResponse('fail', content_type='text/plain')

                self._handle_success(out_trade_no, trade_no, None)
                logger.warning(f"[ALIPAY_NOTIFY_DEBUG] _handle_success 完成")
            else:
                logger.info(f"支付宝支付状态非成功: {trade_status}, out_trade_no={out_trade_no}")

            # 支付宝要求返回 "success"（纯文本），否则会重复通知
            return HttpResponse('success', content_type='text/plain')

        except Exception as e:
            logger.error(f"[ALIPAY_NOTIFY_DEBUG] 支付宝回调处理异常: {str(e)}")
            logger.error(traceback.format_exc())
            return HttpResponse('fail', content_type='text/plain')


def alipay_pay_page(request):
    """支付宝H5中转页 - 中转跳转到支付宝支付，以及支付完成后的返回页。"""
    pay_url = request.GET.get('pay_url', '')
    out_trade_no = request.GET.get('out_trade_no', '')

    # 优先从 cache 取 pay_url（前端传订单号，避免 URL 过长）
    if not pay_url and out_trade_no:
        cache_key = f'alipay_pay_url_{out_trade_no}'
        pay_url = cache.get(cache_key) or ''

    if pay_url:
        # 中转模式：自动跳转到支付宝
        return render(request, 'alipay/pay.html', {'pay_url': pay_url})
    elif out_trade_no:
        # 返回模式：支付完成返回
        return render(request, 'alipay/pay.html', {'out_trade_no': out_trade_no})
    else:
        return render(request, 'alipay/pay.html', {})


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 = Order.query.filter(OrderID=dingdanid).first()
            if not dingdan:
                return Response({'code': 2, 'msg': '订单不存在'})

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

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

            # ---------- 5. 如果状态为9，则主动查询支付状态 ----------
            if dingdan.Status == 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 = None
                    transaction_id = None

                    from jituan.services.pay_confirm import confirm_remote_payment
                    remote = confirm_remote_payment(
                        dingdanid,
                        getattr(dingdan, 'ClubID', None),
                        prefer_amount=getattr(dingdan, 'Amount', None),
                    )
                    if remote.get('ok'):
                        trade_state = 'SUCCESS'
                        transaction_id = remote.get('transaction_id')
                    elif remote.get('pending'):
                        return Response({'code': 1, 'msg': '支付中', 'data': {'zhuangtai': 9}})
                    else:
                        return Response({'code': 2, 'msg': remote.get('msg') or '支付失败'})

                    if trade_state == 'SUCCESS':
                        # 支付成功，执行本地更新
                        self._process_payment_success(dingdan, transaction_id, current_user.UserUID)
                        # 重新获取订单以获取最新状态
                        dingdan.refresh_from_db()
                        return Response({
                            'code': 0,
                            'msg': '支付成功',
                            'data': {'dingdanid': dingdanid, 'zhuangtai': dingdan.Status}
                        })

                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.Status, '订单状态异常')
                return Response({'code': 3, 'msg': status_msg, 'data': {'zhuangtai': dingdan.Status}})

        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 = Order.query.select_for_update().get(pk=dingdan.pk)
            if dingdan.Status != 9:
                try:
                    from jituan.services.szjilu_accounting import repair_wechat_income_if_missing
                    repair_wechat_income_if_missing(
                        dingdan.Amount,
                        getattr(dingdan, 'ClubID', None),
                        biz_ref=f'order:{dingdan.OrderID}',
                    )
                except Exception as e:
                    logger.error(f'订单复查补记收支失败 {dingdan.OrderID}: {e}', exc_info=True)
                return

            # 更新订单状态
            dingdan.Status = 7 if dingdan.AssignedID and dingdan.AssignedID.strip() else 1
            dingdan.WechatTransactionID = transaction_id
            dingdan.AssignedCS = operator_id   # 可选：记录操作人ID
            dingdan.save()

            # 删除同一用户同一商品的其他未支付订单（逻辑删除，状态25）
            Order.query.filter(
                User1ID=dingdan.User1ID,
                ProductID=dingdan.ProductID,
                Status=9
            ).exclude(OrderID=dingdan.OrderID).update(Status=25)

            # 更新老板扩展表
            laoban_id = dingdan.pingtai_kuozhan.BossID if hasattr(dingdan, 'pingtai_kuozhan') else None
            if laoban_id:
                user_main = User.query.filter(UserUID=laoban_id).select_related('BossProfile').first()
                if user_main and hasattr(user_main, 'BossProfile'):
                    boss = user_main.BossProfile
                    boss.zonge = (boss.zonge or 0) + (dingdan.Amount or 0)
                    boss.alldingdan = (boss.alldingdan or 0) + 1
                    boss.save()

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


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

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

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


            try:
                from jituan.services.szjilu_accounting import repair_wechat_income_if_missing
                repair_wechat_income_if_missing(
                    dingdan.Amount,
                    getattr(dingdan, 'ClubID', None),
                    biz_ref=f'order:{dingdan.OrderID}',
                )
            except Exception as e:
                logger.error(f'订单收支统计失败 {dingdan.OrderID}: {e}', exc_info=True)

    def _query_wechat_payment(self, out_trade_no, club_id=None):
        """
        调用微信支付订单查询接口，返回 (trade_state, transaction_id)
        若查询失败，抛出异常
        """
        from jituan.services.wechat_pay import club_id_from_order, get_wechat_v2_config
        pay_cfg = get_wechat_v2_config(club_id or club_id_from_order(out_trade_no))
        appid = pay_cfg['appid']
        mch_id = pay_cfg['mch_id']
        key = pay_cfg['key']
        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, club_id=None):
        """szjilu 已废弃，财务只写 daily_income_stat，此处不再操作。"""
        pass
            # 不抛出异常，因为收支记录不是核心流程，但记录错误供排查

    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 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('Remark', '').strip()
            # H5 曾误传 zhiding_id，兼容两种字段名
            zhiding = (
                request.data.get('zhiding')
                or request.data.get('zhiding_id')
                or ''
            )
            zhiding = str(zhiding).strip()
            jine = request.data.get('jine', 0)
            pay_method = request.data.get('pay_method', 'wechat').strip().lower()

            # 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.query.filter(id=shangpin_id).first()
            if not shangpin:
                return Response({'code': 4, 'msg': '商品不存在', 'data': None})

            # 转盘购票商品禁止走普通点单，避免支付后直接进抢池
            if getattr(shangpin, 'shi_zhuanpan', False):
                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 = User.query.filter(
                    UserUID=zhiding,
                    #user_type='PlayerID'
                ).select_related('DashouProfile').first()

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

                # 查询打手扩展表
                try:
                    dashou_profile = zhiding_user.DashouProfile
                except UserDashou.DoesNotExist:
                    dashou_profile = None

                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. 查询利率并计算分成
            club_id = resolve_club_id_from_request(request)
            from jituan.services.alipay_pay import alipay_pay_method_block_reason
            _alipay_block = alipay_pay_method_block_reason(pay_method, club_id)
            if _alipay_block:
                return Response({'code': 99, 'msg': _alipay_block, 'data': None})
            dashou_lilu = get_commission_rate_object(club_id, '1')


            # 🔥 新增：判断是否使用商品配置的额外分成
            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.Rate))


            # 查询管事利率（字符'2'）
            #guanshi_lilu = CommissionRate.query.filter(Platform='2').first()

            if not (shangpin.kaioi_ewai_dashou_fencheng and shangpin.ewai_dashou_fencheng is not None):
                if get_commission_rate(club_id, '1') <= 0 and not CommissionRate.query.filter(Platform='1').exists():
                    return Response({'code': 9, 'msg': '系统利率配置不完整', 'data': None})

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

                # 支付宝支付不需要 openid
                if pay_method == 'wechat' and not user_openid:
                    return Response({'code': 10, 'msg': '用户openid不存在', 'data': None})

                # 创建订单主表数据
                order_data = {
                    'OrderID': dingdanid,
                    'Status': 9,  # 未付款状态
                    'Amount': shangpin_jiage,
                    'Platform':1,
                    'PlayerCommission': dashou_fencheng,
                    'AssignedID': zhiding_id_value,
                    'ProductID': shangpin_id,
                    'GrabRequirement': getattr(shangpin, 'yaoqiuleixing', None),
                    'MembershipID': getattr(shangpin, 'huiyuan_id', ''),
                    'CommissionReq': getattr(shangpin, 'yongjin', 0),
                    'Description': getattr(shangpin, 'jieshao', ''),
                    'Remark': beizhu,
                    'Nickname': nicheng,
                    'ImageURL':shangpin_tupian,
                    'User1ID':f"Boss{request.user.UserUID}",
                    'ProductTypeID':shangpin.leixing_id,
                    'ClubID': club_id,
                }

                # 创建订单记录
                
                dingdan = Order.query.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 = {
                    'Order': dingdan,
                    'BossID': laoban_yonghuid,
                    'PlatformIncome': pingtai_shouyi,
                    # ---------- 新增上级分红快照 ----------
                    'ParentShopID': shangji_dianpu_id,
                    'ParentBonus': shangji_fenhong if shangji_fenhong else Decimal('0.00'),
                }
                if dianpu_id:
                    pingtaikuozhan_data['ShopID'] = dianpu_id
                    pingtaikuozhan_data['ShopIncome'] = dianpu_shouyi
                else:
                    pingtaikuozhan_data['ShopIncome'] = Decimal('0.00')

                PlatformOrderExt.query.create(**pingtaikuozhan_data)


                # 计算收益
                '''dianpu_id, pingtai_shouyi, dianpu_shouyi = calculate_pingtai_and_dianpu_shouyi(
                    ProductID=shangpin_id,
                    dingdan_jiage=shangpin_jiage,
                    PlayerCommission=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')

                PlatformOrderExt.query.create(**pingtaikuozhan_data)'''


                # 7. 根据支付方式生成支付参数
                if pay_method == 'alipay':
                    pay_params = self.generate_alipay_pay_params(
                        dingdanid=dingdanid,
                        jine=shangpin_jiage,
                        subject=getattr(settings, 'WEIXIN_PAY_DESCRIPTION', '星阙订单'),
                        club_id=club_id,
                    )
                else:
                    from jituan.services.club_user import get_pay_app_source
                    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,
                        club_id=club_id,
                        app_source=get_pay_app_source(request),
                    )

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

                # 8. 返回成功响应
                response_data = {
                    'code': 0,
                    'msg': '订单创建成功',
                    'data': {
                        'dingdanid': dingdanid,
                        'payMethod': pay_method,
                        '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, club_id=None, app_source='mini'):
        """
        调用微信支付统一下单接口，生成支付参数。
        app_source=official/h5：用服务号 AppID + 同商户号（H5）；跳过付呗小程序通道。
        """
        try:
            from jituan.constants import FUBEI_BIZ_ORDER
            from jituan.services.mini_pay_router import maybe_create_fubei_jsapi_params
            from jituan.services.wechat_pay import get_wechat_v2_config
            source = (app_source or 'mini').strip().lower()
            pay_cfg = get_wechat_v2_config(club_id, app_source=source)
            APPID = pay_cfg['appid']
            MCHID = pay_cfg['mch_id']
            KEY = pay_cfg['key']
            NOTIFY_URL = getattr(settings, 'WEIXIN_NOTIFY_URL', '')

            # H5/服务号：复用同一商户号走微信直连 JSAPI，不走付呗小程序通道
            fb_params = None
            if source not in ('official', 'h5', 'oa'):
                fb_params = maybe_create_fubei_jsapi_params(
                    club_id=club_id,
                    out_trade_no=dingdanid,
                    amount_yuan=jine,
                    body=beizhu,
                    openid=openid,
                    notify_url=NOTIFY_URL,
                    biz_type=FUBEI_BIZ_ORDER,
                )
            if fb_params is not None:
                return fb_params

            # NOAUTH 诊断日志：打印生效的 club_id / appid / mchid / openid 指纹
            _oid_preview = (openid or '')[:6] + '...' + (openid or '')[-4:] if (openid or '') else '(empty)'
            logger.warning(
                "[WX_PAY_NOAUTH_DIAG] dingdanid=%s club_id=%s app_source=%s appid=%s mch_id=%s openid_preview=%s openid_len=%d",
                dingdanid, club_id, source, APPID, MCHID, _oid_preview, len(openid or ''),
            )

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

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

            # 金额（单位：分）
            total_fee = yuan_to_fen(jine)

            # 交易类型
            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
            logger.warning("[WX_PAY_NOAUTH_DIAG] wechat_raw_response=%s", response.content.decode('utf-8', errors='replace'))
            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()

                # 返回支付参数（H5 JSAPI 必须带 appId；小程序可忽略）
                result = {
                    'appId': APPID,
                    '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

    def generate_alipay_pay_params(self, dingdanid, jine, subject, club_id=None):
        """
        生成支付宝 wap.pay URL 并转成二维码图片。
        用户用支付宝 APP 扫一扫二维码，在支付宝内置浏览器完成支付
        （支付宝环境支持 alipay:// scheme，不受微信 web-view 限制）。
        无需签约"当面付"产品，仅需已开通的"手机网站支付"。
        """
        try:
            from jituan.services.alipay_pay import build_wap_pay_url, qr_link_to_base64
            pay_url = build_wap_pay_url(
                out_trade_no=dingdanid,
                amount=jine,
                subject=subject,
                club_id=club_id,
            )
            qr_image = qr_link_to_base64(pay_url)
            # 标记支付宝订单（fucha 接口据此跳过微信查询，直接等异步回调更新状态）
            cache.set(f'alipay_pay_url_{dingdanid}', pay_url, 60 * 30)
            return {
                'qr_code': pay_url,
                'qr_image': qr_image,
                'pay_method': 'alipay',
            }
        except Exception as e:
            raise e


class ContinuePayView(APIView):
    """
    待付款续付：复用原 OrderID 重新拉起支付，不新建订单。

    安全约束（硬保证）：
    1. 本接口绝不把 Status 从 9 改成已付；已付只由微信/支付宝回调或 /dingdan/fucha
       在「渠道查单确认 SUCCESS」后写入（与现网一致）。
    2. 续付前先查渠道：若其实已付成功，则走现有复查履约，避免「用户已付仍显示待付款」。
    3. 仅 Status==9 且本人订单可续付；其它状态直接拒绝，不会误改。
    """
    permission_classes = [permissions.IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        try:
            dingdanid = (request.data.get('dingdanid') or request.data.get('dingdan_id') or '').strip()
            pay_method = (request.data.get('pay_method') or 'wechat').strip().lower()
            if not dingdanid:
                return Response({'code': 1, 'msg': '订单ID不能为空', 'data': None})
            if pay_method not in ('wechat', 'alipay'):
                return Response({'code': 1, 'msg': '不支持的支付方式', 'data': None})

            current_user = request.user
            boss_id = f"Boss{current_user.UserUID}"

            dingdan = Order.query.filter(OrderID=dingdanid).first()
            if not dingdan:
                return Response({'code': 2, 'msg': '订单不存在', 'data': None})
            if dingdan.User1ID != boss_id:
                logger.warning('续付越权 dingdanid=%s uid=%s', dingdanid, current_user.UserUID)
                return Response({'code': 403, 'msg': '无权操作此订单', 'data': None})

            from jituan.services.alipay_pay import alipay_pay_method_block_reason
            _club_for_alipay = getattr(dingdan, 'ClubID', None) or resolve_club_id_from_request(request)
            _alipay_block = alipay_pay_method_block_reason(pay_method, _club_for_alipay)
            if _alipay_block:
                return Response({'code': 99, 'msg': _alipay_block, 'data': None})

            # 已进入正常履约/服务流程：不得再拉起支付，也不得改状态
            if dingdan.Status in (1, 7):
                return Response({
                    'code': 0,
                    'msg': '订单已支付',
                    'data': {
                        'dingdanid': dingdanid,
                        'zhuangtai': dingdan.Status,
                        'already_paid': True,
                    },
                })
            if dingdan.Status != 9:
                return Response({
                    'code': 3,
                    'msg': '仅待付款订单可继续支付',
                    'data': {'zhuangtai': dingdan.Status},
                })

            club_id = getattr(dingdan, 'ClubID', None) or resolve_club_id_from_request(request)

            # 续付前强制查渠道：已付则履约，杜绝「付了还待付款」
            from jituan.services.pay_confirm import confirm_remote_payment
            remote = confirm_remote_payment(
                dingdanid,
                club_id,
                prefer_amount=getattr(dingdan, 'Amount', None),
            )
            if remote.get('ok'):
                PaymentVerifyView()._process_payment_success(
                    dingdan,
                    remote.get('transaction_id'),
                    current_user.UserUID,
                )
                dingdan.refresh_from_db()
                return Response({
                    'code': 0,
                    'msg': '订单已支付',
                    'data': {
                        'dingdanid': dingdanid,
                        'zhuangtai': dingdan.Status,
                        'already_paid': True,
                    },
                })

            # 仍未付：复用原单号重新下预支付单（不改 Status，保持 9）
            helper = CreateOrderView()
            user_openid, club_id = get_payment_openid(request, current_user, club_id)
            if pay_method == 'wechat' and not user_openid:
                return Response({'code': 10, 'msg': '用户openid不存在', 'data': None})

            jine = dingdan.Amount
            if jine is None or Decimal(str(jine)) <= 0:
                return Response({'code': 6, 'msg': '订单金额异常', 'data': None})

            subject = getattr(settings, 'WEIXIN_PAY_DESCRIPTION', '星阙订单')
            try:
                if pay_method == 'alipay':
                    pay_params = helper.generate_alipay_pay_params(
                        dingdanid=dingdanid,
                        jine=jine,
                        subject=subject,
                        club_id=club_id,
                    )
                else:
                    from jituan.services.club_user import get_pay_app_source
                    pay_params = helper.generate_wechat_pay_params(
                        dingdanid=dingdanid,
                        jine=jine,
                        beizhu=subject,
                        user_ip=helper.get_client_ip(request),
                        openid=user_openid,
                        club_id=club_id,
                        app_source=get_pay_app_source(request),
                    )
            except Exception as pay_exc:
                err_text = str(pay_exc)
                # 渠道侧可能已付（同 out_trade_no），再查一次并履约，绝不静默标已付
                if 'ORDERPAID' in err_text.upper() or '已支付' in err_text:
                    remote2 = confirm_remote_payment(
                        dingdanid, club_id, prefer_amount=getattr(dingdan, 'Amount', None),
                    )
                    if remote2.get('ok'):
                        PaymentVerifyView()._process_payment_success(
                            dingdan,
                            remote2.get('transaction_id'),
                            current_user.UserUID,
                        )
                        dingdan.refresh_from_db()
                        return Response({
                            'code': 0,
                            'msg': '订单已支付',
                            'data': {
                                'dingdanid': dingdanid,
                                'zhuangtai': dingdan.Status,
                                'already_paid': True,
                            },
                        })
                logger.exception('续付拉起支付失败 dingdanid=%s', dingdanid)
                return Response({'code': 11, 'msg': f'拉起支付失败: {err_text}', 'data': None})

            if not pay_params:
                return Response({'code': 11, 'msg': '支付参数生成失败', 'data': None})

            # 再次确认本地仍为 9（并发下回调可能已履约）
            dingdan.refresh_from_db()
            if dingdan.Status != 9:
                return Response({
                    'code': 0,
                    'msg': '订单状态已更新',
                    'data': {
                        'dingdanid': dingdanid,
                        'zhuangtai': dingdan.Status,
                        'already_paid': dingdan.Status in (1, 7),
                    },
                })

            return Response({
                'code': 0,
                'msg': 'ok',
                'data': {
                    'dingdanid': dingdanid,
                    'payMethod': pay_method,
                    'payParams': pay_params,
                    'zhuangtai': 9,
                    'already_paid': False,
                },
            })
        except Exception as e:
            logger.exception('ContinuePayView 异常')
            return Response({'code': 99, 'msg': f'系统错误: {str(e)}', 'data': None})


