# shangpin/views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.throttling import AnonRateThrottle
from django.db import models
from shangpin.models import ShangpinLeixing, ShangpinZhuanqu, Shangpin
import logging
from rest_framework.permissions import AllowAny  # 新增这行

# 配置日志
logger = logging.getLogger(__name__)




class ShangpinHuoquView(APIView):
    """
    商品数据获取接口
    一次性返回商品类型、商品专区、商品列表
    """

    # 应用节流（限制频率）
    throttle_classes = [AnonRateThrottle]
    permission_classes = [AllowAny]

    def post(self, request):
        """
        处理POST请求，返回所有商品相关数据
        """
        try:
            logger.info("收到商品数据获取请求")

            # 1. 查询商品类型（只查询正常状态的类型，并排序）
            # 正常运营：只显示 shenhezhuangtai=2 的商品类型
            leixing_queryset = ShangpinLeixing.objects.filter(
                shenhezhuangtai=1  # 只取正常状态
            ).order_by('-paixu', 'id')  # 先按paixu降序，再按id升序

            # 注意：审核期间使用下面这行代码（先注释掉）
            '''leixing_queryset = ShangpinLeixing.objects.filter(
                 shenhezhuangtai=2  # 审核期间：只取审核专用状态
             ).order_by('-paixu', 'id')'''

            shangpinleixing_data = []
            for leixing in leixing_queryset:
                shangpinleixing_data.append({
                    "id": leixing.id,
                    "jieshao": leixing.jieshao,
                    "tupian_url": leixing.tupian_url,
                    "paixu": leixing.paixu
                })

            # 2. 查询商品专区（只查询可见类型下的专区，并排序）
            # 先获取可见的类型ID列表
            visible_leixing_ids = [leixing['id'] for leixing in shangpinleixing_data]

            if visible_leixing_ids:
                zhuanqu_queryset = ShangpinZhuanqu.objects.filter(
                    leixing_id__in=visible_leixing_ids,
                    shenhezhuangtai=1  # 🔴【添加】只筛选审核状态为2的专区
                ).order_by('-paixu', 'id')  # 先按paixu降序，再按id升序
            else:
                zhuanqu_queryset = ShangpinZhuanqu.objects.none()

            shangpinzhuanqu_data = []
            for zhuanqu in zhuanqu_queryset:
                shangpinzhuanqu_data.append({
                    "id": zhuanqu.id,
                    "mingzi": zhuanqu.mingzi,
                    "leixing_id": zhuanqu.leixing_id,
                    "paixu": zhuanqu.paixu
                })

            # 3. 查询商品列表（只查询可见专区下的商品，并排序）
            # 先获取可见的专区ID列表
            visible_zhuanqu_ids = [zhuanqu['id'] for zhuanqu in shangpinzhuanqu_data]

            if visible_zhuanqu_ids:
                # 注意：这里使用values()只获取指定字段，提高查询效率
                shangpin_queryset = Shangpin.objects.filter(
                    zhuanqu_id__in=visible_zhuanqu_ids,
                    shenhezhuangtai=1  # 🔴【添加】只筛选审核状态为2的商品
                ).values(
                    'id', 'biaoqian', 'jiage', 'leixing_id',
                    'zhuanqu_id', 'tupian_url', 'duiwai_xiaoliang', 'paixu'
                ).order_by('-paixu', 'id')  # 先按paixu降序，再按id升序

                # 将QuerySet转换为列表
                shangpinliebiao_data = list(shangpin_queryset)
            else:
                shangpinliebiao_data = []

            # 4. 构建返回数据
            response_data = {
                "shangpinleixing": shangpinleixing_data,
                "shangpinzhuanqu": shangpinzhuanqu_data,
                "shangpinliebiao": shangpinliebiao_data
            }

            logger.info(f"返回数据：类型{len(shangpinleixing_data)}个，"
                        f"专区{len(shangpinzhuanqu_data)}个，"
                        f"商品{len(shangpinliebiao_data)}个")

            # 5. 返回响应
            return Response(response_data, status=status.HTTP_200_OK)

        except Exception as e:
            # 记录异常
            logger.error(f"获取商品数据时发生错误：{str(e)}", exc_info=True)

            # 返回错误响应
            error_data = {
                "error": "服务器内部错误",
                "detail": "获取商品数据失败，请稍后重试"
            }
            return Response(error_data, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

class ShangpinXiangqingHuoquView(APIView):
    """
    商品详情接口 - 极简版
    假设所有字段都存在，直接返回
    """

    throttle_classes = [AnonRateThrottle]
    permission_classes = [AllowAny]

    def post(self, request):
        try:
            shangpin_id = request.data.get('shangpin_id')

            if not shangpin_id:
                return Response({
                    "code": 1,
                    "msg": "商品ID不能为空",
                    "data": None
                }, status=400)

            # 直接查询，数据量小，性能没问题
            shangpin = Shangpin.objects.filter(id=shangpin_id).first()

            if not shangpin:
                return Response({
                    "code": 2,
                    "msg": "商品不存在",
                    "data": None
                }, status=404)

            # 直接构建数据，不处理空值
            data = {
                "tupian": shangpin.tupian_url,
                "biaoti": shangpin.biaoqian,
                "jiage": shangpin.jiage,
                "xiangqing": shangpin.jieshao,
                "xiadanxuzhi": shangpin.xiadan_xuzhi,
                "guize": shangpin.guize_tupian,
                "xiaoliang": shangpin.duiwai_xiaoliang,
                "kucun": shangpin.kucun,
            }

            return Response({
                "code": 0,
                "msg": "success",
                "data": data
            })

        except Exception as e:
            logger.error(f"接口异常: {e}")
            return Response({
                "code": 500,
                "msg": "服务器错误",
                "data": None
            }, status=500)



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

import logging

logger = logging.getLogger(__name__)

class DashouHuiyuanList(APIView):
    """
    获取打手会员商品列表
    路径：/shangpin/dshyhq
    请求方式：POST
    权限：JWT认证
    返回：会员商品列表，字段对应前端需求
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # 1. 检查用户是否是打手（通过反向查询）
            try:
                dashou = request.user.dashou_profile
            except UserDashou.DoesNotExist:
                logger.warning(f"用户{request.user.yonghuid}不是打手，尝试访问打手接口")
                return Response({
                    'code': 400,
                    'message': '用户不是打手，无法访问此接口'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 2. 检查打手账号状态
            if dashou.zhanghaozhuangtai != 1:
                logger.warning(f"打手{request.user.yonghuid}账号状态异常: {dashou.zhanghaozhuangtai}")
                return Response({
                    'code': 400,
                    'message': '账号状态异常，无法购买会员'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 3. 查询所有会员数据（ORM查询，确保性能）
            huiyuan_queryset = Huiyuan.objects.all().only(
                'huiyuan_id',  # 会员ID
                'jieshao',     # 会员名字（注意：jieshao字段实际存储的是会员名字）
                'jtjieshao',   # 会员具体介绍
                'jiage'        # 会员价格
            ).order_by('jiage')  # 按价格排序

            # 4. 构建返回数据列表
            huiyuan_list = []
            for huiyuan in huiyuan_queryset:
                huiyuan_list.append({
                    'id': huiyuan.huiyuan_id,       # 会员ID（对应前端id）
                    'mingzi': huiyuan.jieshao,      # 会员名字（对应前端mingzi）
                    'jiage': float(huiyuan.jiage),  # 会员价格（转为浮点数）
                    'jieshao': huiyuan.jtjieshao    # 会员介绍（对应前端jieshao）
                })

            # 5. 返回数据
            return Response({
                'code': 200,
                'message': '获取会员列表成功',
                'data': huiyuan_list  # 对应前端接收的列表
            }, status=status.HTTP_200_OK)

        except Exception as e:
            logger.error(f"获取会员列表接口异常: {str(e)}", exc_info=True)
            return Response({
                'code': 500,
                'message': '服务器内部错误，请稍后重试'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)



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

import logging

logger = logging.getLogger(__name__)


class YajinGoumai(APIView):
    """
    押金充值支付参数接口
    路径：/shangpin/yajingoumai
    请求方式：POST
    权限：JWT认证
    参数：jine（金额，1-10000元）
    返回：支付参数(payParams)和订单ID(dingdanid)
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # 1. 验证用户身份和状态
            try:
                dashou = request.user.dashou_profile
            except UserDashou.DoesNotExist:
                return Response({
                    'code': 400,
                    'message': '用户不是打手，无法充值押金'
                }, status=status.HTTP_400_BAD_REQUEST)

            if dashou.zhanghaozhuangtai != 1:
                return Response({
                    'code': 400,
                    'message': '账号状态异常，无法进行充值'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 2. 获取并验证金额参数
            jine = request.data.get('jine')
            if not jine:
                return Response({
                    'code': 400,
                    'message': '请填写充值金额'
                }, status=status.HTTP_400_BAD_REQUEST)

            try:
                jine = int(jine)
            except (ValueError, TypeError):
                return Response({
                    'code': 400,
                    'message': '金额格式错误，请填写1-10000的整数'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 验证金额范围
            if jine < 1 or jine > 10000:
                return Response({
                    'code': 400,
                    'message': '充值金额必须在1-10000元之间'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 3. 生成订单ID（使用你提供的算法，前缀改为CzYJ）
            timestamp_ms = int(time.time() * 1000)
            timestamp_ns = int(time.time_ns() // 1000) % 1000000
            random_num = random.randint(0, 99)

            dingdanid = f"CzYJ{timestamp_ms:011d}{timestamp_ns:06d}{random_num:02d}"

            # 4. 创建充值记录订单
            chongzhi_jilu = Czjilu.objects.create(
                dingdan_id=dingdanid,
                zhuangtai=9,  # 未支付状态
                yonghuid=request.user.yonghuid,
                jine=jine,
                leixing=2,  # 充值类型：2=押金
                shuoming=settings.YAJIN_PAY_DESCRIPTION
            )

            logger.info(f"创建押金充值订单: 用户{request.user.yonghuid}, 订单{dingdanid}, 金额{jine}元")

            # 5. 生成微信支付参数
            try:
                pay_params = self.generate_wechat_pay_params(
                    dingdanid=dingdanid,
                    jine=jine,
                    openid=request.user.openid,  # 直接从request.user获取openid
                    pay_type='yajin'
                )
            except Exception as e:
                # 支付参数生成失败，删除订单记录
                chongzhi_jilu.delete()
                logger.error(f"生成微信支付参数失败: {str(e)}")
                return Response({
                    'code': 500,
                    'message': f'支付参数生成失败: {str(e)}'
                }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

            # 6. 返回支付参数和订单ID
            return Response({
                'code': 200,
                'message': '支付参数生成成功',
                'payParams': pay_params,  # 支付参数（前端接收为payParams）
                'dingdanid': dingdanid  # 订单ID（前端接收为dingdanid）
            }, status=status.HTTP_200_OK)

        except Exception as e:
            logger.error(f"押金充值接口异常: {str(e)}", exc_info=True)
            return Response({
                'code': 500,
                'message': '服务器内部错误，请稍后重试'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def generate_wechat_pay_params(self, dingdanid, jine, openid, pay_type):
        """生成微信小程序支付参数"""
        # 获取配置
        APPID = settings.WEIXIN_APPID
        MCHID = settings.WEIXIN_MCHID
        KEY = settings.WEIXIN_SHANGHUMIYAO

        # 根据支付类型获取对应的配置
        if pay_type == 'yajin':
            PAY_DESCRIPTION = settings.YAJIN_PAY_DESCRIPTION
            NOTIFY_URL = settings.YAJIN_PAY_NOTIFY_URL
        elif pay_type == 'jifen':
            PAY_DESCRIPTION = settings.JIFEN_PAY_DESCRIPTION
            NOTIFY_URL = settings.JIFEN_PAY_NOTIFY_URL
        elif pay_type == 'huiyuan':
            PAY_DESCRIPTION = settings.HUIYUAN_PAY_DESCRIPTION
            NOTIFY_URL = settings.HUIYUAN_PAY_NOTIFY_URL
        else:
            raise Exception('未知的支付类型')

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

        # 金额转换（元转分）
        total_fee = int(jine * 100)

        # 交易类型（小程序支付使用JSAPI）
        trade_type = 'JSAPI'

        # 获取客户端IP
        user_ip = self.get_client_ip()

        # 1. 第一次签名（统一下单接口）
        sign_data = {
            'appid': APPID,
            'mch_id': MCHID,
            'nonce_str': nonce_str,
            'body': PAY_DESCRIPTION,
            'out_trade_no': dingdanid,
            'total_fee': total_fee,
            'spbill_create_ip': user_ip,
            'notify_url': NOTIFY_URL,
            'trade_type': trade_type,
            'openid': 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>{PAY_DESCRIPTION}</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
            prepay_id = root.find('prepay_id').text

            # 2. 第二次签名（小程序支付参数）
            timestamp = str(int(time.time()))
            nonce_str = ''.join(random.choices(string.ascii_letters + string.digits, k=32))
            package = f'prepay_id={prepay_id}'
            sign_type = 'MD5'

            # 生成支付签名（注意：这里key的大小写和字段名与第一次不同）
            pay_sign_data = {
                'appId': APPID,  # 注意：这里是appId，不是appid
                'timeStamp': timestamp,  # 注意：这里是timeStamp，不是timestamp
                'nonceStr': nonce_str,
                'package': package,
                'signType': sign_type
            }

            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()

            # 返回前端需要的支付参数
            return {
                'appId': APPID,  # 对应前端：appId
                'timeStamp': timestamp,  # 对应前端：timeStamp
                'nonceStr': nonce_str,  # 对应前端：nonceStr
                'package': package,  # 对应前端：package
                'signType': sign_type,  # 对应前端：signType
                'paySign': pay_sign  # 对应前端：paySign
            }
        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}")

    def get_client_ip(self):
        """获取客户端IP（从DRF的request对象中获取）"""
        request = self.request
        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 if ip else '127.0.0.1'


# views.py
from django.views import View

import logging

logger = logging.getLogger(__name__)


class YajinHuitiao(View):
    """
    押金支付回调接口
    路径：/shangpin/yajinhuitiao
    注意：这个接口不需要JWT认证，由微信服务器调用
    """

    def post(self, request):
        try:
            # 1. 解析微信回调XML数据
            request_body = request.body
            logger.info(f"收到微信支付回调，原始数据: {request_body.decode('utf-8')}")

            root = ET.fromstring(request_body)

            # 获取关键字段
            return_code = root.find('return_code').text
            result_code = root.find('result_code').text
            out_trade_no = root.find('out_trade_no').text  # 订单ID
            transaction_id = root.find('transaction_id').text  # 微信交易号
            total_fee = int(root.find('total_fee').text)  # 支付金额（分）

            logger.info(f"回调数据解析: 订单{out_trade_no}, 状态{return_code}/{result_code}, 金额{total_fee}分")

            # 2. 验证基本返回状态
            if return_code != 'SUCCESS' or result_code != 'SUCCESS':
                logger.warning(f"微信支付回调状态异常: {return_code}/{result_code}")
                return self.wechat_response('FAIL', '支付失败')

            # 3. 验证签名（确保是微信发来的）
            if not self.verify_signature(request_body):
                logger.error(f"签名验证失败: {out_trade_no}")
                return self.wechat_response('FAIL', '签名验证失败')

            # 4. 查询订单
            try:
                order = Czjilu.objects.get(dingdan_id=out_trade_no)
                logger.info(f"找到订单: {order.dingdan_id}, 状态: {order.zhuangtai}, 金额: {order.jine}")
            except Czjilu.DoesNotExist:
                logger.error(f"订单不存在: {out_trade_no}")
                return self.wechat_response('FAIL', '订单不存在')

            # 5. 检查订单状态是否为未支付（9）
            if order.zhuangtai != 9:
                logger.warning(f"订单状态不是未支付: {order.dingdan_id}, 当前状态: {order.zhuangtai}")
                # 已处理过的订单直接返回成功，避免微信重复回调
                return self.wechat_response('SUCCESS', 'OK')

            # 6. 验证金额（微信返回的是分，需要转换）
            wechat_amount_yuan = total_fee / 100  # 转换为元
            order_amount_yuan = float(order.jine)  # 订单金额（元）

            # 允许1分钱的误差（浮点数比较）
            if abs(wechat_amount_yuan - order_amount_yuan) > 0.01:
                logger.error(f"金额不一致: 订单金额{order_amount_yuan}元, 支付金额{wechat_amount_yuan}元")
                return self.wechat_response('FAIL', '金额不一致')

            # 7. 更新订单状态为已支付（3）
            order.zhuangtai = 3
            order.save(update_fields=['zhuangtai'])
            logger.info(f"订单状态更新成功: {order.dingdan_id} -> 3")

            # 8. 更新打手押金
            try:
                # 通过用户ID查找打手（高效查询）
                dashou = UserDashou.objects.get(user__yonghuid=order.yonghuid)

                # 增加押金（使用Decimal确保精度）
                from decimal import Decimal
                dashou.yajin += Decimal(str(order_amount_yuan))
                dashou.save(update_fields=['yajin'])

                logger.info(f"打手押金更新成功: 用户{order.yonghuid}, 增加{order_amount_yuan}元, 新押金{dashou.yajin}")

                # 8b. 押金分红（仅微信确认到账后；费率 Lilubiao fadanpingtai=12）
                try:
                    from decimal import Decimal
                    from django.db import transaction
                    from dingdan.models import Lilubiao
                    from shangpin.models import Gsfenhong
                    from yonghu.models import UserGuanshi

                    guanshi_id = dashou.yaoqingren
                    if not guanshi_id:
                        logger.info(f"押金分红跳过: 打手{order.yonghuid}无邀请管事")
                    elif Gsfenhong.objects.filter(dingdan_id=order.dingdan_id).exists():
                        logger.info(f"押金分红已处理: 订单{order.dingdan_id}")
                    else:
                        lilu_obj = Lilubiao.objects.filter(fadanpingtai='12').first()
                        rate = lilu_obj.lilu if lilu_obj and lilu_obj.lilu is not None else Decimal('0')
                        if rate <= 0:
                            logger.info(f"押金分红跳过: 费率未配置或为0")
                        else:
                            recharge_amount = Decimal(str(order_amount_yuan))
                            fenhong_jine = (recharge_amount * rate).quantize(Decimal('0.01'))
                            if fenhong_jine > 0:
                                with transaction.atomic():
                                    guanshi = UserGuanshi.objects.select_for_update().get(
                                        user__yonghuid=guanshi_id
                                    )
                                    guanshi.yue += fenhong_jine
                                    guanshi.chongzhifenrun += fenhong_jine
                                    guanshi.save(update_fields=['yue', 'chongzhifenrun'])

                                    user_main = dashou.user
                                    Gsfenhong.objects.create(
                                        dingdan_id=order.dingdan_id,
                                        guanshi=guanshi_id,
                                        dashouid=order.yonghuid,
                                        shuoming='押金分红',
                                        fenhong=fenhong_jine,
                                        avatar=user_main.avatar,
                                        nicheng=dashou.nicheng or '未知打手',
                                        fenhong_leixing=2,
                                    )
                                logger.info(
                                    f"押金分红成功: 订单{order.dingdan_id}, 管事{guanshi_id}, "
                                    f"打手{order.yonghuid}, 金额{fenhong_jine}元"
                                )
                                try:
                                    from houtai.utils import update_guanshi_daily_by_action
                                    update_guanshi_daily_by_action(
                                        yonghuid=guanshi_id,
                                        action=4,
                                        amount=fenhong_jine,
                                    )
                                except Exception as e:
                                    logger.error(f"押金分红管事日统计更新失败: {e}")
                except UserGuanshi.DoesNotExist:
                    logger.warning(f"押金分红跳过: 管事{guanshi_id}不存在")
                except Exception as e:
                    logger.error(f"押金分红处理失败: {str(e)}", exc_info=True)

            except UserDashou.DoesNotExist:
                # 如果找不到打手，记录错误，但依然返回成功（避免微信重复回调）
                logger.error(f"打手信息不存在: 用户{order.yonghuid}")
                return self.wechat_response('SUCCESS', 'OK')
            except Exception as e:
                logger.error(f"更新打手押金失败: {str(e)}", exc_info=True)
                return self.wechat_response('FAIL', '更新押金失败')

            # ==== 在返回成功响应之前添加这段代码 ====

            # 更新收支记录表
            try:
                from peizhi.models import Szjilu
                from decimal import Decimal



                # 获取订单金额（确保是Decimal类型）
                jine_decimal = Decimal(str(order.jine)) if not isinstance(order.jine, Decimal) else order.jine

                # 查询或创建ID=1的收支记录
                from dingdan.utils import update_daily_income
                update_daily_income(jine_decimal)

                szjilu, created = Szjilu.objects.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()

                logger.info(f"收支记录更新成功: 订单{order.dingdan_id}, 金额{jine_decimal}元")

            except Exception as e:
                # 收支记录更新失败不影响主流程，只记录日志
                logger.error(f"更新收支记录失败: {str(e)}", exc_info=True)

            # ==== 添加结束 ====

            # 9. 返回成功响应给微信
            logger.info(f"押金支付回调处理完成: {out_trade_no}")
            return self.wechat_response('SUCCESS', 'OK')

        except ET.ParseError as e:
            logger.error(f"XML解析失败: {str(e)}")
            return self.wechat_response('FAIL', '数据格式错误')
        except Exception as e:
            logger.error(f"押金支付回调处理异常: {str(e)}", exc_info=True)
            # 返回FAIL让微信重试
            return self.wechat_response('FAIL', '处理异常')

    def verify_signature(self, xml_data):
        """验证微信支付签名"""
        try:
            root = ET.fromstring(xml_data)
            sign = root.find('sign').text

            if not sign:
                logger.error("签名字段不存在")
                return False

            # 获取所有参数并排除sign
            params = {}
            for child in root:
                if child.tag != 'sign' and child.text is not None:
                    params[child.tag] = child.text

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

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

            # 计算签名
            calculated_sign = hashlib.md5(sign_string.encode('utf-8')).hexdigest().upper()

            is_valid = sign == calculated_sign
            if not is_valid:
                logger.error(f"签名验证失败: 计算签名{calculated_sign}, 收到签名{sign}")

            return is_valid

        except Exception as e:
            logger.error(f"验证签名异常: {str(e)}")
            return False

    def wechat_response(self, return_code, return_msg):
        """返回微信支付回调响应"""
        xml_response = f"""<xml>
<return_code><![CDATA[{return_code}]]></return_code>
<return_msg><![CDATA[{return_msg}]]></return_msg>
</xml>"""

        logger.info(f"返回微信响应: {return_code} - {return_msg}")
        return HttpResponse(xml_response, content_type='application/xml')


# views.py
class YajinShibai(APIView):
    """
    押金支付失败处理接口
    路径：/shangpin/yajinshibai
    请求方式：POST
    权限：JWT认证
    参数：dingdanid（订单ID）
    返回：删除结果
    """
    permission_classes = [IsAuthenticated]

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

            # 2. 查询订单（确保是当前用户的订单）
            try:
                order = Czjilu.objects.get(
                    dingdan_id=dingdanid,
                    yonghuid=request.user.yonghuid
                )
            except Czjilu.DoesNotExist:
                return Response({
                    'code': 400,
                    'message': '订单不存在或不属于当前用户'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 3. 检查订单状态是否为未支付（9）
            if order.zhuangtai == 9:
                # 删除订单
                order.delete()
                logger.info(f"用户{request.user.yonghuid}删除未支付订单: {dingdanid}")

                return Response({
                    'code': 200,
                    'message': '订单已删除'
                }, status=status.HTTP_200_OK)
            else:
                return Response({
                    'code': 400,
                    'message': '订单状态不是未支付，无法删除'
                }, status=status.HTTP_400_BAD_REQUEST)

        except Exception as e:
            logger.error(f"押金支付失败处理异常: {str(e)}", exc_info=True)
            return Response({
                'code': 500,
                'message': '服务器内部错误'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


# views.py
class YajinLunxun(APIView):
    """
    押金支付成功轮询接口
    路径：/shangpin/yajinlunxun
    请求方式：POST
    权限：JWT认证
    参数：dingdanid（订单ID）
    返回：订单状态和当前押金
    """
    permission_classes = [IsAuthenticated]

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

            # 2. 查询订单（确保是当前用户的订单）
            try:
                order = Czjilu.objects.get(
                    dingdan_id=dingdanid,
                    yonghuid=request.user.yonghuid
                )
            except Czjilu.DoesNotExist:
                return Response({
                    'code': 400,
                    'message': '订单不存在或不属于当前用户'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 3. 检查订单状态是否为已支付（3）
            if order.zhuangtai != 3:
                logger.info(f"订单{dingdanid}尚未支付完成，当前状态: {order.zhuangtai}")
                return Response({
                    'code': 400,
                    'message': '订单尚未支付完成'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 4. 获取打手押金（通过反向查询，最快捷的方式）
            try:
                dashou = request.user.dashou_profile
                yajin = float(dashou.yajin)  # 转为浮点数方便前端处理

                logger.info(f"轮询成功: 订单{dingdanid}已支付，用户{request.user.yonghuid}押金为{yajin}元")

                return Response({
                    'code': 200,
                    'message': '支付流程全部完成',
                    'yajin': yajin  # 返回当前押金（前端需要更新全局变量）
                }, status=status.HTTP_200_OK)

            except UserDashou.DoesNotExist:
                logger.error(f"打手信息不存在: 用户{request.user.yonghuid}")
                return Response({
                    'code': 400,
                    'message': '打手信息不存在'
                }, status=status.HTTP_400_BAD_REQUEST)

        except Exception as e:
            logger.error(f"押金轮询异常: {str(e)}", exc_info=True)
            return Response({
                'code': 500,
                'message': '服务器内部错误'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


# views.py
class JifenBuchong(APIView):
    """
    积分补充支付参数接口
    路径：/shangpin/jifenbc
    请求方式：POST
    权限：JWT认证
    参数：无（固定5元）
    返回：支付参数(payParams)和订单ID(dingdanid)
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # 1. 验证用户身份和状态
            try:
                dashou = request.user.dashou_profile
            except UserDashou.DoesNotExist:
                return Response({
                    'code': 400,
                    'message': '用户不是打手，无法补充积分'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 2. 检查打手账号状态
            if dashou.zhanghaozhuangtai != 1:
                return Response({
                    'code': 400,
                    'message': '账号状态异常，无法进行操作'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 3. 检查积分是否已满（满分10分）
            if dashou.jifen >= 10:
                return Response({
                    'code': 400,
                    'message': '积分已满，无需补充'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 4. 生成订单ID（前缀CzJF表示积分充值）
            timestamp_ms = int(time.time() * 1000)
            timestamp_ns = int(time.time_ns() // 1000) % 1000000
            random_num = random.randint(0, 99)

            dingdanid = f"CzJF{timestamp_ms:011d}{timestamp_ns:06d}{random_num:02d}"

            # 5. 创建积分充值记录订单（固定5元）
            jine = 5.00  # 固定5元
            chongzhi_jilu = Czjilu.objects.create(
                dingdan_id=dingdanid,
                zhuangtai=9,  # 未支付状态
                yonghuid=request.user.yonghuid,
                jine=jine,
                leixing=3,  # 充值类型：3=积分
                shuoming=settings.JIFEN_PAY_DESCRIPTION
            )

            logger.info(f"创建积分充值订单: 用户{request.user.yonghuid}, 订单{dingdanid}, 金额{jine}元")

            # 6. 生成微信支付参数（完整版）
            try:
                pay_params = self.generate_wechat_pay_params(
                    dingdanid=dingdanid,
                    jine=jine,
                    openid=request.user.openid,
                    pay_type='jifen'
                )
            except Exception as e:
                # 支付参数生成失败，删除订单记录
                chongzhi_jilu.delete()
                logger.error(f"生成积分支付参数失败: {str(e)}")
                return Response({
                    'code': 500,
                    'message': f'支付参数生成失败: {str(e)}'
                }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

            # 7. 返回支付参数和订单ID
            return Response({
                'code': 200,
                'message': '支付参数生成成功',
                'payParams': pay_params,  # 对应前端payParams
                'dingdanid': dingdanid  # 对应前端dingdanid
            }, status=status.HTTP_200_OK)

        except Exception as e:
            logger.error(f"积分充值接口异常: {str(e)}", exc_info=True)
            return Response({
                'code': 500,
                'message': '服务器内部错误，请稍后重试'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def generate_wechat_pay_params(self, dingdanid, jine, openid, pay_type):
        """生成微信支付参数（完整版，无省略）"""
        # 微信支付配置 - 从settings中获取
        APPID = settings.WEIXIN_APPID
        MCHID = settings.WEIXIN_MCHID
        KEY = settings.WEIXIN_SHANGHUMIYAO

        # 根据支付类型获取对应的配置
        if pay_type == 'yajin':
            PAY_DESCRIPTION = settings.YAJIN_PAY_DESCRIPTION
            NOTIFY_URL = settings.YAJIN_PAY_NOTIFY_URL
        elif pay_type == 'jifen':
            PAY_DESCRIPTION = settings.JIFEN_PAY_DESCRIPTION
            NOTIFY_URL = settings.JIFEN_PAY_NOTIFY_URL
        elif pay_type == 'huiyuan':
            PAY_DESCRIPTION = settings.HUIYUAN_PAY_DESCRIPTION
            NOTIFY_URL = settings.HUIYUAN_PAY_NOTIFY_URL
        else:
            raise Exception('未知的支付类型')

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

        # 金额转换（元转分）
        total_fee = int(jine * 100)

        # 交易类型（小程序支付使用JSAPI）
        trade_type = 'JSAPI'

        # 获取客户端IP
        user_ip = self.get_client_ip()

        # 1. 第一次签名（统一下单接口）
        sign_data = {
            'appid': APPID,
            'mch_id': MCHID,
            'nonce_str': nonce_str,
            'body': PAY_DESCRIPTION,
            'out_trade_no': dingdanid,
            'total_fee': total_fee,
            'spbill_create_ip': user_ip,
            'notify_url': NOTIFY_URL,
            'trade_type': trade_type,
            'openid': 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>{PAY_DESCRIPTION}</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
            prepay_id = root.find('prepay_id').text

            # 2. 第二次签名（小程序支付参数）
            timestamp = str(int(time.time()))
            nonce_str = ''.join(random.choices(string.ascii_letters + string.digits, k=32))
            package = f'prepay_id={prepay_id}'
            sign_type = 'MD5'

            # 生成支付签名（注意：这里key的大小写和字段名与第一次不同）
            pay_sign_data = {
                'appId': APPID,  # 注意：这里是appId，不是appid
                'timeStamp': timestamp,  # 注意：这里是timeStamp，不是timestamp
                'nonceStr': nonce_str,
                'package': package,
                'signType': sign_type
            }

            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()

            # 返回前端需要的支付参数
            return {
                'appId': APPID,  # 对应前端：appId
                'timeStamp': timestamp,  # 对应前端：timeStamp
                'nonceStr': nonce_str,  # 对应前端：nonceStr
                'package': package,  # 对应前端：package
                'signType': sign_type,  # 对应前端：signType
                'paySign': pay_sign  # 对应前端：paySign
            }
        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}")

    def get_client_ip(self):
        """获取客户端IP（完整版）"""
        request = self.request
        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 if ip else '127.0.0.1'


# views.py
class JifenHuitiao(View):
    """
    积分支付回调接口
    路径：/shangpin/jifenhuitiao
    注意：这个接口不需要JWT认证，由微信服务器调用
    """

    def post(self, request):
        try:
            # 1. 解析微信回调XML数据
            request_body = request.body
            logger.info(f"收到积分支付回调，原始数据: {request_body.decode('utf-8')}")

            root = ET.fromstring(request_body)

            # 获取关键字段
            return_code = root.find('return_code').text
            result_code = root.find('result_code').text
            out_trade_no = root.find('out_trade_no').text  # 订单ID
            transaction_id = root.find('transaction_id').text  # 微信交易号
            total_fee = int(root.find('total_fee').text)  # 支付金额（分）

            logger.info(f"积分回调数据: 订单{out_trade_no}, 状态{return_code}/{result_code}, 金额{total_fee}分")

            # 2. 验证基本返回状态
            if return_code != 'SUCCESS' or result_code != 'SUCCESS':
                logger.warning(f"积分支付回调状态异常: {return_code}/{result_code}")
                return self.wechat_response('FAIL', '支付失败')

            # 3. 验证签名
            if not self.verify_signature(request_body):
                logger.error(f"积分签名验证失败: {out_trade_no}")
                return self.wechat_response('FAIL', '签名验证失败')

            # 4. 查询订单
            try:
                order = Czjilu.objects.get(dingdan_id=out_trade_no)
                logger.info(f"找到积分订单: {order.dingdan_id}, 状态: {order.zhuangtai}, 金额: {order.jine}")
            except Czjilu.DoesNotExist:
                logger.error(f"积分订单不存在: {out_trade_no}")
                return self.wechat_response('FAIL', '订单不存在')

            # 5. 检查订单状态是否为未支付（9）
            if order.zhuangtai != 9:
                logger.warning(f"积分订单状态不是未支付: {order.dingdan_id}, 当前状态: {order.zhuangtai}")
                return self.wechat_response('SUCCESS', 'OK')

            # 6. 验证金额（固定5元）
            wechat_amount_yuan = total_fee / 100  # 转换为元
            order_amount_yuan = float(order.jine)  # 订单金额（元）

            # 验证是否是5元（允许1分钱误差）
            if abs(wechat_amount_yuan - 5.00) > 0.01:
                logger.error(f"积分金额错误: 订单金额{order_amount_yuan}元, 支付金额{wechat_amount_yuan}元")
                return self.wechat_response('FAIL', '金额错误')

            # ==== 在返回成功响应之前添加这段代码 ====

            # 更新收支记录表
            try:
                from peizhi.models import Szjilu
                from decimal import Decimal

                # 获取订单金额（确保是Decimal类型）
                jine_decimal = Decimal(str(order.jine)) if not isinstance(order.jine, Decimal) else order.jine

                # 查询或创建ID=1的收支记录

                from dingdan.utils import update_daily_income
                update_daily_income(jine_decimal)

                szjilu, created = Szjilu.objects.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()

                logger.info(f"收支记录更新成功: 订单{order.dingdan_id}, 金额{jine_decimal}元")

            except Exception as e:
                # 收支记录更新失败不影响主流程，只记录日志
                logger.error(f"更新收支记录失败: {str(e)}", exc_info=True)

            # ==== 添加结束 ====

            # 7. 更新订单状态为已支付（3）
            order.zhuangtai = 3
            order.save(update_fields=['zhuangtai'])
            logger.info(f"积分订单状态更新成功: {order.dingdan_id} -> 3")

            # 8. 更新打手积分
            try:
                # 通过用户ID查找打手
                dashou = UserDashou.objects.get(user__yonghuid=order.yonghuid)

                # 检查积分是否小于10
                if dashou.jifen < 10:
                    # 增加5积分，但不超过10
                    new_jifen = dashou.jifen + 5
                    dashou.jifen = min(new_jifen, 10)  # 确保不超过10
                    dashou.save(update_fields=['jifen'])

                    logger.info(f"打手积分更新成功: 用户{order.yonghuid}, 增加5积分, 新积分{dashou.jifen}")




                else:
                    logger.warning(f"打手积分已满: 用户{order.yonghuid}, 当前积分{dashou.jifen}")

            except UserDashou.DoesNotExist:
                logger.error(f"打手信息不存在: 用户{order.yonghuid}")
                return self.wechat_response('SUCCESS', 'OK')
            except Exception as e:
                logger.error(f"更新打手积分失败: {str(e)}", exc_info=True)
                return self.wechat_response('FAIL', '更新积分失败')

            # 9. 返回成功响应给微信
            logger.info(f"积分支付回调处理完成: {out_trade_no}")
            return self.wechat_response('SUCCESS', 'OK')

        except ET.ParseError as e:
            logger.error(f"积分XML解析失败: {str(e)}")
            return self.wechat_response('FAIL', '数据格式错误')
        except Exception as e:
            logger.error(f"积分支付回调处理异常: {str(e)}", exc_info=True)
            return self.wechat_response('FAIL', '处理异常')

    def verify_signature(self, xml_data):
        """验证微信支付签名"""
        try:
            root = ET.fromstring(xml_data)
            sign = root.find('sign').text

            if not sign:
                logger.error("积分数签名字段不存在")
                return False

            # 获取所有参数并排除sign
            params = {}
            for child in root:
                if child.tag != 'sign' and child.text is not None:
                    params[child.tag] = child.text

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

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

            # 计算签名
            calculated_sign = hashlib.md5(sign_string.encode('utf-8')).hexdigest().upper()

            is_valid = sign == calculated_sign
            if not is_valid:
                logger.error(f"积分签名验证失败: 计算签名{calculated_sign}, 收到签名{sign}")

            return is_valid

        except Exception as e:
            logger.error(f"积分验证签名异常: {str(e)}")
            return False

    def wechat_response(self, return_code, return_msg):
        """返回微信支付回调响应"""
        xml_response = f"""<xml>
<return_code><![CDATA[{return_code}]]></return_code>
<return_msg><![CDATA[{return_msg}]]></return_msg>
</xml>"""

        logger.info(f"积分返回微信响应: {return_code} - {return_msg}")
        return HttpResponse(xml_response, content_type='application/xml')


# views.py
class JifenShibai(APIView):
    """
    积分支付失败处理接口
    路径：/shangpin/jifenshibai
    请求方式：POST
    权限：JWT认证
    参数：dingdanid（订单ID）
    返回：删除结果
    """
    permission_classes = [IsAuthenticated]

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

            # 2. 查询订单（确保是当前用户的订单）
            try:
                order = Czjilu.objects.get(
                    dingdan_id=dingdanid,
                    yonghuid=request.user.yonghuid
                )
            except Czjilu.DoesNotExist:
                return Response({
                    'code': 400,
                    'message': '订单不存在或不属于当前用户'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 3. 检查订单类型是否为积分（3）
            if order.leixing != 3:
                return Response({
                    'code': 400,
                    'message': '订单类型错误，不是积分订单'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 4. 检查订单状态是否为未支付（9）
            if order.zhuangtai == 9:
                # 删除订单
                order.delete()
                logger.info(f"用户{request.user.yonghuid}删除未支付积分订单: {dingdanid}")

                return Response({
                    'code': 200,
                    'message': '积分订单已删除'
                }, status=status.HTTP_200_OK)
            else:
                return Response({
                    'code': 400,
                    'message': '积分订单状态不是未支付，无法删除'
                }, status=status.HTTP_400_BAD_REQUEST)

        except Exception as e:
            logger.error(f"积分支付失败处理异常: {str(e)}", exc_info=True)
            return Response({
                'code': 500,
                'message': '服务器内部错误'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


# views.py
class JifenLunxun(APIView):
    """
    积分支付成功轮询接口
    路径：/shangpin/jifenlunxun
    请求方式：POST
    权限：JWT认证
    参数：dingdanid（订单ID）
    返回：订单状态和当前积分
    """
    permission_classes = [IsAuthenticated]

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

            # 2. 查询订单（确保是当前用户的订单）
            try:
                order = Czjilu.objects.get(
                    dingdan_id=dingdanid,
                    yonghuid=request.user.yonghuid
                )
            except Czjilu.DoesNotExist:
                return Response({
                    'code': 400,
                    'message': '订单不存在或不属于当前用户'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 3. 检查订单类型是否为积分（3）
            if order.leixing != 3:
                return Response({
                    'code': 400,
                    'message': '订单类型错误，不是积分订单'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 4. 检查订单状态是否为已支付（3）
            if order.zhuangtai != 3:
                logger.info(f"积分订单{dingdanid}尚未支付完成，当前状态: {order.zhuangtai}")
                return Response({
                    'code': 400,
                    'message': '积分订单尚未支付完成'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 5. 获取打手积分（通过反向查询）
            try:
                dashou = request.user.dashou_profile
                jifen = dashou.jifen  # 直接使用整数

                logger.info(f"积分轮询成功: 订单{dingdanid}已支付，用户{request.user.yonghuid}积分为{jifen}")

                return Response({
                    'code': 200,
                    'message': '支付流程全部完成',
                    'jifen': jifen  # 返回当前积分（前端需要更新全局变量）
                }, status=status.HTTP_200_OK)

            except UserDashou.DoesNotExist:
                logger.error(f"打手信息不存在: 用户{request.user.yonghuid}")
                return Response({
                    'code': 400,
                    'message': '打手信息不存在'
                }, status=status.HTTP_400_BAD_REQUEST)

        except Exception as e:
            logger.error(f"积分轮询异常: {str(e)}", exc_info=True)
            return Response({
                'code': 500,
                'message': '服务器内部错误'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


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

import logging

logger = logging.getLogger(__name__)


class HuiyuanGoumai(APIView):
    """
    会员充值支付参数接口
    路径：/shangpin/huiyuangm
    请求方式：POST
    权限：JWT认证
    参数：huiyuanid（会员ID）
    返回：支付参数(payParams)和订单ID(dingdanid)
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # 1. 获取会员ID参数
            huiyuanid = request.data.get('huiyuanid')
            if not huiyuanid:
                return Response({
                    'code': 400,
                    'message': '会员ID不能为空'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 2. 验证用户身份和状态
            try:
                dashou = request.user.dashou_profile
            except UserDashou.DoesNotExist:
                return Response({
                    'code': 400,
                    'message': '用户不是打手，无法购买会员'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 3. 检查打手账号状态
            if dashou.zhanghaozhuangtai != 1:
                return Response({
                    'code': 400,
                    'message': '账号状态异常，无法进行购买'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 4. 查询会员信息
            try:
                huiyuan = Huiyuan.objects.get(huiyuan_id=huiyuanid)
            except Huiyuan.DoesNotExist:
                return Response({
                    'code': 400,
                    'message': '会员信息不存在'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 5. 生成订单ID（前缀CzHY表示会员充值）
            timestamp_ms = int(time.time() * 1000)
            timestamp_ns = int(time.time_ns() // 1000) % 1000000
            random_num = random.randint(0, 99)

            dingdanid = f"CzHY{timestamp_ms:011d}{timestamp_ns:06d}{random_num:02d}"

            # 6. 创建充值记录订单
            jine = float(huiyuan.jiage)  # 会员价格
            # 组合订单说明：会员介绍 + 配置描述
            shuoming = f"{huiyuan.jieshao} - {settings.HUIYUAN_PAY_DESCRIPTION}"

            chongzhi_jilu = Czjilu.objects.create(
                dingdan_id=dingdanid,
                zhuangtai=9,  # 未支付状态
                yonghuid=request.user.yonghuid,
                jine=jine,
                leixing=1,  # 充值类型：1=会员
                shuoming=shuoming,
                huiyuan_id=huiyuanid  # 存储会员ID
            )

            logger.info(
                f"创建会员充值订单: 用户{request.user.yonghuid}, 订单{dingdanid}, 会员{huiyuanid}, 金额{jine}元")

            # 7. 生成微信支付参数
            try:
                pay_params = self.generate_wechat_pay_params(
                    dingdanid=dingdanid,
                    jine=jine,
                    openid=request.user.openid,
                    pay_type='huiyuan'
                )
            except Exception as e:
                # 支付参数生成失败，删除订单记录
                chongzhi_jilu.delete()
                logger.error(f"生成会员支付参数失败: {str(e)}")
                return Response({
                    'code': 500,
                    'message': f'支付参数生成失败: {str(e)}'
                }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

            # 8. 返回支付参数和订单ID
            return Response({
                'code': 200,
                'message': '支付参数生成成功',
                'payParams': pay_params,  # 对应前端payParams
                'dingdanid': dingdanid  # 对应前端dingdanid
            }, status=status.HTTP_200_OK)

        except Exception as e:
            logger.error(f"会员充值接口异常: {str(e)}", exc_info=True)
            return Response({
                'code': 500,
                'message': '服务器内部错误，请稍后重试'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def generate_wechat_pay_params(self, dingdanid, jine, openid, pay_type):
        """生成微信支付参数（完整版，无省略）"""
        # 微信支付配置 - 从settings中获取
        APPID = settings.WEIXIN_APPID
        MCHID = settings.WEIXIN_MCHID
        KEY = settings.WEIXIN_SHANGHUMIYAO

        # 根据支付类型获取对应的配置
        if pay_type == 'yajin':
            PAY_DESCRIPTION = settings.YAJIN_PAY_DESCRIPTION
            NOTIFY_URL = settings.YAJIN_PAY_NOTIFY_URL
        elif pay_type == 'jifen':
            PAY_DESCRIPTION = settings.JIFEN_PAY_DESCRIPTION
            NOTIFY_URL = settings.JIFEN_PAY_NOTIFY_URL
        elif pay_type == 'huiyuan':
            PAY_DESCRIPTION = settings.HUIYUAN_PAY_DESCRIPTION
            NOTIFY_URL = settings.HUIYUAN_PAY_NOTIFY_URL
        else:
            raise Exception('未知的支付类型')

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

        # 金额转换（元转分）
        total_fee = int(jine * 100)

        # 交易类型（小程序支付使用JSAPI）
        trade_type = 'JSAPI'

        # 获取客户端IP
        user_ip = self.get_client_ip()

        # 1. 第一次签名（统一下单接口）
        sign_data = {
            'appid': APPID,
            'mch_id': MCHID,
            'nonce_str': nonce_str,
            'body': PAY_DESCRIPTION,
            'out_trade_no': dingdanid,
            'total_fee': total_fee,
            'spbill_create_ip': user_ip,
            'notify_url': NOTIFY_URL,
            'trade_type': trade_type,
            'openid': 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>{PAY_DESCRIPTION}</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
            prepay_id = root.find('prepay_id').text

            # 2. 第二次签名（小程序支付参数）
            timestamp = str(int(time.time()))
            nonce_str = ''.join(random.choices(string.ascii_letters + string.digits, k=32))
            package = f'prepay_id={prepay_id}'
            sign_type = 'MD5'

            # 生成支付签名（注意：这里key的大小写和字段名与第一次不同）
            pay_sign_data = {
                'appId': APPID,  # 注意：这里是appId，不是appid
                'timeStamp': timestamp,  # 注意：这里是timeStamp，不是timestamp
                'nonceStr': nonce_str,
                'package': package,
                'signType': sign_type
            }

            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()

            # 返回前端需要的支付参数
            return {
                'appId': APPID,  # 对应前端：appId
                'timeStamp': timestamp,  # 对应前端：timeStamp
                'nonceStr': nonce_str,  # 对应前端：nonceStr
                'package': package,  # 对应前端：package
                'signType': sign_type,  # 对应前端：signType
                'paySign': pay_sign  # 对应前端：paySign
            }
        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}")

    def get_client_ip(self):
        """获取客户端IP（完整版）"""
        request = self.request
        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 if ip else '127.0.0.1'


# views.py

from django.views import View
from django.http import HttpResponse
from yonghu.models import UserDashou, UserMain, UserGuanshi,UserZuzhang
from shangpin.models import Czjilu, Huiyuan, Huiyuangoumai, Gsfenhong,DuociFenhong
from peizhi.models import Szjilu
from datetime import timedelta
import logging

logger = logging.getLogger(__name__)



class HuiyuanHuitiao(View):
    """
    会员支付回调接口
    路径：/shangpin/huiyuanhuitiao
    """

    def post(self, request):
        try:
            # 1. 解析微信回调XML数据
            request_body = request.body
            logger.info(f"收到会员支付回调，原始数据: {request_body.decode('utf-8')}")

            root = ET.fromstring(request_body)

            return_code = root.find('return_code').text
            result_code = root.find('result_code').text
            out_trade_no = root.find('out_trade_no').text
            transaction_id = root.find('transaction_id').text
            total_fee = int(root.find('total_fee').text)

            logger.info(f"会员回调数据: 订单{out_trade_no}, 状态{return_code}/{result_code}, 金额{total_fee}分")

            if return_code != 'SUCCESS' or result_code != 'SUCCESS':
                logger.warning(f"会员支付回调状态异常: {return_code}/{result_code}")
                return self.wechat_response('FAIL', '支付失败')

            if not self.verify_signature(request_body):
                logger.error(f"会员签名验证失败: {out_trade_no}")
                return self.wechat_response('FAIL', '签名验证失败')

            # 查询订单
            try:
                order = Czjilu.objects.get(dingdan_id=out_trade_no)
            except Czjilu.DoesNotExist:
                logger.error(f"会员订单不存在: {out_trade_no}")
                return self.wechat_response('FAIL', '订单不存在')

            if order.leixing != 1:
                logger.error(f"订单类型错误: {order.leixing}, 期望1(会员)")
                return self.wechat_response('FAIL', '订单类型错误')

            if order.zhuangtai != 9:
                logger.warning(f"会员订单状态不是未支付: {order.dingdan_id}, 当前状态: {order.zhuangtai}")
                return self.wechat_response('SUCCESS', 'OK')

            # 验证金额
            wechat_amount_yuan = total_fee / 100
            order_amount_yuan = float(order.jine)
            if abs(wechat_amount_yuan - order_amount_yuan) > 0.01:
                logger.error(f"会员金额不一致: 订单金额{order_amount_yuan}元, 支付金额{wechat_amount_yuan}元")
                return self.wechat_response('FAIL', '金额不一致')

            # 查询会员信息
            try:
                huiyuan = Huiyuan.objects.get(huiyuan_id=order.huiyuan_id)
            except Huiyuan.DoesNotExist:
                logger.error(f"会员信息不存在: {order.huiyuan_id}")
                return self.wechat_response('FAIL', '会员信息不存在')

            # ===== 更新收支记录 =====
            try:
                jine_decimal = Decimal(str(order.jine)) if not isinstance(order.jine, Decimal) else order.jine

                from dingdan.utils import update_daily_income
                update_daily_income(jine_decimal)

                szjilu, _ = Szjilu.objects.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()
                logger.info(f"收支记录更新成功: 订单{order.dingdan_id}, 金额{jine_decimal}元")
            except Exception as e:
                logger.error(f"更新收支记录失败: {str(e)}", exc_info=True)

            # 更新订单状态
            order.zhuangtai = 3
            order.save(update_fields=['zhuangtai'])
            logger.info(f"会员订单状态更新成功: {order.dingdan_id} -> 3")

            # 更新会员购买次数
            huiyuan.goumai_cishu += 1
            huiyuan.save(update_fields=['goumai_cishu'])

            # 处理会员购买记录
            goumai_record, is_new, is_first_buy = self.process_huiyuan_goumai(
                order.yonghuid, order.huiyuan_id, huiyuan
            )

            if is_first_buy:
                self.add_first_buy_jifen(order.yonghuid)

            # 🆕 新增：处理分红（包含管事和组长）
            with transaction.atomic():
                self.process_fenhong(order, huiyuan)

            logger.info(f"会员支付回调处理完成: {out_trade_no}")
            return self.wechat_response('SUCCESS', 'OK')

        except ET.ParseError as e:
            logger.error(f"会员XML解析失败: {str(e)}")
            return self.wechat_response('FAIL', '数据格式错误')
        except Exception as e:
            logger.error(f"会员支付回调处理异常: {str(e)}", exc_info=True)
            return self.wechat_response('FAIL', '处理异常')

    # ---------- 以下为原方法，基本不变，但需要导入新增模型 ----------

    def process_huiyuan_goumai(self, yonghuid, huiyuan_id, huiyuan):
        """处理会员购买记录（与原代码一致）"""
        try:
            existing_record = Huiyuangoumai.objects.filter(
                yonghu_id=yonghuid,
                huiyuan_id=huiyuan_id
            ).first()

            is_first_buy_any = False

            if existing_record:
                existing_record.daoqi_time += timedelta(days=30)
                existing_record.huiyuan_zhuangtai = 1
                existing_record.save()
                logger.info(f"会员续费: 用户{yonghuid}, 会员{huiyuan_id}")
                return existing_record, False, False
            else:
                other_huiyuan_count = Huiyuangoumai.objects.filter(
                    yonghu_id=yonghuid
                ).exclude(huiyuan_id=huiyuan_id).count()
                if other_huiyuan_count == 0:
                    is_first_buy_any = True
                    logger.info(f"用户{yonghuid}首次购买任何会员，将获得10积分")

                goumai_record = Huiyuangoumai.objects.create(
                    yonghu_id=yonghuid,
                    huiyuan_id=huiyuan_id,
                    jieshao=huiyuan.jieshao,
                    huiyuan_zhuangtai=1,
                    daoqi_time=timezone.now() + timedelta(days=30)
                )
                logger.info(f"新购会员: 用户{yonghuid}, 会员{huiyuan_id}")
                return goumai_record, True, is_first_buy_any
        except Exception as e:
            logger.error(f"处理会员购买记录失败: {str(e)}", exc_info=True)
            if "unique" in str(e).lower() or "duplicate" in str(e).lower():
                logger.warning(f"检测到重复创建尝试，已由数据库拦截: 用户{yonghuid}, 会员{huiyuan_id}")
                return self.process_huiyuan_goumai(yonghuid, huiyuan_id, huiyuan)
            raise

    def add_first_buy_jifen(self, yonghuid):
        """首次购买积分奖励（与原代码一致）"""
        try:
            dashou = UserDashou.objects.get(user__yonghuid=yonghuid)
            dashou.jifen += 10
            dashou.save(update_fields=['jifen'])
            logger.info(f"用户{yonghuid}首次购买会员，积分+10，当前积分: {dashou.jifen}")
        except UserDashou.DoesNotExist:
            logger.error(f"找不到打手记录，无法增加积分: {yonghuid}")
        except Exception as e:
            logger.error(f"增加积分失败: {str(e)}")

    # 🆕 新增：统一分红处理函数
    def process_fenhong(self, order, huiyuan):
        """
        处理管事和组长分红（支持多次分红配置）
        """
        try:
            # 获取打手信息
            dashou = UserDashou.objects.get(user__yonghuid=order.yonghuid)
            guanshi_id = dashou.yaoqingren
            if not guanshi_id:
                logger.info(f"打手{order.yonghuid}没有邀请人，无分红")
                return

            # 获取管事信息
            try:
                guanshi = UserGuanshi.objects.get(user__yonghuid=guanshi_id)
            except UserGuanshi.DoesNotExist:
                logger.warning(f"管事信息不存在: {guanshi_id}")
                return

            # 获取组长ID（从管事扩展表的邀请人）
            zuzhang_id = guanshi.yaoqingren

            # 获取打手头像和昵称
            user_main = dashou.user
            avatar = user_main.avatar
            nicheng = dashou.nicheng or "未知打手"

            # 查询该打手针对该管事的已分红次数
            existing_count = Gsfenhong.objects.filter(
                dashouid=order.yonghuid,
                guanshi=guanshi_id
            ).count()
            cishu = existing_count + 1  # 本次是第几次

            # 获取订单金额（用于限制分红总额）
            order_amount = Decimal(str(order.jine)) if not isinstance(order.jine, Decimal) else order.jine

            # 计算管事分红金额
            guanshi_fenhong = self._calc_guanshi_fenhong(guanshi, huiyuan, guanshi_id, cishu)
            if guanshi_fenhong is None:
                logger.info(f"管事{guanshi_id}本次无分红")
                guanshi_fenhong = Decimal('0.00')

            # 计算组长分红金额（如果存在组长）
            zuzhang_fenhong = Decimal('0.00')
            if zuzhang_id:
                # 获取组长信息
                try:
                    zuzhang = UserZuzhang.objects.get(user__yonghuid=zuzhang_id)
                except UserZuzhang.DoesNotExist:
                    logger.warning(f"组长信息不存在: {zuzhang_id}")
                    zuzhang = None

                zuzhang_fenhong = self._calc_zuzhang_fenhong(zuzhang, huiyuan, zuzhang_id, cishu)
                if zuzhang_fenhong is None:
                    logger.info(f"组长{zuzhang_id}本次无分红")
                    zuzhang_fenhong = Decimal('0.00')
            else:
                logger.info(f"管事{guanshi_id}没有组长，无组长分红")

            # 检查分红总额是否超过订单金额（优先保证管事分红）
            total_fenhong = guanshi_fenhong + zuzhang_fenhong
            if total_fenhong > order_amount:
                logger.warning(f"分红总额{total_fenhong}超过订单金额{order_amount}，组长分红设为0")
                zuzhang_fenhong = Decimal('0.00')
                total_fenhong = guanshi_fenhong
                if total_fenhong > order_amount:
                    logger.warning(f"管事分红{guanshi_fenhong}也超过订单金额，强制设为0")
                    guanshi_fenhong = Decimal('0.00')
                    total_fenhong = Decimal('0.00')

            # 创建分红记录（先创建主记录，即使金额为0也记录？但为0无意义，所以只有大于0才创建）
            if guanshi_fenhong > 0 or zuzhang_fenhong > 0:
                # 更新管事扩展表
                if guanshi_fenhong > 0:
                    guanshi.chongzhifenrun += guanshi_fenhong
                    guanshi.yue += guanshi_fenhong
                    guanshi.jinrichongzhi += 1
                    guanshi.jinyuechongzhi += 1
                    guanshi.save(update_fields=['chongzhifenrun', 'yue', 'jinrichongzhi', 'jinyuechongzhi'])
                    logger.info(f"管事分红成功: 管事{guanshi_id}, 金额{guanshi_fenhong}")

                # 更新组长扩展表
                if zuzhang_fenhong > 0 and zuzhang:
                    zuzhang.fenyong_zonge += zuzhang_fenhong
                    zuzhang.ketixian_jine += zuzhang_fenhong
                    zuzhang.jinri_fenyong += zuzhang_fenhong
                    zuzhang.jinyue_fenyong += zuzhang_fenhong
                    zuzhang.save(update_fields=['fenyong_zonge', 'ketixian_jine', 'jinri_fenyong', 'jinyue_fenyong'])
                    logger.info(f"组长分红成功: 组长{zuzhang_id}, 金额{zuzhang_fenhong}")

                # 创建分红记录
                Gsfenhong.objects.create(
                    dingdan_id=order.dingdan_id,
                    guanshi=guanshi_id,
                    dashouid=order.yonghuid,
                    shuoming=order.shuoming,
                    fenhong=guanshi_fenhong,
                    avatar=avatar,
                    nicheng=nicheng,
                    # 新增字段
                    zuzhang_id=zuzhang_id if zuzhang_fenhong > 0 else None,
                    zuzhang_fenhong=zuzhang_fenhong if zuzhang_fenhong > 0 else None,
                    huiyuan_id=huiyuan.huiyuan_id,
                    fenhong_leixing=1,
                )



                # ========== 管事每日统计（新购） ==========
                if guanshi_fenhong > 0 and cishu == 1:
                    try:
                        from houtai.utils import update_guanshi_daily_by_action
                        update_guanshi_daily_by_action(
                            yonghuid=guanshi_id,
                            action=2,
                            amount=guanshi_fenhong
                        )
                        logger.info(f"管事每日统计更新成功（新购）：管事{guanshi_id}，分红{guanshi_fenhong}")
                    except Exception as e:
                        logger.error(f"管事每日统计更新失败（新购）：{str(e)}")

                # ========== 管事每日统计（续费） ==========
                if guanshi_fenhong > 0 and cishu > 1:
                    try:
                        from houtai.utils import update_guanshi_xufei_daily
                        update_guanshi_xufei_daily(
                            yonghuid=guanshi_id,
                            xufei_jine=guanshi_fenhong
                        )
                        logger.info(f"管事续费统计更新成功：管事{guanshi_id}，续费分红{guanshi_fenhong}")
                    except Exception as e:
                        logger.error(f"管事续费统计更新失败：{str(e)}")

                # ========== 组长每日统计（分佣收入） ==========
                if zuzhang_fenhong > 0 and zuzhang_id:
                    try:
                        from houtai.utils import update_zuzhang_daily_by_action
                        update_zuzhang_daily_by_action(
                            yonghuid=zuzhang_id,
                            action=2,
                            amount=zuzhang_fenhong
                        )
                        logger.info(f"组长每日统计更新成功：组长{zuzhang_id}，分佣{zuzhang_fenhong}")
                    except Exception as e:
                        logger.error(f"组长每日统计更新失败：{str(e)}")


                logger.info(f"分红记录创建成功: 订单{order.dingdan_id}")
            else:
                logger.info(f"分红金额均为0，不创建记录")

        except Exception as e:
            logger.error(f"处理分红失败: {str(e)}", exc_info=True)
            # 不抛出异常，避免影响主流程

    def _calc_guanshi_fenhong(self, guanshi, huiyuan, guanshi_id, cishu):
        """计算管事分红金额"""
        # 先查多次分红配置表
        try:
            config = DuociFenhong.objects.get(
                huiyuan=huiyuan,
                yonghuid=guanshi_id,
                cishu=cishu
            )
            return Decimal(str(config.guanshi_fenhong))
        except DuociFenhong.DoesNotExist:
            pass

        if cishu == 1:
            # 第一次分红，取会员表默认金额
            return Decimal(str(huiyuan.guanshifc))
        else:
            # 第二次及以上，检查是否开启二次分红
            if guanshi.fenghong_erci_enabled:
                return Decimal(str(guanshi.fenghong_erci))
            else:
                return None  # 无分红

    def _calc_zuzhang_fenhong(self, zuzhang, huiyuan, zuzhang_id, cishu):
        """计算组长分红金额"""
        if zuzhang is None:
            return None
        # 查多次分红配置表
        try:
            config = DuociFenhong.objects.get(
                huiyuan=huiyuan,
                yonghuid=zuzhang_id,
                cishu=cishu
            )
            return Decimal(str(config.zuzhang_fenhong))
        except DuociFenhong.DoesNotExist:
            pass

        if cishu == 1:
            # 第一次分红，取会员表默认组长分成
            return Decimal(str(huiyuan.zuzhangfc))
        else:
            # 第二次及以上，检查组长是否开启额外分红
            if zuzhang.kaioi_ewai_fenhong:
                return Decimal(str(zuzhang.ewai_fenhong_jine))
            else:
                return None

    # 以下为原辅助方法，保持原样
    def verify_signature(self, xml_data):
        """验证微信支付签名（与原代码一致）"""
        try:
            root = ET.fromstring(xml_data)
            sign = root.find('sign').text
            if not sign:
                logger.error("会员签名字段不存在")
                return False

            params = {}
            for child in root:
                if child.tag != 'sign' and child.text is not None:
                    params[child.tag] = child.text

            sorted_params = sorted(params.items(), key=lambda x: x[0])
            sign_string = '&'.join([f"{key}={value}" for key, value in sorted_params if value])
            sign_string += f'&key={settings.WEIXIN_SHANGHUMIYAO}'
            calculated_sign = hashlib.md5(sign_string.encode('utf-8')).hexdigest().upper()
            return sign == calculated_sign
        except Exception as e:
            logger.error(f"会员验证签名异常: {str(e)}")
            return False

    def wechat_response(self, return_code, return_msg):
        """返回微信回调响应"""
        xml_response = f"""<xml>
<return_code><![CDATA[{return_code}]]></return_code>
<return_msg><![CDATA[{return_msg}]]></return_msg>
</xml>"""
        logger.info(f"会员返回微信响应: {return_code} - {return_msg}")
        return HttpResponse(xml_response, content_type='application/xml')



'''class HuiyuanHuitiao(View):
    """
    会员支付回调接口
    路径：/shangpin/huiyuanhuitiao
    注意：这个接口不需要JWT认证，由微信服务器调用
    """

    def post(self, request):
        try:
            # 1. 解析微信回调XML数据
            request_body = request.body
            logger.info(f"收到会员支付回调，原始数据: {request_body.decode('utf-8')}")

            root = ET.fromstring(request_body)

            # 获取关键字段
            return_code = root.find('return_code').text
            result_code = root.find('result_code').text
            out_trade_no = root.find('out_trade_no').text  # 订单ID
            transaction_id = root.find('transaction_id').text  # 微信交易号
            total_fee = int(root.find('total_fee').text)  # 支付金额（分）

            logger.info(f"会员回调数据: 订单{out_trade_no}, 状态{return_code}/{result_code}, 金额{total_fee}分")

            # 2. 验证基本返回状态
            if return_code != 'SUCCESS' or result_code != 'SUCCESS':
                logger.warning(f"会员支付回调状态异常: {return_code}/{result_code}")
                return self.wechat_response('FAIL', '支付失败')

            # 3. 验证签名（完整版）
            if not self.verify_signature(request_body):
                logger.error(f"会员签名验证失败: {out_trade_no}")
                return self.wechat_response('FAIL', '签名验证失败')

            # 4. 查询订单
            try:
                order = Czjilu.objects.get(dingdan_id=out_trade_no)
                logger.info(f"找到会员订单: {order.dingdan_id}, 状态: {order.zhuangtai}, 金额: {order.jine}")
            except Czjilu.DoesNotExist:
                logger.error(f"会员订单不存在: {out_trade_no}")
                return self.wechat_response('FAIL', '订单不存在')

            # 5. 检查订单类型是否为会员（1）
            if order.leixing != 1:
                logger.error(f"订单类型错误: {order.leixing}, 期望1(会员)")
                return self.wechat_response('FAIL', '订单类型错误')

            # 6. 检查订单状态是否为未支付（9）
            if order.zhuangtai != 9:
                logger.warning(f"会员订单状态不是未支付: {order.dingdan_id}, 当前状态: {order.zhuangtai}")
                return self.wechat_response('SUCCESS', 'OK')

            # 7. 验证金额
            wechat_amount_yuan = total_fee / 100  # 转换为元
            order_amount_yuan = float(order.jine)  # 订单金额（元）

            # 允许1分钱的误差
            if abs(wechat_amount_yuan - order_amount_yuan) > 0.01:
                logger.error(f"会员金额不一致: 订单金额{order_amount_yuan}元, 支付金额{wechat_amount_yuan}元")
                return self.wechat_response('FAIL', '金额不一致')

            # 8. 查询会员信息
            try:
                huiyuan = Huiyuan.objects.get(huiyuan_id=order.huiyuan_id)
            except Huiyuan.DoesNotExist:
                logger.error(f"会员信息不存在: {order.huiyuan_id}")
                return self.wechat_response('FAIL', '会员信息不存在')

            # ===== 在这里添加收支记录更新代码 =====
            # 更新收支记录表
            try:
                from peizhi.models import Szjilu
                from decimal import Decimal

                # 获取订单金额（确保是Decimal类型）
                jine_decimal = Decimal(str(order.jine)) if not isinstance(order.jine, Decimal) else order.jine

                # 查询或创建ID=1的收支记录
                szjilu, created = Szjilu.objects.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()

                logger.info(f"收支记录更新成功: 订单{order.dingdan_id}, 金额{jine_decimal}元")

            except Exception as e:
                # 收支记录更新失败不影响主流程，只记录日志
                logger.error(f"更新收支记录失败: {str(e)}", exc_info=True)
            # ===== 添加结束 =====


            # 9. 更新订单状态为已支付（3）
            order.zhuangtai = 3
            order.save(update_fields=['zhuangtai'])
            logger.info(f"会员订单状态更新成功: {order.dingdan_id} -> 3")

            # 10. 更新会员表的购买次数
            huiyuan.goumai_cishu += 1
            huiyuan.save(update_fields=['goumai_cishu'])

            # 11. 处理会员购买记录
            #self.process_huiyuan_goumai(order.yonghuid, order.huiyuan_id, huiyuan)
            goumai_record, is_new, is_first_buy = self.process_huiyuan_goumai(
                order.yonghuid, order.huiyuan_id, huiyuan
            )

            # 12. 如果是首次购买任何会员，加10积分
            if is_first_buy:
                self.add_first_buy_jifen(order.yonghuid)

            # 12. 处理管事分红（只有在第一次购买时才分红）
            self.process_guanshi_fenhong(order, huiyuan)

            # 13. 返回成功响应给微信
            logger.info(f"会员支付回调处理完成: {out_trade_no}")
            return self.wechat_response('SUCCESS', 'OK')

        except ET.ParseError as e:
            logger.error(f"会员XML解析失败: {str(e)}")
            return self.wechat_response('FAIL', '数据格式错误')
        except Exception as e:
            logger.error(f"会员支付回调处理异常: {str(e)}", exc_info=True)
            return self.wechat_response('FAIL', '处理异常')

    def process_huiyuan_goumai(self, yonghuid, huiyuan_id, huiyuan):
        """处理会员购买记录（优化版）"""
        try:
            # 1. 先尝试获取现有记录（如果存在就是续费）
            existing_record = Huiyuangoumai.objects.filter(
                yonghu_id=yonghuid,
                huiyuan_id=huiyuan_id
            ).first()

            is_first_buy_any = False  # 标记是否首次购买任何会员

            if existing_record:
                # 已存在记录，续费
                existing_record.daoqi_time += timedelta(days=30)
                existing_record.huiyuan_zhuangtai = 1
                existing_record.save()
                logger.info(f"会员续费: 用户{yonghuid}, 会员{huiyuan_id}")
                return existing_record, False, False  # (记录, 是否新建, 是否首次买任何)
            else:
                # 2. 检查是否是首次购买任何会员（关键查询！）
                # 查询该用户是否买过其他会员
                other_huiyuan_count = Huiyuangoumai.objects.filter(
                    yonghu_id=yonghuid
                ).exclude(huiyuan_id=huiyuan_id).count()  # 排除本次会员

                if other_huiyuan_count == 0:
                    # 这是该用户第一次买任何会员！
                    is_first_buy_any = True
                    logger.info(f"用户{yonghuid}首次购买任何会员，将获得10积分")

                # 3. 创建新记录
                goumai_record = Huiyuangoumai.objects.create(
                    yonghu_id=yonghuid,
                    huiyuan_id=huiyuan_id,
                    jieshao=huiyuan.jieshao,
                    huiyuan_zhuangtai=1,
                    daoqi_time=timezone.now() + timedelta(days=30)
                )
                logger.info(f"新购会员: 用户{yonghuid}, 会员{huiyuan_id}")
                return goumai_record, True, is_first_buy_any

        except Exception as e:
            logger.error(f"处理会员购买记录失败: {str(e)}", exc_info=True)
            # 如果是因为唯一约束冲突（数据库已拦截）
            if "unique" in str(e).lower() or "duplicate" in str(e).lower():
                logger.warning(f"检测到重复创建尝试，已由数据库拦截: 用户{yonghuid}, 会员{huiyuan_id}")
                # 重新查询并续费
                return self.process_huiyuan_goumai(yonghuid, huiyuan_id, huiyuan)
            raise

    def add_first_buy_jifen(self, yonghuid):
        """为首次购买会员的用户增加10积分"""
        try:
            # 找到对应的打手记录
            dashou = UserDashou.objects.get(user__yonghuid=yonghuid)
            # 增加10积分
            dashou.jifen += 10
            dashou.save(update_fields=['jifen'])
            logger.info(f"用户{yonghuid}首次购买会员，积分+10，当前积分: {dashou.jifen}")

            # 可选：记录积分变动历史
            # self.create_jifen_history(yonghuid, 10, "首次购买会员奖励")

        except UserDashou.DoesNotExist:
            logger.error(f"找不到打手记录，无法增加积分: {yonghuid}")
        except Exception as e:
            logger.error(f"增加积分失败: {str(e)}")

    def process_guanshi_fenhong(self, order, huiyuan):
        """
        处理管事分红（支持首次和二次分红，特殊用户首次可配置）
        """
        try:
            # 1. 获取打手信息
            dashou = UserDashou.objects.get(user__yonghuid=order.yonghuid)
            yaoqingren = dashou.yaoqingren
            if not yaoqingren:
                logger.info(f"打手{order.yonghuid}没有邀请人，无分红")
                return

            # 2. 获取管事信息
            try:
                guanshi = UserGuanshi.objects.get(user__yonghuid=yaoqingren)
            except UserGuanshi.DoesNotExist:
                logger.warning(f"管事信息不存在: {yaoqingren}")
                return

            # 3. 获取打手头像和昵称
            user_main = dashou.user
            avatar = user_main.avatar
            nicheng = dashou.nicheng or "未知打手"

            # 4. 判断是该打手第几次分红（通过查询分红记录表）
            existing_count = Gsfenhong.objects.filter(dashouid=order.yonghuid).count()
            is_first = (existing_count == 0)  # 第一次分红

            # 5. 确定分红金额
            fenhong_amount = None
            if is_first:
                # 首次分红
                special_ids = getattr(settings, 'SPECIAL_GUANSHI_IDS', [])
                if yaoqingren in special_ids:
                    # 特殊管事：从管事扩展表获取首次分红金额
                    fenhong_amount = guanshi.fenhong_yici
                    logger.info(f"管事{yaoqingren}为特殊用户，首次分红金额取配置值: {fenhong_amount}")
                else:
                    # 普通管事：从会员配置表获取分红金额
                    fenhong_amount = huiyuan.guanshifc
                    logger.info(f"管事{yaoqingren}为普通用户，首次分红金额取会员表: {fenhong_amount}")
            else:
                # 第二次及以上分红（目前只支持第二次）
                if guanshi.fenghong_erci_enabled:
                    fenhong_amount = guanshi.fenghong_erci
                    logger.info(f"管事{yaoqingren}开启二次分红，分红金额: {fenhong_amount}")
                else:
                    logger.info(f"管事{yaoqingren}未开启二次分红，本次不分红")
                    return

            # 6. 如果分红金额 <= 0，则不分红
            if fenhong_amount <= 0:
                logger.info(f"分红金额 {fenhong_amount} <=0，不分红")
                return

            # 7. 创建分红记录（注意：dashouid 唯一约束已移除）
            Gsfenhong.objects.create(
                dingdan_id=order.dingdan_id,
                guanshi=yaoqingren,
                dashouid=order.yonghuid,
                shuoming=order.shuoming,
                fenhong=fenhong_amount,
                avatar=avatar,
                nicheng=nicheng
            )

            # 8. 更新管事扩展表
            guanshi.chongzhifenrun += fenhong_amount
            guanshi.yue += fenhong_amount
            guanshi.jinrichongzhi += 1
            guanshi.jinyuechongzhi += 1
            guanshi.save(update_fields=['chongzhifenrun', 'yue', 'jinrichongzhi', 'jinyuechongzhi'])

            logger.info(f"创建分红记录成功: 管事{yaoqingren}, 打手{order.yonghuid}, 分红{fenhong_amount}元")

        except Exception as e:
            logger.error(f"处理管事分红失败: {str(e)}", exc_info=True)
            # 继续执行，不中断主流程





    #不针对特殊用户，且不含二次分红的版本
    #
    #
    #
    #
    #
    #
    def process_guanshi_fenhong(self, order, huiyuan):
        """处理管事分红（完整版，只有第一次购买才分红）"""
        try:
            # 查询打手信息
            dashou = UserDashou.objects.get(user__yonghuid=order.yonghuid)

            # 检查是否已有分红记录（确保只有第一次购买才分红）
            if Gsfenhong.objects.filter(dashouid=order.yonghuid).exists():
                logger.info(f"打手{order.yonghuid}已有分红记录，不再分红")
                return

            # 获取管事ID（邀请人ID）
            yaoqingren = dashou.yaoqingren
            if not yaoqingren:
                logger.info(f"打手{order.yonghuid}没有邀请人，无分红")
                return

            # 查询管事信息
            try:
                guanshi = UserGuanshi.objects.get(user__yonghuid=yaoqingren)
            except UserGuanshi.DoesNotExist:
                logger.warning(f"管事信息不存在: {yaoqingren}")
                return

            # 获取打手头像和昵称
            user_main = dashou.user
            avatar = user_main.avatar
            nicheng = dashou.nicheng or "未知打手"

            # 创建分红记录
            fenhong_record = Gsfenhong.objects.create(
                dingdan_id=order.dingdan_id,
                guanshi=yaoqingren,
                dashouid=order.yonghuid,
                shuoming=order.shuoming,
                fenhong=huiyuan.guanshifc,  # 管事分成金额
                avatar=avatar,
                nicheng=nicheng
            )

            # 更新管事扩展表数据
            guanshi.chongzhifenrun += huiyuan.guanshifc
            guanshi.yue += huiyuan.guanshifc
            guanshi.jinrichongzhi += 1
            guanshi.jinyuechongzhi += 1
            guanshi.save(update_fields=['chongzhifenrun', 'yue', 'jinrichongzhi', 'jinyuechongzhi'])

            logger.info(f"创建分红记录: 管事{yaoqingren}, 打手{order.yonghuid}, 分成{huiyuan.guanshifc}元")

        except Exception as e:
            logger.error(f"处理管事分红失败: {str(e)}", exc_info=True)
            #
            #
            #
            #
            #
            # 继续执行，不中断主流程
            

    def verify_signature(self, xml_data):
        """验证微信支付签名（完整版）"""
        try:
            root = ET.fromstring(xml_data)
            sign = root.find('sign').text

            if not sign:
                logger.error("会员签名字段不存在")
                return False

            # 获取所有参数并排除sign
            params = {}
            for child in root:
                if child.tag != 'sign' and child.text is not None:
                    params[child.tag] = child.text

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

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

            # 计算签名
            calculated_sign = hashlib.md5(sign_string.encode('utf-8')).hexdigest().upper()

            is_valid = sign == calculated_sign
            if not is_valid:
                logger.error(f"会员签名验证失败: 计算签名{calculated_sign}, 收到签名{sign}")

            return is_valid

        except Exception as e:
            logger.error(f"会员验证签名异常: {str(e)}")
            return False

    def wechat_response(self, return_code, return_msg):
        """返回微信支付回调响应（完整版）"""
        xml_response = f"""<xml>
<return_code><![CDATA[{return_code}]]></return_code>
<return_msg><![CDATA[{return_msg}]]></return_msg>
</xml>"""

        logger.info(f"会员返回微信响应: {return_code} - {return_msg}")
        return HttpResponse(xml_response, content_type='application/xml')'''


# views.py
class HuiyuanShibai(APIView):
    """
    会员支付失败处理接口
    路径：/shangpin/huiyuanshibai
    请求方式：POST
    权限：JWT认证
    参数：dingdanid（订单ID）
    返回：删除结果
    """
    permission_classes = [IsAuthenticated]

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

            # 2. 查询订单（确保是当前用户的订单）
            try:
                order = Czjilu.objects.get(
                    dingdan_id=dingdanid,
                    yonghuid=request.user.yonghuid
                )
            except Czjilu.DoesNotExist:
                return Response({
                    'code': 400,
                    'message': '订单不存在或不属于当前用户'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 3. 检查订单类型是否为会员（1）
            if order.leixing != 1:
                return Response({
                    'code': 400,
                    'message': '订单类型错误，不是会员订单'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 4. 检查订单状态是否为未支付（9）
            if order.zhuangtai == 9:
                # 删除订单
                order.delete()
                logger.info(f"用户{request.user.yonghuid}删除未支付会员订单: {dingdanid}")

                return Response({
                    'code': 200,
                    'message': '会员订单已删除'
                }, status=status.HTTP_200_OK)
            else:
                return Response({
                    'code': 400,
                    'message': '会员订单状态不是未支付，无法删除'
                }, status=status.HTTP_400_BAD_REQUEST)

        except Exception as e:
            logger.error(f"会员支付失败处理异常: {str(e)}", exc_info=True)
            return Response({
                'code': 500,
                'message': '服务器内部错误'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


# views.py
class HuiyuanLunxun(APIView):
    """
    会员支付成功轮询接口
    路径：/shangpin/huiyuanlx
    请求方式：POST
    权限：JWT认证
    参数：dingdanid（订单ID）
    返回：订单状态和会员信息
    """
    permission_classes = [IsAuthenticated]

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

            # 2. 查询订单（确保是当前用户的订单）
            try:
                order = Czjilu.objects.get(
                    dingdan_id=dingdanid,
                    yonghuid=request.user.yonghuid
                )
            except Czjilu.DoesNotExist:
                return Response({
                    'code': 400,
                    'message': '订单不存在或不属于当前用户'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 3. 检查订单类型是否为会员（1）
            if order.leixing != 1:
                return Response({
                    'code': 400,
                    'message': '订单类型错误，不是会员订单'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 4. 检查订单状态是否为已支付（3）
            if order.zhuangtai != 3:
                logger.info(f"会员订单{dingdanid}尚未支付完成，当前状态: {order.zhuangtai}")
                return Response({
                    'code': 400,
                    'message': '会员订单尚未支付完成'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 5. 查询会员信息
            try:
                huiyuan = Huiyuan.objects.get(huiyuan_id=order.huiyuan_id)

                # 6. 查询会员购买记录
                goumai_record = Huiyuangoumai.objects.filter(
                    yonghu_id=request.user.yonghuid,
                    huiyuan_id=order.huiyuan_id
                ).first()

                if not goumai_record:
                    return Response({
                        'code': 400,
                        'message': '会员购买记录不存在'
                    }, status=status.HTTP_400_BAD_REQUEST)

                # 7. 格式化到期时间
                #from django.utils.timezone import localtime
                #daoqi_time = localtime(goumai_record.daoqi_time).strftime('%Y-%m-%d %H:%M:%S')
                daoqi_time = goumai_record.daoqi_time.strftime('%Y-%m-%d %H:%M:%S')
                current_user = request.user
                dashou = current_user.dashou_profile

                logger.info(f"会员轮询成功: 订单{dingdanid}已支付，用户{request.user.yonghuid}, 会员{order.huiyuan_id}")

                # 8. 返回会员信息（用于更新前端全局变量）
                return Response({
                    'code': 200,
                    'message': '支付流程全部完成',
                    'jifen': dashou.jifen,
                    'huiyuan': {
                        'huiyuanid': order.huiyuan_id,
                        'huiyuanming': huiyuan.jieshao,
                        'daoqi': daoqi_time,

                    }
                }, status=status.HTTP_200_OK)

            except Huiyuan.DoesNotExist:
                logger.error(f"会员信息不存在: {order.huiyuan_id}")
                return Response({
                    'code': 400,
                    'message': '会员信息不存在'
                }, status=status.HTTP_400_BAD_REQUEST)

        except Exception as e:
            logger.error(f"会员轮询异常: {str(e)}", exc_info=True)
            return Response({
                'code': 500,
                'message': '服务器内部错误'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)



# views.py in shangpin app
import time
import random
import string
import hashlib
import xml.etree.ElementTree as ET
import requests
from decimal import Decimal
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 yonghu.models import UserMain, UserShangjia
from shangpin.models import Czjilu
import logging

logger = logging.getLogger(__name__)


class ShangjiaChongzhi(APIView):
    """
    商家余额充值支付参数接口
    路径：/shangpin/sjcz
    请求方式：POST
    权限：JWT认证
    参数：jine（金额，1-10000元）
    返回：支付参数(payParams)和订单ID(dingdanid)
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # 1. 验证用户身份和商家状态
            try:
                shangjia = request.user.shop_profile
            except UserShangjia.DoesNotExist:
                logger.warning(f"用户{request.user.yonghuid}尝试充值但不是商家")
                return Response({
                    'code': 400,
                    'message': '用户不是商家，无法充值'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 检查商家状态
            if shangjia.zhuangtai != 1:
                logger.warning(f"商家{shangjia.nicheng}状态异常: {shangjia.zhuangtai}")
                return Response({
                    'code': 400,
                    'message': '商家状态异常，无法进行充值'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 2. 获取并验证金额参数
            jine = request.data.get('jine')
            if not jine:
                return Response({
                    'code': 400,
                    'message': '请填写充值金额'
                }, status=status.HTTP_400_BAD_REQUEST)

            try:
                jine = float(jine)
            except (ValueError, TypeError):
                return Response({
                    'code': 400,
                    'message': '金额格式错误，请填写有效的数字'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 验证金额范围
            if jine < settings.SHANGJIA_CZ_MIN_AMOUNT or jine > settings.SHANGJIA_CZ_MAX_AMOUNT:
                return Response({
                    'code': 400,
                    'message': f'充值金额必须在{settings.SHANGJIA_CZ_MIN_AMOUNT}-{settings.SHANGJIA_CZ_MAX_AMOUNT}元之间'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 3. 生成订单ID（使用配置的前缀）
            timestamp_ms = int(time.time() * 1000)
            timestamp_ns = int(time.time_ns() // 1000) % 1000000
            random_num = random.randint(0, 99)

            dingdanid = f"{settings.SHANGJIA_CZ_PREFIX}{timestamp_ms:011d}{timestamp_ns:06d}{random_num:02d}"

            # 4. 创建充值记录订单
            try:
                chongzhi_jilu = Czjilu.objects.create(
                    dingdan_id=dingdanid,
                    zhuangtai=9,  # 未支付状态
                    yonghuid=request.user.yonghuid,
                    jine=jine,
                    leixing=4,  # 充值类型：4=商家充值
                    shuoming=settings.SHANGJIA_CZ_PAY_DESCRIPTION
                )
                logger.info(f"创建商家充值订单: 商家{shangjia.nicheng}, 订单{dingdanid}, 金额{jine}元")
            except Exception as e:
                logger.error(f"创建订单失败: {str(e)}")
                return Response({
                    'code': 500,
                    'message': '订单创建失败，请重试'
                }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

            # 5. 生成微信支付参数
            try:
                pay_params = self.generate_wechat_pay_params(
                    dingdanid=dingdanid,
                    jine=jine,
                    openid=request.user.openid,
                    pay_type='shangjia'
                )
            except Exception as e:
                # 支付参数生成失败，删除订单记录
                chongzhi_jilu.delete()
                logger.error(f"生成微信支付参数失败: {str(e)}")
                return Response({
                    'code': 500,
                    'message': f'支付参数生成失败: {str(e)}'
                }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

            # 6. 返回支付参数和订单ID
            logger.info(f"商家{shangjia.nicheng}支付参数生成成功: {dingdanid}")
            return Response({
                'code': 200,
                'message': '支付参数生成成功',
                'payParams': pay_params,
                'dingdanid': dingdanid
            }, status=status.HTTP_200_OK)

        except Exception as e:
            logger.error(f"商家充值接口异常: {str(e)}", exc_info=True)
            return Response({
                'code': 500,
                'message': '服务器内部错误，请稍后重试'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def generate_wechat_pay_params(self, dingdanid, jine, openid, pay_type):
        """生成微信小程序支付参数"""
        # 获取配置
        APPID = settings.WEIXIN_APPID
        MCHID = settings.WEIXIN_MCHID
        KEY = settings.WEIXIN_SHANGHUMIYAO

        # 根据支付类型获取对应的配置
        if pay_type == 'shangjia':
            PAY_DESCRIPTION = settings.SHANGJIA_CZ_PAY_DESCRIPTION
            NOTIFY_URL = settings.SHANGJIA_CZ_PAY_NOTIFY_URL
        else:
            raise Exception('未知的支付类型')

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

        # 金额转换（元转分）
        total_fee = int(Decimal(str(jine)) * 100)

        # 交易类型（小程序支付使用JSAPI）
        trade_type = 'JSAPI'

        # 获取客户端IP
        user_ip = self.get_client_ip()

        # 1. 第一次签名（统一下单接口）
        sign_data = {
            'appid': APPID,
            'mch_id': MCHID,
            'nonce_str': nonce_str,
            'body': PAY_DESCRIPTION,
            'out_trade_no': dingdanid,
            'total_fee': total_fee,
            'spbill_create_ip': user_ip,
            'notify_url': NOTIFY_URL,
            'trade_type': trade_type,
            'openid': 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>{PAY_DESCRIPTION}</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
            prepay_id = root.find('prepay_id').text

            # 2. 第二次签名（小程序支付参数）
            timestamp = str(int(time.time()))
            nonce_str = ''.join(random.choices(string.ascii_letters + string.digits, k=32))
            package = f'prepay_id={prepay_id}'
            sign_type = 'MD5'

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

            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()

            # 返回前端需要的支付参数
            return {
                'appId': APPID,
                'timeStamp': timestamp,
                'nonceStr': nonce_str,
                'package': package,
                'signType': sign_type,
                'paySign': pay_sign
            }
        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}")

    def get_client_ip(self):
        """获取客户端IP"""
        request = self.request
        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 if ip else '127.0.0.1'



from django.db import transaction

logger = logging.getLogger(__name__)


class ShangjiaHuitiao(View):
    """
    商家支付回调接口
    路径：/shangpin/sjhuitiao
    注意：这个接口不需要JWT认证，由微信服务器调用
    """

    def post(self, request):
        try:
            # 1. 解析微信回调XML数据
            request_body = request.body
            logger.info(f"收到商家支付回调，原始数据: {request_body.decode('utf-8')}")

            root = ET.fromstring(request_body)

            # 获取关键字段
            return_code = root.find('return_code').text
            result_code = root.find('result_code').text
            out_trade_no = root.find('out_trade_no').text  # 订单ID
            transaction_id = root.find('transaction_id').text  # 微信交易号
            total_fee = int(root.find('total_fee').text)  # 支付金额（分）

            logger.info(f"商家回调数据解析: 订单{out_trade_no}, 状态{return_code}/{result_code}, 金额{total_fee}分")

            # 2. 验证基本返回状态
            if return_code != 'SUCCESS' or result_code != 'SUCCESS':
                logger.warning(f"商家支付回调状态异常: {return_code}/{result_code}")
                return self.wechat_response('FAIL', '支付失败')

            # 3. 验证签名（确保是微信发来的）
            if not self.verify_signature(request_body):
                logger.error(f"商家支付签名验证失败: {out_trade_no}")
                return self.wechat_response('FAIL', '签名验证失败')

            # 4. 查询订单
            try:
                from decimal import Decimal
                order = Czjilu.objects.get(dingdan_id=out_trade_no)
                logger.info(f"找到商家订单: {order.dingdan_id}, 状态: {order.zhuangtai}, 金额: {order.jine}")
            except Czjilu.DoesNotExist:
                logger.error(f"商家订单不存在: {out_trade_no}")
                return self.wechat_response('FAIL', '订单不存在')

            # 5. 检查订单状态是否为未支付（9）
            if order.zhuangtai != 9:
                logger.warning(f"商家订单状态不是未支付: {order.dingdan_id}, 当前状态: {order.zhuangtai}")
                # 已处理过的订单直接返回成功，避免微信重复回调
                return self.wechat_response('SUCCESS', 'OK')

            # 6. 验证金额（微信返回的是分，需要转换）
            wechat_amount_yuan = Decimal(str(total_fee)) / Decimal('100')  # 转换为元
            order_amount_yuan = Decimal(str(order.jine))  # 订单金额（元）

            # 允许1分钱的误差
            if abs(wechat_amount_yuan - order_amount_yuan) > Decimal('0.01'):
                logger.error(f"商家订单金额不一致: 订单金额{order_amount_yuan}元, 支付金额{wechat_amount_yuan}元")
                return self.wechat_response('FAIL', '金额不一致')

            # ===== 在这里添加收支记录更新代码 =====
            # 更新收支记录表
            try:
                from peizhi.models import Szjilu
                from decimal import Decimal

                # 获取订单金额（确保是Decimal类型）
                jine_decimal = Decimal(str(order.jine)) if not isinstance(order.jine, Decimal) else order.jine

                # 查询或创建ID=1的收支记录

                from dingdan.utils import update_daily_income
                update_daily_income(jine_decimal)

                szjilu, created = Szjilu.objects.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()

                logger.info(f"收支记录更新成功: 订单{order.dingdan_id}, 金额{jine_decimal}元")

            except Exception as e:
                # 收支记录更新失败不影响主流程，只记录日志
                logger.error(f"更新收支记录失败: {str(e)}", exc_info=True)
            # ===== 添加结束 =====



            # 7. 使用事务更新订单状态和商家余额
            with transaction.atomic():
                # 更新订单状态为已支付（3）
                order.zhuangtai = 3
                order.save(update_fields=['zhuangtai'])
                logger.info(f"商家订单状态更新成功: {order.dingdan_id} -> 3")

                # 更新商家余额
                try:
                    # 通过用户ID查找商家（高效查询）
                    shangjia = UserShangjia.objects.get(user__yonghuid=order.yonghuid)

                    # 增加余额
                    shangjia.yue += order_amount_yuan
                    shangjia.save(update_fields=['yue'])

                    logger.info(f"商家余额更新成功: 商家{shangjia.nicheng}, 增加{order_amount_yuan}元, 新余额{shangjia.yue}")

                except UserShangjia.DoesNotExist:
                    # 如果找不到商家，记录错误，但依然返回成功（避免微信重复回调）
                    logger.error(f"商家信息不存在: 用户{order.yonghuid}")
                    return self.wechat_response('SUCCESS', 'OK')
                except Exception as e:
                    logger.error(f"更新商家余额失败: {str(e)}", exc_info=True)
                    # 回滚事务
                    raise

            # 8. 返回成功响应给微信
            logger.info(f"商家支付回调处理完成: {out_trade_no}")
            return self.wechat_response('SUCCESS', 'OK')

        except ET.ParseError as e:
            logger.error(f"XML解析失败: {str(e)}")
            return self.wechat_response('FAIL', '数据格式错误')
        except Exception as e:
            logger.error(f"商家支付回调处理异常: {str(e)}", exc_info=True)
            # 返回FAIL让微信重试
            return self.wechat_response('FAIL', '处理异常')

    def verify_signature(self, xml_data):
        """验证微信支付签名"""
        try:
            root = ET.fromstring(xml_data)
            sign = root.find('sign').text

            if not sign:
                logger.error("签名字段不存在")
                return False

            # 获取所有参数并排除sign
            params = {}
            for child in root:
                if child.tag != 'sign' and child.text is not None:
                    params[child.tag] = child.text

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

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

            # 计算签名
            calculated_sign = hashlib.md5(sign_string.encode('utf-8')).hexdigest().upper()

            is_valid = sign == calculated_sign
            if not is_valid:
                logger.error(f"商家支付签名验证失败: 计算签名{calculated_sign}, 收到签名{sign}")

            return is_valid

        except Exception as e:
            logger.error(f"验证签名异常: {str(e)}")
            return False

    def wechat_response(self, return_code, return_msg):
        """返回微信支付回调响应"""
        xml_response = f"""<xml>
<return_code><![CDATA[{return_code}]]></return_code>
<return_msg><![CDATA[{return_msg}]]></return_msg>
</xml>"""

        logger.info(f"返回微信响应: {return_code} - {return_msg}")
        return HttpResponse(xml_response, content_type='application/xml')




# views.py
class ShangjiaShibai(APIView):
    """
    商家支付失败处理接口
    路径：/shangpin/sjshibai
    请求方式：POST
    权限：JWT认证
    参数：dingdanid（订单ID）
    返回：删除结果
    """
    permission_classes = [IsAuthenticated]

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

            # 2. 查询订单（确保是当前用户的订单）
            try:
                order = Czjilu.objects.get(
                    dingdan_id=dingdanid,
                    yonghuid=request.user.yonghuid,
                    leixing=4  # 确保是商家充值订单
                )
            except Czjilu.DoesNotExist:
                logger.warning(f"商家订单不存在或不属于当前用户: {dingdanid}, 用户{request.user.yonghuid}")
                return Response({
                    'code': 400,
                    'message': '订单不存在或不属于当前用户'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 3. 检查订单状态是否为未支付（9）
            if order.zhuangtai == 9:
                # 删除订单
                order.delete()
                logger.info(f"商家{request.user.shop_profile.nicheng}删除未支付订单: {dingdanid}")

                return Response({
                    'code': 200,
                    'message': '订单已删除'
                }, status=status.HTTP_200_OK)
            else:
                return Response({
                    'code': 400,
                    'message': '订单状态不是未支付，无法删除'
                }, status=status.HTTP_400_BAD_REQUEST)

        except UserShangjia.DoesNotExist:
            return Response({
                'code': 400,
                'message': '用户不是商家'
            }, status=status.HTTP_400_BAD_REQUEST)
        except Exception as e:
            logger.error(f"商家支付失败处理异常: {str(e)}", exc_info=True)
            return Response({
                'code': 500,
                'message': '服务器内部错误'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)



# views.py
class ShangjiaChenggong(APIView):
    """
    商家支付成功轮询接口
    路径：/shangpin/sjcg
    请求方式：POST
    权限：JWT认证
    参数：dingdanid（订单ID）
    返回：订单状态和当前商家余额
    """
    permission_classes = [IsAuthenticated]

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

            # 2. 查询订单（确保是当前用户的商家订单）
            try:
                order = Czjilu.objects.get(
                    dingdan_id=dingdanid,
                    yonghuid=request.user.yonghuid,
                    leixing=4  # 商家充值类型
                )
            except Czjilu.DoesNotExist:
                logger.warning(f"商家订单不存在: {dingdanid}, 用户{request.user.yonghuid}")
                return Response({
                    'code': 400,
                    'message': '订单不存在或不属于当前用户'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 3. 检查订单状态是否为已支付（3）
            if order.zhuangtai != 3:
                logger.info(f"商家订单{dingdanid}尚未支付完成，当前状态: {order.zhuangtai}")
                return Response({
                    'code': 400,
                    'message': '订单尚未支付完成'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 4. 获取商家余额（通过反向查询）
            try:
                shangjia = request.user.shop_profile
                yue = float(shangjia.yue)  # 转为浮点数方便前端处理

                logger.info(f"商家轮询成功: 订单{dingdanid}已支付，商家{shangjia.nicheng}余额为{yue}元")

                return Response({
                    'code': 200,
                    'message': '支付流程全部完成',
                    'yue': yue  # 返回当前商家余额（前端需要更新全局变量）
                }, status=status.HTTP_200_OK)

            except UserShangjia.DoesNotExist:
                logger.error(f"商家信息不存在: 用户{request.user.yonghuid}")
                return Response({
                    'code': 400,
                    'message': '商家信息不存在'
                }, status=status.HTTP_400_BAD_REQUEST)

        except Exception as e:
            logger.error(f"商家轮询异常: {str(e)}", exc_info=True)
            return Response({
                'code': 500,
                'message': '服务器内部错误'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


# 管事分红记录查询API

from django.db.models import Q
from decimal import Decimal
import logging

logger = logging.getLogger(__name__)


class GuanshiFenhongListAPI(APIView):
    """
    管事分红记录查询接口
    权限：需要JWT认证
    请求方式：POST
    分页参数：page, page_size
    """

    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # 获取当前管事用户ID
            yonghuid = request.user.yonghuid

            # 获取分页参数
            page = int(request.data.get('page', 1))
            page_size = int(request.data.get('page_size', 50))

            if page < 1:
                page = 1
            if page_size < 1 or page_size > 100:  # 限制最大100条
                page_size = 50

            # 计算偏移量
            offset = (page - 1) * page_size

            # 查询条件：管事ID匹配
            query = Q(guanshi=yonghuid)

            # 先查询总数（使用分页查询优化）
            from django.db.models import Count
            from .models import Gsfenhong

            # 查询总记录数
            zong_tiaoshu = Gsfenhong.objects.filter(query).count()

            # 查询去重后的打手数量
            chongzhi_dashou_shuliang = Gsfenhong.objects.filter(query).values('dashouid').distinct().count()

            # 查询当前页数据，按创建时间倒序排列
            fenhong_list = Gsfenhong.objects.filter(query) \
                .order_by('-create_time') \
                .values('dashouid', 'avatar', 'nicheng', 'fenhong', 'create_time')[offset:offset + page_size]

            # 格式化数据
            formatted_list = []
            for item in fenhong_list:
                formatted_list.append({
                    'yonghuid': item['dashouid'],  # 打手ID
                    'avatar': item['avatar'] or '',  # 打手头像
                    'nicheng': item['nicheng'] or '未知用户',  # 打手昵称
                    'fenhong': str(item['fenhong']),  # 分红金额
                    'create_time': item['create_time'].strftime('%Y-%m-%d %H:%M:%S') if item['create_time'] else ''
                })

            # 返回数据
            return Response({
                'code': 200,
                'msg': '成功',
                'data': {
                    'list': formatted_list,
                    'total': zong_tiaoshu,  # 总记录数
                    'chongzhi_dashou_shuliang': chongzhi_dashou_shuliang,  # 充值打手数量（去重）
                    'page': page,
                    'page_size': page_size,
                    'has_more': len(formatted_list) == page_size  # 是否还有更多数据
                }
            })

        except Exception as e:
            logger.error(f"查询管事分红记录失败: {str(e)}", exc_info=True)
            return Response({
                'code': 500,
                'msg': f'服务器错误: {str(e)}',
                'data': {}
            })


# views.py - 商品模块视图

from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from rest_framework import status
from django.db.models import Q
import logging

# 导入模型
from yonghu.models import UserMain, AdminProfile
from shangpin.models import ShangpinLeixing, ShangpinZhuanqu, Huiyuan

# 日志记录器
logger = logging.getLogger(__name__)


class AdGetAllDataView(APIView):
    """
    获取商品类型、商品专区、会员数据的接口
    接口地址：/shangpin/adhqlx
    请求方法：POST
    权限要求：JWT Token认证 + 管理员权限
    """

    # 需要JWT Token认证
    permission_classes = [IsAuthenticated]

    def post(self, request):
        """
        处理POST请求，返回商品相关数据
        """
        try:
            # 1. 获取请求数据
            zhanghao = request.data.get('zhanghao')

            if not zhanghao:
                logger.warning(f"管理员接口：未接收到账号参数，请求用户：{request.user.yonghuid}")
                return Response({
                    'code': 400,
                    'message': '缺少账号参数',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 2. 获取当前登录用户
            current_user = request.user

            # 3. 验证用户类型是否为管理员
            if current_user.user_type != 'admin':
                logger.warning(
                    f"权限验证失败：用户 {current_user.yonghuid} 的用户类型为 {current_user.user_type}，非管理员")
                return Response({
                    'code': 401,
                    'message': '无管理员权限',
                    'data': None
                }, status=status.HTTP_401_UNAUTHORIZED)

            # 4. 验证手机号与传递的账号是否一致
            if current_user.phone != zhanghao:
                logger.warning(
                    f"账号验证失败：用户 {current_user.yonghuid} 的phone={current_user.phone}，传递的zhanghao={zhanghao}")
                return Response({
                    'code': 401,
                    'message': '账号验证失败',
                    'data': None
                }, status=status.HTTP_401_UNAUTHORIZED)

            # 5. 验证管理员扩展表是否存在
            try:
                admin_profile = current_user.admin_profile
                logger.info(f"管理员验证通过：用户 {current_user.yonghuid}，手机号 {current_user.phone}")
            except AdminProfile.DoesNotExist:
                logger.error(
                    f"管理员扩展表不存在：用户 {current_user.yonghuid} 虽然user_type=admin，但没有AdminProfile记录")
                return Response({
                    'code': 401,
                    'message': '管理员信息不完整',
                    'data': None
                }, status=status.HTTP_401_UNAUTHORIZED)

            # 6. 查询商品类型数据
            try:
                # 使用select_related或prefetch_related优化查询（如果需要关联查询）
                # 这里直接查询所有字段，然后提取需要的字段
                shangpinleixing_queryset = ShangpinLeixing.objects.all()

                # 转换为前端需要的格式
                shangpinleixing_list = []
                for leixing in shangpinleixing_queryset:
                    leixing_data = {
                        'id': leixing.id,
                        'yaoqiuleixing': leixing.yaoqiuleixing if leixing.yaoqiuleixing is not None else None,
                        'huiyuan_id': leixing.huiyuan_id if leixing.huiyuan_id else None,
                        'yongjin': str(leixing.yongjin) if leixing.yongjin is not None else None,
                        'jieshao': leixing.jieshao if leixing.jieshao else '',
                        'tupian_url': leixing.tupian_url if leixing.tupian_url else ''
                    }
                    shangpinleixing_list.append(leixing_data)

                #logger.info(f"成功查询到 {len(shangpinleixing_list)} 条商品类型数据")

            except Exception as e:
                logger.error(f"查询商品类型数据时出错：{str(e)}")
                shangpinleixing_list = []

            # 7. 查询商品专区数据
            try:
                # 查询所有商品专区
                zhuanqu_queryset = ShangpinZhuanqu.objects.all()

                # 转换为前端需要的格式
                zhuanqu_list = []
                for zhuanqu in zhuanqu_queryset:
                    zhuanqu_data = {
                        'id': zhuanqu.id,
                        'mingzi': zhuanqu.mingzi if zhuanqu.mingzi else '',
                        'leixing_id': zhuanqu.leixing_id
                    }
                    zhuanqu_list.append(zhuanqu_data)

               # logger.info(f"成功查询到 {len(zhuanqu_list)} 条商品专区数据")

            except Exception as e:
                logger.error(f"查询商品专区数据时出错：{str(e)}")
                zhuanqu_list = []

            # 8. 查询会员数据
            try:
                # 查询所有会员
                huiyuan_queryset = Huiyuan.objects.all()

                # 转换为前端需要的格式
                huiyuan_list = []
                for huiyuan in huiyuan_queryset:
                    huiyuan_data = {
                        'huiyuan_id': huiyuan.huiyuan_id,
                        'jieshao': huiyuan.jieshao,
                        'jiage': str(huiyuan.jiage)  # Decimal转为字符串
                    }
                    huiyuan_list.append(huiyuan_data)

              #  logger.info(f"成功查询到 {len(huiyuan_list)} 条会员数据")

            except Exception as e:
                logger.error(f"查询会员数据时出错：{str(e)}")
                huiyuan_list = []

            # 9. 检查会员列表是否为空
            if not huiyuan_list:
                logger.warning("会员列表为空，可能会影响商品发布功能")

            # 10. 组织返回数据
            response_data = {
                'code': 0,
                'message': '获取数据成功',
                'data': {
                    'shangpinleixingList': shangpinleixing_list,
                    'zhuanquList': zhuanqu_list,
                    'huiyuanList': huiyuan_list
                }
            }

            return Response(response_data, status=status.HTTP_200_OK)

        except Exception as e:
            # 捕获未预期的异常
            logger.error(f"接口处理异常：{str(e)}", exc_info=True)
            return Response({
                'code': 500,
                'message': f'服务器内部错误：{str(e)}',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


# views.py - shangpin模块
from django.db import transaction
from rest_framework.views import APIView
from rest_framework import permissions, status
from rest_framework.response import Response
from django.shortcuts import get_object_or_404
from rest_framework.parsers import MultiPartParser, FormParser, JSONParser
import os
import uuid

# 导入模型和工具
from .models import ShangpinLeixing, Huiyuan, ShangpinZhuanqu, Shangpin
from yonghu.models import UserMain, AdminProfile
from utils.oss_utils import validate_image, upload_to_oss


class ShangpinLeixingFabuView(APIView):
    """
    商品类型发布接口
    接收图片、类型介绍、抢单要求类型等字段
    需要管理员权限
    """
    permission_classes = [permissions.IsAuthenticated]
    parser_classes = (MultiPartParser, FormParser)  # 需要处理文件上传

    def post(self, request):
        try:
            # === 1. 权限验证 ===
            # 获取当前用户
            user_main = request.user

            # 1.1 验证前端传递的账号是否匹配（使用phone字段）
            zhanghao = request.data.get('zhanghao', '').strip()
            if not zhanghao:
                return Response(
                    {'code': 401, 'msg': '未提供账号信息', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 验证账号是否匹配（使用phone字段比较）
            if user_main.phone != zhanghao:
                return Response(
                    {'code': 401, 'msg': '账号验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 1.2 验证是否为管理员（检查user_type字段）
            if user_main.user_type != 'admin':
                return Response(
                    {'code': 401, 'msg': '权限不足', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 1.3 验证管理员扩展表（使用AdminProfile模型）
            try:
                admin_profile = AdminProfile.objects.get(user=user_main)
            except AdminProfile.DoesNotExist:
                return Response(
                    {'code': 401, 'msg': '管理员信息不存在', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # === 2. 接收并验证字段 ===
            # 2.1 必填字段验证
            jieshao = request.data.get('jieshao', '').strip()
            yaoqiuleixing = request.data.get('yaoqiuleixing')


            if not jieshao:
                return Response(
                    {'code': 400, 'msg': '类型介绍不能为空', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            if yaoqiuleixing not in ['1', '2']:
                return Response(
                    {'code': 400, 'msg': '抢单要求类型无效', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 2.2 验证图片
            tupian_file = request.FILES.get('file')
            if not tupian_file:

                return Response(
                    {'code': 400, 'msg': '请上传类型图片', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 验证图片格式和大小
            is_valid, error_msg = validate_image(tupian_file)
            if not is_valid:
                return Response(
                    {'code': 400, 'msg': f'图片验证失败: {error_msg}', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 2.3 根据抢单要求类型验证对应字段
            huiyuan_id = request.data.get('huiyuan_id', '').strip()
            yongjin = request.data.get('yongjin', '').strip()


            # 转换yaoqiuleixing为整数便于处理
            yaoqiuleixing_int = int(yaoqiuleixing)

            if yaoqiuleixing_int == 1:  # 会员抢单
                if not huiyuan_id:
                    return Response(
                        {'code': 400, 'msg': '会员抢单必须选择会员', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )
                # 验证会员ID是否存在
                try:
                    huiyuan_obj = Huiyuan.objects.get(huiyuan_id=huiyuan_id)
                except Huiyuan.DoesNotExist:
                    return Response(
                        {'code': 400, 'msg': '会员ID不存在', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )
                # 会员ID为字符串，佣金为空
                yongjin_value = None
                huiyuan_id_value = huiyuan_id
            else:  # yaoqiuleixing_int == 2 佣金抢单
                if not yongjin:
                    return Response(
                        {'code': 400, 'msg': '佣金抢单必须填写佣金金额', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )
                try:
                    # 验证佣金为有效数字
                    yongjin_value = float(yongjin)
                    if yongjin_value <= 0:
                        return Response(
                            {'code': 400, 'msg': '佣金金额必须大于0', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST
                        )
                except ValueError:
                    return Response(
                        {'code': 400, 'msg': '佣金金额格式错误', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )
                huiyuan_id_value = None

            # === 3. 创建商品类型记录 ===
            with transaction.atomic():
                # 3.1 创建商品类型对象
                leixing_obj = ShangpinLeixing(
                    jieshao=jieshao,
                    yaoqiuleixing=yaoqiuleixing_int,
                    huiyuan_id=huiyuan_id_value,
                    yongjin=yongjin_value,
                    # tupian_url 先留空，上传成功后再更新
                )

                # 保存到数据库获取ID
                leixing_obj.save()
                leixing_id = leixing_obj.id

                # === 4. 处理图片上传 ===
                try:
                    # 4.1 生成文件名和路径
                    file_extension = os.path.splitext(tupian_file.name)[1].lower()
                    if not file_extension:
                        file_extension = '.jpg'

                    # 生成唯一文件名：商品类型ID + 随机UUID + 后缀
                    unique_filename = f"{leixing_id}_{uuid.uuid4().hex}{file_extension}"

                    # 构建OSS文件路径：a_long/leixing/{leixing_id}/{filename}
                    oss_folder = 'a_long'  # 根文件夹
                    leixing_folder = 'leixing'  # 类型文件夹

                    # 构建完整路径
                    oss_file_path = f"{oss_folder}/{leixing_folder}/{leixing_id}/{unique_filename}"

                    # 4.2 上传到OSS
                    tupian_url = upload_to_oss(tupian_file, oss_file_path)

                    if not tupian_url:
                        # 上传失败，抛出异常触发回滚
                        raise Exception("图片上传到OSS失败")

                    # 4.3 更新商品类型的图片URL（存储相对路径）
                    leixing_obj.tupian_url = oss_file_path  # 存相对路径，方便拼接
                    leixing_obj.save()

                except Exception as oss_error:
                    # 图片上传失败，事务会回滚，商品类型记录也会被删除
                    print(f"OSS上传失败: {oss_error}")
                    # 手动抛出异常触发事务回滚
                    raise Exception(f"图片上传失败: {str(oss_error)}")

                # === 5. 构建返回数据 ===
                response_data = {
                    'id': leixing_id,
                    'jieshao': jieshao,
                    'yaoqiuleixing': yaoqiuleixing_int,
                    'tupian_url': leixing_obj.tupian_url,  # 相对路径
                    'huiyuan_id': huiyuan_id_value,
                    'yongjin': str(yongjin_value) if yongjin_value else None
                }

                # 返回成功响应
                return Response({
                    'code': 0,
                    'msg': '商品类型添加成功',
                    'data': response_data
                })

        except Exception as e:
            # 捕获所有异常，返回500错误
            import traceback
            traceback.print_exc()
            return Response({
                'code': 500,
                'msg': f'系统错误: {str(e)}',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class ShangpinZhuanquFabuView(APIView):
    """
    商品专区发布接口
    接收专区名称、类型ID
    需要管理员权限
    """
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        try:
            # === 1. 权限验证 ===
            user_main = request.user

            # 1.1 验证账号（使用phone字段）
            zhanghao = request.data.get('zhanghao', '').strip()
            if not zhanghao:
                return Response(
                    {'code': 401, 'msg': '未提供账号信息', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            if user_main.phone != zhanghao:
                return Response(
                    {'code': 401, 'msg': '账号验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 1.2 验证是否为管理员（检查user_type字段）
            if user_main.user_type != 'admin':
                return Response(
                    {'code': 401, 'msg': '权限不足', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 1.3 验证管理员扩展表（使用AdminProfile模型）
            try:
                admin_profile = AdminProfile.objects.get(user=user_main)
            except AdminProfile.DoesNotExist:
                return Response(
                    {'code': 401, 'msg': '管理员信息不存在', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # === 2. 接收并验证字段 ===
            mingzi = request.data.get('mingzi', '').strip()
            leixing_id = request.data.get('leixing_id')

            # 2.1 验证必填字段
            if not mingzi:
                return Response(
                    {'code': 400, 'msg': '专区名称不能为空', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            if not leixing_id:
                return Response(
                    {'code': 400, 'msg': '类型ID不能为空', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 2.2 验证类型ID是否存在
            try:
                # 验证商品类型是否存在
                leixing_obj = ShangpinLeixing.objects.get(id=leixing_id)
            except ShangpinLeixing.DoesNotExist:
                return Response(
                    {'code': 400, 'msg': '商品类型不存在', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 2.3 验证名称长度（15汉字以内）
            if len(mingzi) > 45:  # 数据库字段最大长度
                return Response(
                    {'code': 400, 'msg': '专区名称过长', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # === 3. 创建商品专区记录 ===
            zhuanqu_obj = ShangpinZhuanqu(
                mingzi=mingzi,
                leixing_id=leixing_id
            )

            zhuanqu_obj.save()

            # === 4. 构建返回数据 ===
            response_data = {
                'id': zhuanqu_obj.id,
                'mingzi': mingzi,
                'leixing_id': leixing_id
            }

            # 返回成功响应
            return Response({
                'code': 0,
                'msg': '商品专区添加成功',
                'data': response_data
            })

        except Exception as e:
            import traceback
            traceback.print_exc()
            return Response({
                'code': 500,
                'msg': f'系统错误: {str(e)}',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class ShangpinFabuView(APIView):
    """
    商品发布接口
    接收商品信息、图片等字段
    需要管理员权限
    """
    permission_classes = [permissions.IsAuthenticated]
    parser_classes = (MultiPartParser, FormParser)  # 需要处理文件上传

    def post(self, request):
        try:
            # === 1. 权限验证 ===
            user_main = request.user

            # 1.1 验证账号（使用phone字段）
            zhanghao = request.data.get('zhanghao', '').strip()
            if not zhanghao:
                return Response(
                    {'code': 401, 'msg': '未提供账号信息', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            if user_main.phone != zhanghao:
                return Response(
                    {'code': 401, 'msg': '账号验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 1.2 验证是否为管理员（检查user_type字段）
            if user_main.user_type != 'admin':
                return Response(
                    {'code': 401, 'msg': '权限不足', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 1.3 验证管理员扩展表（使用AdminProfile模型）
            try:
                admin_profile = AdminProfile.objects.get(user=user_main)
            except AdminProfile.DoesNotExist:
                return Response(
                    {'code': 401, 'msg': '管理员信息不存在', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # === 2. 接收并验证字段 ===
            # 2.1 验证必填字段
            biaoti = request.data.get('biaoti', '').strip()
            jiage = request.data.get('jiage', '').strip()
            kucun = request.data.get('kucun', '').strip()
            leixing_id = request.data.get('leixing_id')
            zhuanqu_id = request.data.get('zhuanqu_id')
            yaoqiuleixing = request.data.get('yaoqiuleixing')
            jieshao = request.data.get('jieshao', '').strip()

            # 验证图片
            shangpin_tupian = request.FILES.get('shangpin_tupian')
            if not shangpin_tupian:

                return Response(
                    {'code': 400, 'msg': '请上传商品图片', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 验证图片格式和大小
            is_valid, error_msg = validate_image(shangpin_tupian)
            if not is_valid:
                return Response(
                    {'code': 400, 'msg': f'商品图片验证失败: {error_msg}', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 2.2 验证必填字段是否为空
            required_fields = {
                'biaoti': biaoti,
                'jiage': jiage,
                'kucun': kucun,
                'leixing_id': leixing_id,
                'zhuanqu_id': zhuanqu_id,
                'yaoqiuleixing': yaoqiuleixing,
                'jieshao': jieshao
            }

            for field_name, field_value in required_fields.items():
                if not field_value:
                    return Response(
                        {'code': 400, 'msg': f'{field_name}不能为空', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

            # 2.3 验证数值字段
            try:
                jiage_value = float(jiage)
                if jiage_value <= 0:
                    return Response(
                        {'code': 400, 'msg': '商品价格必须大于0', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )
            except ValueError:
                return Response(
                    {'code': 400, 'msg': '商品价格格式错误', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            try:
                kucun_value = int(kucun)
                if kucun_value < 0:
                    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
                )

            # 验证抢单要求类型
            if yaoqiuleixing not in ['1', '2']:
                return Response(
                    {'code': 400, 'msg': '抢单要求类型无效', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # === 3. 验证关联数据 ===
            # 3.1 验证商品类型
            try:
                leixing_obj = ShangpinLeixing.objects.get(id=leixing_id)
            except ShangpinLeixing.DoesNotExist:
                return Response(
                    {'code': 400, 'msg': '商品类型不存在', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 3.2 根据抢单要求类型验证商品类型
            yaoqiuleixing_int = int(yaoqiuleixing)

            if yaoqiuleixing_int == 1:  # 会员抢单
                # 需要验证商品类型的抢单要求类型是否为1
                if leixing_obj.yaoqiuleixing != 1:
                    return Response(
                        {'code': 400, 'msg': '商品类型与抢单要求类型不匹配', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                # 获取会员ID（从前端或商品类型）
                huiyuan_id = request.data.get('huiyuan_id', leixing_obj.huiyuan_id)
                if not huiyuan_id:
                    return Response(
                        {'code': 400, 'msg': '会员ID不能为空', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                # 验证会员是否存在
                try:
                    huiyuan_obj = Huiyuan.objects.get(huiyuan_id=huiyuan_id)
                except Huiyuan.DoesNotExist:
                    return Response(
                        {'code': 400, 'msg': '会员不存在', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                # 设置会员相关字段
                huiyuan_id_value = huiyuan_id
                yongjin_value = None
            else:  # 佣金抢单
                # 需要验证商品类型的抢单要求类型是否为2
                if leixing_obj.yaoqiuleixing != 2:
                    return Response(
                        {'code': 400, 'msg': '商品类型与抢单要求类型不匹配', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                # 获取佣金（从前端或商品类型）
                yongjin = request.data.get('yongjin', leixing_obj.yongjin)
                if not yongjin:
                    return Response(
                        {'code': 400, 'msg': '佣金金额不能为空', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                try:
                    yongjin_value = float(yongjin)
                    if yongjin_value <= 0:
                        return Response(
                            {'code': 400, 'msg': '佣金金额必须大于0', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST
                        )
                except ValueError:
                    return Response(
                        {'code': 400, 'msg': '佣金金额格式错误', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                huiyuan_id_value = None

            # 3.3 验证商品专区
            try:
                zhuanqu_obj = ShangpinZhuanqu.objects.get(id=zhuanqu_id, leixing_id=leixing_id)
            except ShangpinZhuanqu.DoesNotExist:
                return Response(
                    {'code': 400, 'msg': '商品专区不存在或与商品类型不匹配', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # === 4. 创建商品记录 ===
            with transaction.atomic():
                # 4.1 获取其他字段
                xuzhi = request.data.get('xuzhi', '').strip()
                xiaoliang = request.data.get('xiaoliang', '0').strip()

                # 转换销量为整数
                try:
                    duiwai_xiaoliang_value = int(xiaoliang) if xiaoliang else 0
                except ValueError:
                    duiwai_xiaoliang_value = 0

                # 4.2 创建商品对象
                shangpin_obj = Shangpin(
                    biaoqian=biaoti,
                    jiage=jiage_value,
                    kucun=kucun_value,
                    leixing_id=leixing_id,
                    zhuanqu_id=zhuanqu_id,
                    duiwai_xiaoliang=duiwai_xiaoliang_value,
                    jieshao=jieshao,
                    xiadan_xuzhi=xuzhi,
                    yaoqiuleixing=yaoqiuleixing_int,
                    huiyuan_id=huiyuan_id_value,
                    yongjin=yongjin_value,
                    # tupian_url 先留空，上传成功后再更新
                )

                # 保存到数据库获取ID
                shangpin_obj.save()
                shangpin_id = shangpin_obj.id

                # === 5. 处理商品图片上传 ===
                try:
                    # 5.1 生成文件名和路径
                    file_extension = os.path.splitext(shangpin_tupian.name)[1].lower()
                    if not file_extension:
                        file_extension = '.jpg'

                    # 构建OSS文件路径：a_long/Spcc{shangpin_id}/{filename}
                    oss_folder = 'a_long'  # 根文件夹
                    spcc_folder = f"Spcc{shangpin_id}"  # 商品图片文件夹

                    # 生成文件名：Spcc{shangpin_id}{file_extension}
                    unique_filename = f"Spcc{shangpin_id}{file_extension}"

                    # 构建完整路径
                    oss_file_path = f"{oss_folder}/{spcc_folder}/{unique_filename}"

                    # 5.2 上传到OSS
                    tupian_url = upload_to_oss(shangpin_tupian, oss_file_path)

                    if not tupian_url:
                        # 上传失败，抛出异常触发回滚
                        raise Exception("商品图片上传到OSS失败")

                    # 5.3 更新商品的图片URL（存储相对路径）
                    shangpin_obj.tupian_url = oss_file_path  # 存相对路径
                    shangpin_obj.save()

                except Exception as oss_error:
                    # 图片上传失败，事务会回滚，商品记录也会被删除
                    #print(f"商品图片OSS上传失败: {oss_error}")
                    # 手动抛出异常触发事务回滚
                    raise Exception(f"商品图片上传失败: {str(oss_error)}")

                # === 6. 构建返回数据 ===
                response_data = {
                    'shangpin_id': shangpin_id,
                    'biaoti': biaoti,
                    'jiage': str(jiage_value),
                    'kucun': kucun_value,
                    'leixing_id': leixing_id,
                    'zhuanqu_id': zhuanqu_id,
                    'xiaoliang': duiwai_xiaoliang_value,
                    'jieshao': jieshao,
                    'xuzhi': xuzhi,
                    'yaoqiuleixing': yaoqiuleixing_int,
                    'huiyuan_id': huiyuan_id_value,
                    'yongjin': str(yongjin_value) if yongjin_value else None,
                    'tupian_url': shangpin_obj.tupian_url  # 相对路径
                }

                # 返回成功响应
                return Response({
                    'code': 0,
                    'msg': '商品发布成功',
                    'data': response_data
                })

        except Exception as e:
            # 捕获所有异常，返回500错误
            import traceback
            traceback.print_exc()
            return Response({
                'code': 500,
                'msg': f'系统错误: {str(e)}',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class GuizeTupianShangchuanView(APIView):
    """
    规则图片上传接口
    接收商品ID和规则图片
    需要管理员权限
    """
    permission_classes = [permissions.IsAuthenticated]
    parser_classes = (MultiPartParser, FormParser)  # 需要处理文件上传

    def post(self, request):
        try:
            # === 1. 权限验证 ===
            user_main = request.user

            # 1.1 验证账号（使用phone字段）
            zhanghao = request.data.get('zhanghao', '').strip()
            if not zhanghao:
                return Response(
                    {'code': 401, 'msg': '未提供账号信息', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            if user_main.phone != zhanghao:
                return Response(
                    {'code': 401, 'msg': '账号验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 1.2 验证是否为管理员（检查user_type字段）
            if user_main.user_type != 'admin':
                return Response(
                    {'code': 401, 'msg': '权限不足', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 1.3 验证管理员扩展表（使用AdminProfile模型）
            try:
                admin_profile = AdminProfile.objects.get(user=user_main)
            except AdminProfile.DoesNotExist:
                return Response(
                    {'code': 401, 'msg': '管理员信息不存在', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # === 2. 接收并验证字段 ===
            # 2.1 验证商品ID
            shangpin_id = request.data.get('shangpin_id')
            if not shangpin_id:
                return Response(
                    {'code': 400, 'msg': '商品ID不能为空', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 2.2 验证规则图片
            guize_tupian = request.FILES.get('guize_tupian')
            if not guize_tupian:
                return Response(
                    {'code': 400, 'msg': '请上传规则图片', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 验证图片格式和大小
            is_valid, error_msg = validate_image(guize_tupian)
            if not is_valid:
                return Response(
                    {'code': 400, 'msg': f'规则图片验证失败: {error_msg}', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # === 3. 验证商品是否存在 ===
            try:
                shangpin_obj = Shangpin.objects.get(id=shangpin_id)
            except Shangpin.DoesNotExist:
                return Response(
                    {'code': 400, 'msg': '商品不存在', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # === 4. 处理规则图片上传 ===
            try:
                # 4.1 生成文件名和路径
                file_extension = os.path.splitext(guize_tupian.name)[1].lower()
                if not file_extension:
                    file_extension = '.jpg'

                # 构建OSS文件路径：a_long/Spgz{shangpin_id}/{filename}
                oss_folder = 'a_long'  # 根文件夹
                spgz_folder = f"Spgz{shangpin_id}"  # 规则图片文件夹

                # 生成文件名：Spgz{shangpin_id}{file_extension}
                unique_filename = f"Spgz{shangpin_id}{file_extension}"

                # 构建完整路径
                oss_file_path = f"{oss_folder}/{spgz_folder}/{unique_filename}"

                # 4.2 上传到OSS
                tupian_url = upload_to_oss(guize_tupian, oss_file_path)

                if not tupian_url:
                    # 上传失败
                    return Response({
                        'code': 500,
                        'msg': '规则图片上传失败',
                        'data': None
                    }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

                # 4.3 更新商品的规则图片URL（存储相对路径）
                shangpin_obj.guize_tupian = oss_file_path  # 存相对路径
                shangpin_obj.save()

            except Exception as oss_error:
                # OSS上传失败
                print(f"规则图片OSS上传失败: {oss_error}")
                return Response({
                    'code': 500,
                    'msg': f'规则图片上传失败: {str(oss_error)}',
                    'data': None
                }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

            # === 5. 构建返回数据 ===
            response_data = {
                'shangpin_id': shangpin_id,
                'guize_tupian_url': oss_file_path  # 相对路径
            }

            # 返回成功响应
            return Response({
                'code': 0,
                'msg': '规则图片上传成功',
                'data': response_data
            })

        except Exception as e:
            # 捕获所有异常，返回500错误
            import traceback
            traceback.print_exc()
            return Response({
                'code': 500,
                'msg': f'系统错误: {str(e)}',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)



class AdHuiyuanHqView(APIView):
    """
    管理员获取会员信息和商品类型接口
    需要管理员权限
    """
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        try:
            # === 1. 权限验证 ===
            # 获取当前用户
            user_main = request.user

            # 1.1 验证前端传递的账号是否匹配（使用phone字段）
            zhanghao = request.data.get('zhanghao', '').strip()
            if not zhanghao:
                return Response(
                    {'code': 401, 'msg': '权限验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 验证账号是否匹配（使用phone字段比较）
            if user_main.phone != zhanghao:
                return Response(
                    {'code': 401, 'msg': '权限验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 1.2 验证是否为管理员（检查user_type字段）
            if user_main.user_type != 'admin':
                return Response(
                    {'code': 401, 'msg': '权限验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 1.3 验证管理员扩展表（使用AdminProfile模型）
            try:
                admin_profile = AdminProfile.objects.get(user=user_main)
            except AdminProfile.DoesNotExist:
                return Response(
                    {'code': 401, 'msg': '权限验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # === 2. 查询会员表数据 ===
            # 查询所有会员数据，按创建时间倒序排列
            huiyuan_queryset = Huiyuan.objects.all().order_by('-create_time')

            # 构建会员数据列表
            huiyuan_list = []
            for huiyuan in huiyuan_queryset:
                huiyuan_data = {
                    'huiyuan_id': huiyuan.huiyuan_id,  # 会员ID
                    'jieshao': huiyuan.jieshao,  # 会员介绍（会员标题）
                    'jtjieshao': huiyuan.jtjieshao if huiyuan.jtjieshao else '',  # 会员规则介绍（具体介绍）
                    'jiage': str(huiyuan.jiage),  # 会员价格（转换为字符串，避免Decimal序列化问题）
                    'guanshifc': str(huiyuan.guanshifc),  # 管事分成（转换为字符串）
                    'goumai_cishu': huiyuan.goumai_cishu,  # 购买次数（销量）
                    'create_time': huiyuan.create_time.strftime('%Y-%m-%d %H:%M:%S') if huiyuan.create_time else None,
                    # 创建时间
                    'update_time': huiyuan.update_time.strftime('%Y-%m-%d %H:%M:%S') if huiyuan.update_time else None
                    # 更新时间
                }
                huiyuan_list.append(huiyuan_data)

            # === 3. 查询商品类型表数据 ===
            # 筛选抢单要求类型等于数字1的所有数据（yaoqiuleixing=1）
            shangpinleixing_queryset = ShangpinLeixing.objects.filter(
                yaoqiuleixing=1  # 抢单要求类型为1（会员抢单）
            ).order_by('id')  # 按ID排序

            # 构建商品类型数据列表
            shangpinleixing_list = []
            for leixing in shangpinleixing_queryset:
                # 注意：这里只需要特定的字段
                leixing_data = {
                    'id': leixing.id,  # 商品类型ID
                    'huiyuan_id': leixing.huiyuan_id,  # 会员ID（关联字段）
                    'jieshao': leixing.jieshao,  # 类型介绍（商品类型名称）
                    'tupian_url': leixing.tupian_url if leixing.tupian_url else ''  # 商品类型图片相对URL
                }
                shangpinleixing_list.append(leixing_data)

            # === 4. 构建返回数据 ===
            response_data = {
                'huiyuanList': huiyuan_list,
                'shangpinleixingList': shangpinleixing_list
            }

            # 返回成功响应
            return Response({
                'code': 0,
                'msg': '获取数据成功',
                'data': response_data
            })

        except Exception as e:
            # 捕获所有异常，返回500错误
            import traceback
            traceback.print_exc()
            return Response({
                'code': 500,
                'msg': f'系统错误: {str(e)}',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)





class HuiyuanXiugaiView(APIView):
    """
    会员修改接口
    需要管理员权限
    """
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        try:
            # === 1. 权限验证 ===
            user_main = request.user

            # 1.1 验证前端传递的账号是否匹配（使用phone字段）
            zhanghao = request.data.get('zhanghao', '').strip()
            if not zhanghao:
                return Response(
                    {'code': 401, 'msg': '权限验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            if user_main.phone != zhanghao:
                return Response(
                    {'code': 401, 'msg': '权限验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 1.2 验证是否为管理员（检查user_type字段）
            if user_main.user_type != 'admin':
                return Response(
                    {'code': 401, 'msg': '权限验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 1.3 验证管理员扩展表
            try:
                admin_profile = AdminProfile.objects.get(user=user_main)
            except AdminProfile.DoesNotExist:
                return Response(
                    {'code': 401, 'msg': '权限验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # === 2. 接收并验证必填字段 ===
            huiyuan_id = request.data.get('huiyuan_id', '').strip()
            if not huiyuan_id:
                return Response(
                    {'code': 400, 'msg': '会员ID不能为空', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # === 3. 查询会员数据 ===
            try:
                huiyuan_obj = Huiyuan.objects.get(huiyuan_id=huiyuan_id)
            except Huiyuan.DoesNotExist:
                return Response(
                    {'code': 400, 'msg': '会员不存在', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # === 4. 更新会员信息 ===
            # 4.1 获取前端传递的字段（只更新有值的字段）
            jieshao = request.data.get('jieshao', '').strip()
            jtjieshao = request.data.get('jtjieshao', '').strip()
            jiage = request.data.get('jiage', '').strip()
            guanshifc = request.data.get('guanshifc', '').strip()

            # 4.2 更新字段
            if jieshao:
                # 验证名称长度（30个字符以内）
                if len(jieshao) > 30:
                    return Response(
                        {'code': 400, 'msg': '会员名称不能超过30个字符', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )
                huiyuan_obj.jieshao = jieshao

            if jtjieshao:
                # 验证介绍长度（没有长度限制，但做一下基本检查）
                if len(jtjieshao) > 2000:
                    return Response(
                        {'code': 400, 'msg': '会员介绍过长', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )
                huiyuan_obj.jtjieshao = jtjieshao

            if jiage:
                try:
                    jiage_value = float(jiage)
                    if jiage_value < 0:
                        return Response(
                            {'code': 400, 'msg': '会员价格不能为负数', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST
                        )
                    if jiage_value > 100000:
                        return Response(
                            {'code': 400, 'msg': '会员价格不能超过10万元', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST
                        )
                    huiyuan_obj.jiage = jiage_value
                except ValueError:
                    return Response(
                        {'code': 400, 'msg': '会员价格格式错误', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

            if guanshifc:
                try:
                    guanshifc_value = float(guanshifc)
                    if guanshifc_value < 0:
                        return Response(
                            {'code': 400, 'msg': '管事分成不能为负数', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST
                        )
                    # 检查管事分成是否超过会员价格
                    if hasattr(huiyuan_obj, 'jiage') and huiyuan_obj.jiage:
                        if guanshifc_value > float(huiyuan_obj.jiage):
                            return Response(
                                {'code': 400, 'msg': '管事分成不能超过会员价格', 'data': None},
                                status=status.HTTP_400_BAD_REQUEST
                            )
                    huiyuan_obj.guanshifc = guanshifc_value
                except ValueError:
                    return Response(
                        {'code': 400, 'msg': '管事分成格式错误', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

            # 4.3 检查是否有任何字段需要更新
            if not (jieshao or jtjieshao or jiage or guanshifc):
                return Response(
                    {'code': 400, 'msg': '没有需要更新的字段', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 4.4 保存更新
            huiyuan_obj.save()

            # === 5. 构建返回数据 ===
            response_data = {
                'huiyuan_id': huiyuan_obj.huiyuan_id,
                'jieshao': huiyuan_obj.jieshao,
                'jtjieshao': huiyuan_obj.jtjieshao if huiyuan_obj.jtjieshao else '',
                'jiage': str(huiyuan_obj.jiage),
                'guanshifc': str(huiyuan_obj.guanshifc),
                'goumai_cishu': huiyuan_obj.goumai_cishu,
                'create_time': huiyuan_obj.create_time.strftime(
                    '%Y-%m-%d %H:%M:%S') if huiyuan_obj.create_time else None,
                'update_time': huiyuan_obj.update_time.strftime(
                    '%Y-%m-%d %H:%M:%S') if huiyuan_obj.update_time else None
            }

            # 返回成功响应
            return Response({
                'code': 0,
                'msg': '会员信息修改成功',
                'data': response_data
            })

        except Exception as e:
            # 捕获所有异常，返回500错误
            import traceback
            traceback.print_exc()
            return Response({
                'code': 500,
                'msg': f'系统错误: {str(e)}',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)







class AdHuiyuanFbView(APIView):
    """
    会员发布接口
    需要管理员权限
    """
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        try:
            # === 1. 权限验证 ===
            user_main = request.user

            # 1.1 验证前端传递的账号是否匹配
            zhanghao = request.data.get('zhanghao', '').strip()
            if not zhanghao:
                return Response(
                    {'code': 401, 'msg': '权限验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            if user_main.phone != zhanghao:
                return Response(
                    {'code': 401, 'msg': '权限验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 1.2 验证是否为管理员
            if user_main.user_type != 'admin':
                return Response(
                    {'code': 401, 'msg': '权限验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 1.3 验证管理员扩展表
            try:
                admin_profile = AdminProfile.objects.get(user=user_main)
            except AdminProfile.DoesNotExist:
                return Response(
                    {'code': 401, 'msg': '权限验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # === 2. 接收并验证字段 ===
            jieshao = request.data.get('jieshao', '').strip()
            jtjieshao = request.data.get('jtjieshao', '').strip()
            jiage = request.data.get('jiage', '').strip()
            guanshifc = request.data.get('guanshifc', '').strip()

            # 2.1 验证必填字段
            if not jieshao:
                return Response(
                    {'code': 400, 'msg': '会员名称不能为空', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            if not jiage:
                return Response(
                    {'code': 400, 'msg': '会员价格不能为空', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            if not guanshifc:
                return Response(
                    {'code': 400, 'msg': '管事分成不能为空', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 2.2 验证字段长度和格式
            if len(jieshao) > 30:
                return Response(
                    {'code': 400, 'msg': '会员名称不能超过30个字符', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            if jtjieshao and len(jtjieshao) > 2000:
                return Response(
                    {'code': 400, 'msg': '会员介绍过长', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 2.3 验证价格和分成格式
            try:
                jiage_value = float(jiage)
                if jiage_value <= 0:
                    return Response(
                        {'code': 400, 'msg': '会员价格必须大于0', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )
                if jiage_value > 100000:
                    return Response(
                        {'code': 400, 'msg': '会员价格不能超过10万元', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )
            except ValueError:
                return Response(
                    {'code': 400, 'msg': '会员价格格式错误', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            try:
                guanshifc_value = float(guanshifc)
                if guanshifc_value < 0:
                    return Response(
                        {'code': 400, 'msg': '管事分成不能为负数', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )
                if guanshifc_value > jiage_value:
                    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. 生成会员ID ===
            # 生成6位唯一会员ID，格式：V + 5位随机数字字母
            def generate_huiyuan_id():
                # 使用V开头，后跟5位随机字符（数字和大写字母）
                chars = string.digits + string.ascii_uppercase
                while True:
                    random_part = ''.join(random.choices(chars, k=5))
                    huiyuan_id = f"V{random_part}"
                    # 检查是否已存在
                    if not Huiyuan.objects.filter(huiyuan_id=huiyuan_id).exists():
                        return huiyuan_id

            huiyuan_id = generate_huiyuan_id()

            # === 4. 创建会员记录 ===
            with transaction.atomic():
                huiyuan_obj = Huiyuan(
                    huiyuan_id=huiyuan_id,
                    jieshao=jieshao,
                    jtjieshao=jtjieshao if jtjieshao else '',
                    jiage=jiage_value,
                    guanshifc=guanshifc_value,
                    goumai_cishu=0,  # 初始购买次数为0
                )

                huiyuan_obj.save()

            # === 5. 构建返回数据 ===
            response_data = {
                'huiyuan_id': huiyuan_obj.huiyuan_id,
                'jieshao': huiyuan_obj.jieshao,
                'jtjieshao': huiyuan_obj.jtjieshao,
                'jiage': str(huiyuan_obj.jiage),
                'guanshifc': str(huiyuan_obj.guanshifc),
                'goumai_cishu': huiyuan_obj.goumai_cishu,
                'create_time': huiyuan_obj.create_time.strftime(
                    '%Y-%m-%d %H:%M:%S') if huiyuan_obj.create_time else None,
                'update_time': huiyuan_obj.update_time.strftime(
                    '%Y-%m-%d %H:%M:%S') if huiyuan_obj.update_time else None
            }

            # 返回成功响应
            return Response({
                'code': 0,
                'msg': '会员发布成功',
                'data': response_data
            })

        except Exception as e:
            # 捕获所有异常，返回500错误
            import traceback
            traceback.print_exc()
            return Response({
                'code': 500,
                'msg': f'系统错误: {str(e)}',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


from django.shortcuts import get_object_or_404
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from rest_framework import status
from django.db.models import Q

# 导入模型
from yonghu.models import UserMain, AdminProfile
from .models import ShangpinLeixing, ShangpinZhuanqu, Huiyuan, Shangpin
from peizhi.models import Gonggao, Lunbo

class AdShangpinHuQu(APIView):
    """
    后台商品管理页面数据获取接口
    路径: /shangpin/adsphq/
    方法: POST
    权限: JWT认证 + 管理员权限
    功能: 获取商品管理页面需要的所有数据
    """

    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # 1. 获取前端传递的账号
            qianzhanghao = request.data.get('zhanghao', '').strip()
            if not qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 2. 从JWT Token获取当前用户
            dangqianyonghu = request.user

            # 3. 验证账号匹配
            if not hasattr(dangqianyonghu, 'phone') or str(dangqianyonghu.phone) != qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 4. 验证用户类型为管理员
            if dangqianyonghu.user_type != 'admin':
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 5. 验证管理员扩展表数据
            try:
                guanliyuan = dangqianyonghu.admin_profile
            except AdminProfile.DoesNotExist:
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 6. 查询公告数据（类型=1的公告）
            gonggao_obj = Gonggao.objects.filter(leixing=1).first()
            shangpingonggao = gonggao_obj.jieshao if gonggao_obj else ''

            # 7. 查询轮播图数据（类型=1的轮播图）
            lunbo_objs = Lunbo.objects.filter(leixing=1).values('tupian_url')
            shangpinlunbo = [item['tupian_url'] for item in lunbo_objs]

            # 8. 查询商品类型数据 - 【修改：添加排序字段】
            shangpinleixing_data = ShangpinLeixing.objects.filter(
                shenhezhuangtai=1  # 只返回审核状态为1（正常）的商品类型
            ).values(
                'id',  # 类型ID
                'jieshao',  # 类型介绍（类型名称）
                'tupian_url',  # 类型图片URL
                'yaoqiuleixing',  # 抢单要求类型（1=会员抢单，2=佣金抢单）
                'huiyuan_id',  # 会员ID（如果yaoqiuleixing=1）
                'yongjin',  # 佣金要求（如果yaoqiuleixing=2）
                'paixu'  # 【新增】排序字段
            ).order_by('paixu', 'id')  # 先按排序字段排序，再按ID排序

            # 9. 查询商品专区数据
            shangpinzhuanqu_data = ShangpinZhuanqu.objects.all().values(
                'id',  # 专区ID
                'mingzi',  # 专区名称
                'leixing_id',  # 所属类型ID
                'paixu'  # 【新增】排序字段
            )

            # 10. 查询会员数据
            huiyuan_data = Huiyuan.objects.all().values(
                'huiyuan_id',  # 会员ID
                'jieshao',  # 会员介绍（会员名称）
                'jiage'  # 会员价格
            )

            # 11. 查询商品数据
            shangpin_data = Shangpin.objects.all().values(
                'id',  # 商品ID
                'biaoqian',  # 商品标题/标签
                'jiage',  # 商品价格
                'leixing_id',  # 商品类型ID
                'zhuanqu_id',  # 商品专区ID
                'tupian_url',  # 商品图片URL
                'duiwai_xiaoliang'  # 商品对外销量
            )

            # 12. 构造返回数据
            response_data = {
                'code': 0,
                'message': '获取成功',
                'data': {
                    'shangpingonggao': shangpingonggao,  # 商品公告
                    'shangpinlunbo': shangpinlunbo,  # 轮播图相对URL数组
                    'shangpinleixing': list(shangpinleixing_data),  # 商品类型列表
                    'shangpinzhuanqu': list(shangpinzhuanqu_data),  # 商品专区列表
                    'huiyuanliebiao': list(huiyuan_data),  # 会员列表
                    'shangpinliebiao': list(shangpin_data),  # 商品列表
                }
            }

            return Response(response_data, status=status.HTTP_200_OK)

        except Exception as e:
            print(f"获取商品管理数据异常: {e}")
            return Response(
                {'code': 500, 'message': '服务器内部错误'},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )


class AdLeixingPaixuXiuGai(APIView):
    """
    后台商品类型排序修改接口
    路径: /shangpin/adleixingpaixuxg/
    方法: POST
    权限: JWT认证 + 管理员权限
    功能: 批量修改商品类型的排序顺序
    """

    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # 1. 权限验证
            qianzhanghao = request.data.get('zhanghao', '').strip()
            if not qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            dangqianyonghu = request.user
            if not hasattr(dangqianyonghu, 'phone') or str(dangqianyonghu.phone) != qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            if dangqianyonghu.user_type != 'admin':
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            try:
                guanliyuan = dangqianyonghu.admin_profile
            except AdminProfile.DoesNotExist:
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 2. 获取排序数据
            paixu_data = request.data.get('paixu_data', [])
            if not paixu_data or not isinstance(paixu_data, list):
                return Response(
                    {'code': 400, 'message': '排序数据格式错误'},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 3. 验证数据格式
            for item in paixu_data:
                if not isinstance(item, dict) or 'id' not in item or 'paixu' not in item:
                    return Response(
                        {'code': 400, 'message': '排序数据格式错误：缺少id或paixu字段'},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                # 验证排序值为正整数
                try:
                    paixu_value = int(item['paixu'])
                    if paixu_value <= 0:
                        return Response(
                            {'code': 400, 'message': '排序值必须为正整数'},
                            status=status.HTTP_400_BAD_REQUEST
                        )
                except ValueError:
                    return Response(
                        {'code': 400, 'message': '排序值必须为整数'},
                        status=status.HTTP_400_BAD_REQUEST
                    )

            # 4. 检查排序值是否重复
            paixu_values = [item['paixu'] for item in paixu_data]
            if len(paixu_values) != len(set(paixu_values)):
                return Response(
                    {'code': 400, 'message': '排序值不能重复'},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 5. 检查排序值范围是否连续（从1开始）
            sorted_paixu = sorted(paixu_values)
            if sorted_paixu[0] != 1 or sorted_paixu[-1] != len(paixu_values):
                return Response(
                    {'code': 400, 'message': '排序值必须从1开始连续'},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 6. 验证商品类型ID是否存在
            leixing_ids = [item['id'] for item in paixu_data]
            existing_ids = set(ShangpinLeixing.objects.filter(
                id__in=leixing_ids,
                shenhezhuangtai=1  # 只修改正常状态的商品类型
            ).values_list('id', flat=True))

            if len(existing_ids) != len(leixing_ids):
                return Response(
                    {'code': 400, 'message': '存在无效的商品类型ID'},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 7. 批量更新排序值（使用事务保证一致性）
            from django.db import transaction

            try:
                with transaction.atomic():
                    for item in paixu_data:
                        leixing_id = item['id']
                        paixu_value = int(item['paixu'])

                        ShangpinLeixing.objects.filter(id=leixing_id).update(paixu=paixu_value)

                    # 记录操作日志（可选）
                    #print(f"管理员 {qianzhanghao} 修改了商品类型排序: {paixu_data}")

            except Exception as e:
                #print(f"更新排序时发生错误: {e}")
                return Response(
                    {'code': 500, 'message': '更新排序失败'},
                    status=status.HTTP_500_INTERNAL_SERVER_ERROR
                )

            # 8. 返回成功响应
            return Response({
                'code': 0,
                'message': '排序更新成功',
                'data': {
                    'updated_count': len(paixu_data)
                }
            }, status=status.HTTP_200_OK)

        except Exception as e:
            #print(f"商品类型排序修改异常: {e}")
            return Response(
                {'code': 500, 'message': '服务器内部错误'},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )

'''class AdShangpinHuQu(APIView):
    """
    后台商品管理页面数据获取接口
    路径: /shangpin/adsphq/
    方法: POST
    权限: JWT认证 + 管理员权限
    功能: 获取商品管理页面需要的所有数据
    """

    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # 1. 获取前端传递的账号
            qianzhanghao = request.data.get('zhanghao', '').strip()
            if not qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 2. 从JWT Token获取当前用户
            dangqianyonghu = request.user

            # 3. 验证账号匹配
            if not hasattr(dangqianyonghu, 'phone') or str(dangqianyonghu.phone) != qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 4. 验证用户类型为管理员
            if dangqianyonghu.user_type != 'admin':
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 5. 验证管理员扩展表数据
            try:
                guanliyuan = dangqianyonghu.admin_profile
            except AdminProfile.DoesNotExist:
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 6. 查询公告数据（类型=1的公告）
            gonggao_obj = Gonggao.objects.filter(leixing=1).first()
            shangpingonggao = gonggao_obj.jieshao if gonggao_obj else ''

            # 7. 查询轮播图数据（类型=1的轮播图）
            lunbo_objs = Lunbo.objects.filter(leixing=1).values('tupian_url')
            shangpinlunbo = [item['tupian_url'] for item in lunbo_objs]

            # 8. 查询商品类型数据
            shangpinleixing_data = ShangpinLeixing.objects.all().values(
                'id',  # 类型ID
                'jieshao',  # 类型介绍（类型名称）
                'tupian_url',  # 类型图片URL
                'yaoqiuleixing',  # 抢单要求类型（1=会员抢单，2=佣金抢单）
                'huiyuan_id',  # 会员ID（如果yaoqiuleixing=1）
                'yongjin'  # 佣金要求（如果yaoqiuleixing=2）
            )

            # 9. 查询商品专区数据
            shangpinzhuanqu_data = ShangpinZhuanqu.objects.all().values(
                'id',  # 专区ID
                'mingzi',  # 专区名称
                'leixing_id'  # 所属类型ID
            )

            # 10. 查询会员数据
            huiyuan_data = Huiyuan.objects.all().values(
                'huiyuan_id',  # 会员ID
                'jieshao',  # 会员介绍（会员名称）
                'jiage'  # 会员价格
            )

            # 11. 查询商品数据
            shangpin_data = Shangpin.objects.all().values(
                'id',  # 商品ID
                'biaoqian',  # 商品标题/标签
                'jiage',  # 商品价格
                'leixing_id',  # 商品类型ID
                'zhuanqu_id',  # 商品专区ID
                'tupian_url',  # 商品图片URL
                'duiwai_xiaoliang'  # 商品对外销量
            )

            # 12. 构造返回数据
            response_data = {
                'code': 0,
                'message': '获取成功',
                'data': {
                    'shangpingonggao': shangpingonggao,  # 商品公告
                    'shangpinlunbo': shangpinlunbo,  # 轮播图相对URL数组
                    'shangpinleixing': list(shangpinleixing_data),  # 商品类型列表
                    'shangpinzhuanqu': list(shangpinzhuanqu_data),  # 商品专区列表
                    'huiyuanliebiao': list(huiyuan_data),  # 会员列表
                    'shangpinliebiao': list(shangpin_data),  # 商品列表
                }
            }

            return Response(response_data, status=status.HTTP_200_OK)

        except Exception as e:
            print(f"获取商品管理数据异常: {e}")
            return Response(
                {'code': 500, 'message': '服务器内部错误'},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )'''



# shangpin/views.py
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, AdminProfile
from peizhi.models import Gonggao


class AdGonggaoXiuGai(APIView):
    """
    后台编辑公告接口
    路径: /shangpin/adggxg/
    方法: POST
    权限: JWT认证 + 管理员权限
    功能: 修改公告内容
    """

    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # 1. 获取前端传递的账号
            qianzhanghao = request.data.get('zhanghao', '').strip()
            if not qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 2. 从JWT Token获取当前用户
            dangqianyonghu = request.user

            # 3. 验证账号匹配
            if not hasattr(dangqianyonghu, 'phone') or str(dangqianyonghu.phone) != qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 4. 验证用户类型为管理员
            if dangqianyonghu.user_type != 'admin':
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 5. 验证管理员扩展表数据
            try:
                guanliyuan = dangqianyonghu.admin_profile
            except AdminProfile.DoesNotExist:
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 6. 获取公告内容
            gonggao_neirong = request.data.get('gonggao', '').strip()

            # 7. 验证公告内容
            if not gonggao_neirong:
                return Response(
                    {'code': 400, 'message': '公告内容不能为空', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            if len(gonggao_neirong) > 300:
                return Response(
                    {'code': 400, 'message': '公告内容不能超过300字', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 8. 查询公告表，类型为1的公告
            gonggao_obj = Gonggao.objects.filter(leixing=1).first()

            # 如果不存在，则创建
            if not gonggao_obj:
                gonggao_obj = Gonggao(leixing=1)

            # 9. 更新公告内容
            gonggao_obj.jieshao = gonggao_neirong
            gonggao_obj.save()

            # 10. 返回成功响应
            return Response({
                'code': 0,
                'message': '公告更新成功',
                'data': {
                    'gonggao': gonggao_neirong
                }
            })

        except Exception as e:
            print(f"编辑公告异常: {e}")
            return Response(
                {'code': 500, 'message': '服务器内部错误', 'data': None},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )


class AdZhuanquXiuGai(APIView):
    """
    后台修改专区名称接口
    路径: /shangpin/adzqxg/
    方法: POST
    权限: JWT认证 + 管理员权限
    功能: 修改专区名称
    """

    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # 1. 权限验证
            qianzhanghao = request.data.get('zhanghao', '').strip()
            if not qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            dangqianyonghu = request.user

            if not hasattr(dangqianyonghu, 'phone') or str(dangqianyonghu.phone) != qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            if dangqianyonghu.user_type != 'admin':
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            try:
                guanliyuan = dangqianyonghu.admin_profile
            except AdminProfile.DoesNotExist:
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 2. 获取专区ID和新的专区名称
            zhuanqu_id = request.data.get('zhuanqu_id')
            mingzi = request.data.get('mingzi', '').strip()

            if not zhuanqu_id:
                return Response(
                    {'code': 400, 'message': '专区ID不能为空', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            if not mingzi:
                return Response(
                    {'code': 400, 'message': '专区名称不能为空', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            if len(mingzi) > 10:
                return Response(
                    {'code': 400, 'message': '专区名称不能大于10个字', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 3. 查询专区
            try:
                zhuanqu_obj = ShangpinZhuanqu.objects.get(id=zhuanqu_id)
            except ShangpinZhuanqu.DoesNotExist:
                return Response(
                    {'code': 400, 'message': '专区不存在', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 4. 更新专区名称
            zhuanqu_obj.mingzi = mingzi
            zhuanqu_obj.save()

            # 5. 返回成功响应
            return Response({
                'code': 0,
                'message': '专区名称修改成功',
                'data': {
                    'id': zhuanqu_obj.id,
                    'mingzi': zhuanqu_obj.mingzi,
                    'leixing_id': zhuanqu_obj.leixing_id
                }
            })

        except Exception as e:
            print(f"修改专区名称异常: {e}")
            return Response(
                {'code': 500, 'message': '服务器内部错误', 'data': None},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )




from rest_framework.parsers import MultiPartParser, FormParser
from django.db import transaction
from utils.oss_utils import validate_image, upload_to_oss, delete_from_oss
from peizhi.models import Lunbo
import os
import uuid
import random
import string


class AdLunboXiuGai(APIView):
    """
    后台编辑轮播图接口
    路径: /shangpin/adlunboxg/
    方法: POST
    权限: JWT认证 + 管理员权限
    功能: 添加或删除轮播图
    """

    permission_classes = [IsAuthenticated]
    parser_classes = (MultiPartParser, FormParser,JSONParser)

    def post(self, request):
        try:
            # 1. 权限验证
            qianzhanghao = request.data.get('zhanghao', '').strip()
            if not qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            dangqianyonghu = request.user

            if not hasattr(dangqianyonghu, 'phone') or str(dangqianyonghu.phone) != qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            if dangqianyonghu.user_type != 'admin':
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            try:
                guanliyuan = dangqianyonghu.admin_profile
            except AdminProfile.DoesNotExist:
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 2. 获取操作类型
            action = request.data.get('action', '').strip()  # 'add' 或 'delete'

            if action not in ['add', 'delete']:
                return Response(
                    {'code': 400, 'message': '操作类型无效', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 3. 处理删除操作
            if action == 'delete':
                tupian_url = request.data.get('tupian_url', '').strip()

                if not tupian_url:
                    return Response(
                        {'code': 400, 'message': '图片URL不能为空', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                # 查询轮播图记录
                lunbo_obj = Lunbo.objects.filter(tupian_url=tupian_url, leixing=1).first()

                if not lunbo_obj:
                    return Response(
                        {'code': 400, 'message': '轮播图不存在', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                # 从OSS删除图片
                delete_success = delete_from_oss(tupian_url)

                if not delete_success:
                    return Response(
                        {'code': 500, 'message': 'OSS删除失败', 'data': None},
                        status=status.HTTP_500_INTERNAL_SERVER_ERROR
                    )

                # 从数据库删除记录
                lunbo_obj.delete()

                return Response({
                    'code': 0,
                    'message': '删除成功',
                    'data': None
                })

            # 4. 处理添加操作
            else:  # action == 'add'
                tupian_file = request.FILES.get('file')

                if not tupian_file:
                    return Response(
                        {'code': 400, 'message': '请上传图片', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                # 验证图片
                is_valid, error_msg = validate_image(tupian_file)
                if not is_valid:
                    return Response(
                        {'code': 400, 'message': f'图片验证失败: {error_msg}', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                # 生成文件名和路径
                file_extension = os.path.splitext(tupian_file.name)[1].lower()
                if not file_extension:
                    file_extension = '.jpg'

                # 生成6位随机字符串作为文件名
                random_str = ''.join(random.choices(string.ascii_lowercase + string.digits, k=6))
                unique_filename = f"{random_str}{file_extension}"

                # 构建OSS文件路径：a_long/lunbo/{filename}
                oss_folder = 'a_long'
                lunbo_folder = 'lunbo'

                oss_file_path = f"{oss_folder}/{lunbo_folder}/{unique_filename}"

                # 上传到OSS
                tupian_url = upload_to_oss(tupian_file, oss_file_path)

                if not tupian_url:
                    return Response(
                        {'code': 500, 'message': '图片上传失败', 'data': None},
                        status=status.HTTP_500_INTERNAL_SERVER_ERROR
                    )

                # 创建轮播图记录
                lunbo_obj = Lunbo.objects.create(
                    tupian_url=oss_file_path,  # 存相对路径
                    leixing=1
                )

                return Response({
                    'code': 0,
                    'message': '添加成功',
                    'data': {
                        'tupian_url': lunbo_obj.tupian_url
                    }
                })

        except Exception as e:
            print(f"编辑轮播图异常: {e}")
            return Response(
                {'code': 500, 'message': '服务器内部错误', 'data': None},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )


class AdLeixingXiuGai(APIView):
    """
    后台编辑商品类型接口 - 优化版
    支持：只改图片、只改字段、两者都改
    拒绝：两者都不改
    """

    permission_classes = [IsAuthenticated]
    parser_classes = (MultiPartParser, FormParser, JSONParser)  # 添加JSONParser支持

    def post(self, request):
        try:
            # 1. 权限验证（保持不变）
            qianzhanghao = request.data.get('zhanghao', '').strip()
            if not qianzhanghao:
                return Response({'code': 401, 'message': '身份验证失败'}, status=status.HTTP_401_UNAUTHORIZED)

            dangqianyonghu = request.user
            if not hasattr(dangqianyonghu, 'phone') or str(dangqianyonghu.phone) != qianzhanghao:
                return Response({'code': 401, 'message': '身份验证失败'}, status=status.HTTP_401_UNAUTHORIZED)

            if dangqianyonghu.user_type != 'admin':
                return Response({'code': 401, 'message': '身份验证失败'}, status=status.HTTP_401_UNAUTHORIZED)

            try:
                guanliyuan = dangqianyonghu.admin_profile
            except AdminProfile.DoesNotExist:
                return Response({'code': 401, 'message': '身份验证失败'}, status=status.HTTP_401_UNAUTHORIZED)

            # 2. 获取商品类型ID
            leixing_id = request.data.get('leixing_id')
            if not leixing_id:
                return Response({'code': 400, 'message': '商品类型ID不能为空', 'data': None},
                                status=status.HTTP_400_BAD_REQUEST)

            # 3. 查询商品类型
            try:
                leixing_obj = ShangpinLeixing.objects.get(id=leixing_id)
            except ShangpinLeixing.DoesNotExist:
                return Response({'code': 400, 'message': '商品类型不存在', 'data': None},
                                status=status.HTTP_400_BAD_REQUEST)

            # 4. 获取字段并初始化变更标记
            has_changed = False
            jieshao = request.data.get('jieshao', '').strip()
            yaoqiuleixing = request.data.get('yaoqiuleixing')
            huiyuan_id = request.data.get('huiyuan_id', '').strip()
            yongjin = request.data.get('yongjin', '').strip()
            tupian_url = request.data.get('tupian_url', '').strip()  # 原有图片URL

            # 5. 检查非图片字段是否有变更
            if jieshao and jieshao != leixing_obj.jieshao:
                leixing_obj.jieshao = jieshao
                has_changed = True

            if yaoqiuleixing and int(yaoqiuleixing) != leixing_obj.yaoqiuleixing:
                leixing_obj.yaoqiuleixing = int(yaoqiuleixing)
                has_changed = True

                # 根据类型清空另一个字段
                if leixing_obj.yaoqiuleixing == 1:
                    leixing_obj.yongjin = None
                    if huiyuan_id:
                        leixing_obj.huiyuan_id = huiyuan_id
                        # 验证会员存在
                        try:
                            Huiyuan.objects.get(huiyuan_id=huiyuan_id)
                        except Huiyuan.DoesNotExist:
                            return Response({'code': 400, 'msg': '会员ID不存在', 'data': None},
                                            status=status.HTTP_400_BAD_REQUEST)
                else:  # 类型2
                    leixing_obj.huiyuan_id = None
                    if yongjin:
                        try:
                            leixing_obj.yongjin = float(yongjin)
                            if leixing_obj.yongjin <= 0:
                                return Response({'code': 400, 'message': '佣金金额必须大于0', 'data': None},
                                                status=status.HTTP_400_BAD_REQUEST)
                        except ValueError:
                            return Response({'code': 400, 'message': '佣金金额格式错误', 'data': None},
                                            status=status.HTTP_400_BAD_REQUEST)

            # ===== 在现有代码的第5步后面添加 =====

            # 5.5 检查抢单要求类型不变时，会员ID或佣金是否有变更
            if yaoqiuleixing and int(yaoqiuleixing) == leixing_obj.yaoqiuleixing:
                # 类型没有变化，但需要检查对应字段的变化

                # 情况1：会员抢单 (yaoqiuleixing == 1)
                if leixing_obj.yaoqiuleixing == 1:
                    # 检查会员ID是否变更
                    if huiyuan_id and huiyuan_id != leixing_obj.huiyuan_id:
                        # 验证会员存在
                        try:
                            Huiyuan.objects.get(huiyuan_id=huiyuan_id)
                        except Huiyuan.DoesNotExist:
                            return Response({'code': 400, 'msg': '会员ID不存在', 'data': None},
                                            status=status.HTTP_400_BAD_REQUEST)

                        leixing_obj.huiyuan_id = huiyuan_id
                        has_changed = True
                        # print(f"会员ID变更: {leixing_obj.huiyuan_id} -> {huiyuan_id}")

                # 情况2：佣金抢单 (yaoqiuleixing == 2)
                elif leixing_obj.yaoqiuleixing == 2:
                    # 检查佣金是否变更
                    if yongjin:
                        try:
                            new_yongjin = float(yongjin)
                            if new_yongjin <= 0:
                                return Response({'code': 400, 'message': '佣金金额必须大于0', 'data': None},
                                                status=status.HTTP_400_BAD_REQUEST)

                            # 判断是否有变化（考虑None的情况）
                            current_yongjin = leixing_obj.yongjin
                            if (current_yongjin is None and new_yongjin != 0) or \
                                    (current_yongjin is not None and abs(
                                        float(current_yongjin) - new_yongjin) > 0.001):
                                leixing_obj.yongjin = new_yongjin
                                has_changed = True
                                # print(f"佣金变更: {current_yongjin} -> {new_yongjin}")

                        except ValueError:
                            return Response({'code': 400, 'message': '佣金金额格式错误', 'data': None},
                                            status=status.HTTP_400_BAD_REQUEST)

            # ===== 添加结束 =====

            # 6. 处理图片上传（如果有新图片）
            tupian_file = request.FILES.get('file')
            if tupian_file:
                # 验证图片
                is_valid, error_msg = validate_image(tupian_file)
                if not is_valid:
                    return Response({'code': 400, 'message': f'图片验证失败: {error_msg}', 'data': None},
                                    status=status.HTTP_400_BAD_REQUEST)

                # 删除旧图片（如果存在）
                if leixing_obj.tupian_url:
                    delete_from_oss(leixing_obj.tupian_url)

                # 生成文件名和路径
                file_extension = os.path.splitext(tupian_file.name)[1].lower() or '.jpg'
                oss_folder = 'a_long'
                leixing_folder = 'leixing'

                # 使用原文件名或生成新文件名
                if leixing_obj.tupian_url:
                    original_filename = leixing_obj.tupian_url.split('/')[-1]
                else:
                    original_filename = f"{leixing_id}_{uuid.uuid4().hex}{file_extension}"

                oss_file_path = f"{oss_folder}/{leixing_folder}/{leixing_id}/{original_filename}"

                # 上传到OSS
                new_tupian_url = upload_to_oss(tupian_file, oss_file_path)
                if not new_tupian_url:
                    return Response({'code': 500, 'message': '图片上传失败', 'data': None},
                                    status=status.HTTP_500_INTERNAL_SERVER_ERROR)

                leixing_obj.tupian_url = oss_file_path  # 存相对路径
                has_changed = True
            elif tupian_url and tupian_url != leixing_obj.tupian_url:
                # 前端传了新URL（可能是从其他地方选择的）
                leixing_obj.tupian_url = tupian_url
                has_changed = True

            # 7. 验证是否至少有变更
            if not has_changed:
                return Response({
                    'code': 400,
                    'message': '没有检测到任何更改',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 8. 保存并返回
            leixing_obj.save()
            # 8. 保存商品类型
            leixing_obj.save()

            # 🔴 ===========【新增：同步更新关联商品】===========
            try:
                from django.db.models import Q

                # 1. 准备商品更新字典
                shangpin_update_fields = {}

                # 始终同步抢单要求类型
                shangpin_update_fields['yaoqiuleixing'] = leixing_obj.yaoqiuleixing

                # 根据抢单类型，同步对应字段并清空另一个
                if leixing_obj.yaoqiuleixing == 1:  # 会员抢单
                    if leixing_obj.huiyuan_id:  # 仅当会员ID非空时更新
                        shangpin_update_fields['huiyuan_id'] = leixing_obj.huiyuan_id
                    # 清空佣金字段
                    shangpin_update_fields['yongjin'] = None
                elif leixing_obj.yaoqiuleixing == 2:  # 佣金抢单
                    if leixing_obj.yongjin:  # 仅当佣金非空时更新
                        shangpin_update_fields['yongjin'] = leixing_obj.yongjin
                    # 清空会员字段
                    shangpin_update_fields['huiyuan_id'] = None

                # 2. 执行批量更新（确保只有实际有变化的字段才会执行）
                if shangpin_update_fields:
                    # 查询所有属于该类型的商品（使用filter而非all以提高效率）
                    affected_count = Shangpin.objects.filter(
                        leixing_id=leixing_obj.id
                    ).update(**shangpin_update_fields)

                    # 可选：记录日志以便追踪
                    # logger.info(f"商品类型{leixing_obj.id}修改成功，已同步更新{affected_count}个关联商品")

            except Exception as sync_error:
                # 商品同步失败不影响商品类型本身的修改，但记录错误
                # 可根据需求决定是否抛出异常回滚整个事务
                # 当前设计：记录错误但允许商品类型修改成功
                logger.error(f"修改十五")

                # 可在此添加更详细的错误日志记录
            # 🔴 ===========【新增结束】===========







            response_data = {
                'id': leixing_obj.id,
                'jieshao': leixing_obj.jieshao,
                'tupian_url': leixing_obj.tupian_url,
                'yaoqiuleixing': leixing_obj.yaoqiuleixing,
                'huiyuan_id': leixing_obj.huiyuan_id,
                'yongjin': str(leixing_obj.yongjin) if leixing_obj.yongjin else None
            }

            return Response({
                'code': 0,
                'message': '商品类型修改成功',
                'data': response_data
            })

        except Exception as e:
            print(f"编辑商品类型异常: {e}")
            return Response({'code': 500, 'message': '服务器内部错误', 'data': None},
                            status=status.HTTP_500_INTERNAL_SERVER_ERROR)







'''class AdLeixingXiuGai(APIView):
    """
    后台编辑商品类型接口
    路径: /shangpin/adleixingxg/
    方法: POST
    权限: JWT认证 + 管理员权限
    功能: 修改商品类型信息
    """

    permission_classes = [IsAuthenticated]
    parser_classes = (MultiPartParser, FormParser)

    def post(self, request):
        try:
            # 1. 权限验证
            qianzhanghao = request.data.get('zhanghao', '').strip()
            if not qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            dangqianyonghu = request.user

            if not hasattr(dangqianyonghu, 'phone') or str(dangqianyonghu.phone) != qianzhanghao:
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            if dangqianyonghu.user_type != 'admin':
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            try:
                guanliyuan = dangqianyonghu.admin_profile
            except AdminProfile.DoesNotExist:
                return Response(
                    {'code': 401, 'message': '身份验证失败'},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 2. 获取商品类型ID
            leixing_id = request.data.get('leixing_id')
            if not leixing_id:
                return Response(
                    {'code': 400, 'message': '商品类型ID不能为空', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 3. 查询商品类型
            try:
                leixing_obj = ShangpinLeixing.objects.get(id=leixing_id)
            except ShangpinLeixing.DoesNotExist:
                return Response(
                    {'code': 400, 'message': '商品类型不存在', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 4. 获取其他字段
            jieshao = request.data.get('jieshao', '').strip()
            yaoqiuleixing = request.data.get('yaoqiuleixing')
            huiyuan_id = request.data.get('huiyuan_id', '').strip()
            yongjin = request.data.get('yongjin', '').strip()

            # 5. 验证必填字段
            if not jieshao:
                return Response(
                    {'code': 400, 'message': '类型名称不能为空', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            if yaoqiuleixing not in ['1', '2']:
                return Response(
                    {'code': 400, 'message': '抢单要求类型无效', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            yaoqiuleixing_int = int(yaoqiuleixing)

            # 6. 根据抢单要求类型验证对应字段
            if yaoqiuleixing_int == 1:  # 会员抢单
                if not huiyuan_id:
                    return Response(
                        {'code': 400, 'message': '会员抢单必须选择会员', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )
                # 验证会员ID是否存在
                try:
                    huiyuan_obj = Huiyuan.objects.get(huiyuan_id=huiyuan_id)
                except Huiyuan.DoesNotExist:
                    return Response(
                        {'code': 400, 'msg': '会员ID不存在', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )
                # 会员ID为字符串，佣金为空
                yongjin_value = None
                huiyuan_id_value = huiyuan_id
            else:  # yaoqiuleixing_int == 2 佣金抢单
                if not yongjin:
                    return Response(
                        {'code': 400, 'message': '佣金抢单必须填写佣金金额', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )
                try:
                    # 验证佣金为有效数字
                    yongjin_value = float(yongjin)
                    if yongjin_value <= 0:
                        return Response(
                            {'code': 400, 'message': '佣金金额必须大于0', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST
                        )
                except ValueError:
                    return Response(
                        {'code': 400, 'message': '佣金金额格式错误', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )
                huiyuan_id_value = None

            # 7. 处理图片上传（如果有新图片）
            tupian_file = request.FILES.get('file')
            tupian_url = None

            if tupian_file:
                # 验证图片
                is_valid, error_msg = validate_image(tupian_file)
                if not is_valid:
                    return Response(
                        {'code': 400, 'message': f'图片验证失败: {error_msg}', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                # 如果有原图片，先删除
                if leixing_obj.tupian_url:
                    delete_from_oss(leixing_obj.tupian_url)

                # 生成文件名（使用原文件名，保持路径不变）
                file_extension = os.path.splitext(tupian_file.name)[1].lower()
                if not file_extension:
                    file_extension = '.jpg'

                # 构建OSS文件路径：使用原来的路径结构
                oss_folder = 'a_long'
                leixing_folder = 'leixing'

                # 提取原文件名
                if leixing_obj.tupian_url:
                    # 如果原路径存在，使用原文件名
                    original_filename = leixing_obj.tupian_url.split('/')[-1]
                else:
                    # 否则生成新的文件名
                    original_filename = f"{leixing_id}_{uuid.uuid4().hex}{file_extension}"

                oss_file_path = f"{oss_folder}/{leixing_folder}/{leixing_id}/{original_filename}"

                # 上传到OSS
                tupian_url = upload_to_oss(tupian_file, oss_file_path)

                if not tupian_url:
                    return Response(
                        {'code': 500, 'message': '图片上传失败', 'data': None},
                        status=status.HTTP_500_INTERNAL_SERVER_ERROR
                    )

            # 8. 更新商品类型记录
            leixing_obj.jieshao = jieshao
            leixing_obj.yaoqiuleixing = yaoqiuleixing_int
            leixing_obj.huiyuan_id = huiyuan_id_value
            leixing_obj.yongjin = yongjin_value

            if tupian_url:
                leixing_obj.tupian_url = oss_file_path  # 存相对路径

            leixing_obj.save()

            # 9. 返回成功响应
            response_data = {
                'id': leixing_obj.id,
                'jieshao': leixing_obj.jieshao,
                'tupian_url': leixing_obj.tupian_url,
                'yaoqiuleixing': leixing_obj.yaoqiuleixing,
                'huiyuan_id': leixing_obj.huiyuan_id,
                'yongjin': str(leixing_obj.yongjin) if leixing_obj.yongjin else None
            }

            return Response({
                'code': 0,
                'message': '商品类型修改成功',
                'data': response_data
            })

        except Exception as e:
            print(f"编辑商品类型异常: {e}")
            return Response(
                {'code': 500, 'message': '服务器内部错误', 'data': None},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )'''




logger = logging.getLogger(__name__)


class AdShangpinNeiRongHuoQu(APIView):
    """
    后台获取商品详情接口
    路径: /shangpin/adspnrhq/
    方法: POST
    权限: JWT认证 + 管理员权限
    功能: 获取指定商品的详细信息
    """

    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        try:
            # 1. 获取前端数据
            qianzhanghao = request.data.get('zhanghao', '').strip()
            shangpin_id = request.data.get('shangpin_id')

            if not qianzhanghao or not shangpin_id:
                return Response(
                    {'code': 400, 'message': '参数不完整', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 2. 权限验证
            dangqianyonghu = request.user

            # 验证phone字段匹配
            if not hasattr(dangqianyonghu, 'phone') or str(dangqianyonghu.phone) != qianzhanghao:
                logger.warning(
                    f"账号不匹配: 当前用户phone={getattr(dangqianyonghu, 'phone', '无')}, 前端账号={qianzhanghao}")
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 验证用户类型
            if dangqianyonghu.user_type != 'admin':
                logger.warning(f"非管理员访问: user_type={dangqianyonghu.user_type}")
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 3. 验证管理员扩展表
            try:
                guanliyuan = dangqianyonghu.admin_profile
            except AdminProfile.DoesNotExist:
                logger.warning(f"管理员扩展表不存在: user_id={dangqianyonghu.id}")
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 4. 查询商品数据
            try:
                shangpin_obj = Shangpin.objects.get(id=shangpin_id)
            except Shangpin.DoesNotExist:
                return Response(
                    {'code': 404, 'message': '商品不存在', 'data': None},
                    status=status.HTTP_404_NOT_FOUND
                )

            # 5. 构建返回数据（与前端字段对应）
            response_data = {
                'tupian_url': shangpin_obj.tupian_url or '',  # 商品图片相对URL
                'biaoti': shangpin_obj.biaoqian or '',  # 商品标题（前端用biaoti，对应biaoqian）
                'jieshao': shangpin_obj.jieshao or '',  # 商品介绍
                'jiage': str(shangpin_obj.jiage) if shangpin_obj.jiage else '0.00',  # 商品价格
                'kucun': shangpin_obj.kucun,  # 商品库存
                'zhenshixiaoliang': shangpin_obj.zhenshi_xiaoliang,  # 商品真实销量
                'duiwaixiaoliang': shangpin_obj.duiwai_xiaoliang,  # 商品对外销量
                'xiadanxuzhi': shangpin_obj.xiadan_xuzhi or '',  # 下单须知
                'guizetupian_url': shangpin_obj.guize_tupian or '',  # 规则图片相对URL
                #'yajin': str(shangpin_obj.yajin) if hasattr(shangpin_obj, 'yajin') and shangpin_obj.yajin else None,
                # 押金（可能不存在）
                'chuangjianshijian': shangpin_obj.create_time.strftime(
                    '%Y-%m-%d %H:%M:%S') if shangpin_obj.create_time else '',
                'genggaishijian': shangpin_obj.update_time.strftime(
                    '%Y-%m-%d %H:%M:%S') if shangpin_obj.update_time else '',
                # 额外字段，前端可能不需要但可以保留
                'leixing_id': shangpin_obj.leixing_id,
                'zhuanqu_id': shangpin_obj.zhuanqu_id,
                'yaoqiuleixing': shangpin_obj.yaoqiuleixing,
                'huiyuan_id': shangpin_obj.huiyuan_id,
                'yongjin': str(shangpin_obj.yongjin) if shangpin_obj.yongjin else None,



                'kaioi_ewai_dashou_fencheng': shangpin_obj.kaioi_ewai_dashou_fencheng,
                'ewai_dashou_fencheng': str(shangpin_obj.ewai_dashou_fencheng) if shangpin_obj.ewai_dashou_fencheng else None,
            }

            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
            )


from rest_framework.parsers import MultiPartParser, FormParser
from django.db import transaction


'''class AdShangpinXiuGai(APIView):
    """
    后台更改商品数据接口 - 修复版
    修复：1. 图片替换逻辑 2. 对外销量字段处理
    """

    permission_classes = [IsAuthenticated]
    parser_classes = (MultiPartParser, FormParser, JSONParser)

    def post(self, request):
        try:
            # 1. 权限验证
            qianzhanghao = request.data.get('zhanghao', '').strip()
            shangpin_id = request.data.get('shangpin_id')

            if not qianzhanghao or not shangpin_id:
                return Response(
                    {'code': 400, 'message': '参数不完整', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 验证身份
            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 AdminProfile.DoesNotExist:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 2. 判断操作类型：删除还是修改
            action = request.data.get('action', 'update').strip().lower()

            if action == 'delete':
                return self._delete_shangpin(shangpin_id)
            else:
                return self._update_shangpin(request, shangpin_id)

        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 _delete_shangpin(self, shangpin_id):
        """删除商品逻辑"""
        try:
            # 查询商品
            try:
                shangpin_obj = Shangpin.objects.get(id=shangpin_id)
            except Shangpin.DoesNotExist:
                return Response(
                    {'code': 404, 'message': '商品不存在', 'data': None},
                    status=status.HTTP_404_NOT_FOUND
                )

            # 获取图片URL（如果有）
            tupian_url = shangpin_obj.tupian_url
            guizetupian_url = shangpin_obj.guize_tupian

            # 异步或同步删除OSS图片（互不影响）
            if tupian_url:
                try:
                    delete_from_oss(tupian_url)
                except Exception as e:
                    logger.warning(f"删除商品图片失败: {tupian_url}, 错误: {e}")

            if guizetupian_url:
                try:
                    delete_from_oss(guizetupian_url)
                except Exception as e:
                    logger.warning(f"删除规则图片失败: {guizetupian_url}, 错误: {e}")

            # 删除数据库记录
            shangpin_obj.delete()

            return Response({
                'code': 0,
                'message': '删除成功',
                'data': {
                    'shangpin_id': shangpin_id,
                    'deleted': True
                }
            })

        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 _update_shangpin(self, request, shangpin_id):
        """修改商品逻辑 - 修复：确保图片正确替换"""
        try:
            # 查询商品
            try:
                shangpin_obj = Shangpin.objects.get(id=shangpin_id)
            except Shangpin.DoesNotExist:
                return Response(
                    {'code': 404, 'message': '商品不存在', 'data': None},
                    status=status.HTTP_404_NOT_FOUND
                )

            has_changes = False

            # 3. 处理图片上传（如果有新商品图片）
            tupian_file = request.FILES.get('tupian_file')
            if tupian_file:
                # 验证图片
                is_valid, error_msg = validate_image(tupian_file)
                if not is_valid:
                    return Response(
                        {'code': 400, 'message': f'图片验证失败: {error_msg}', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                # 获取原图片URL
                old_tupian_url = shangpin_obj.tupian_url

                # 确定OSS路径
                if old_tupian_url:
                    # 有原图：使用原路径替换
                    oss_file_path = old_tupian_url

                    # 删除原图片
                    try:
                        delete_from_oss(old_tupian_url)
                    except Exception as e:
                        logger.warning(f"删除原商品图片失败: {old_tupian_url}, 错误: {e}")
                        # 继续上传新图片
                else:
                    # 没有原图：创建新路径
                    oss_folder = 'a_long'
                    shangpin_folder = 'shangpin'
                    file_extension = os.path.splitext(tupian_file.name)[1].lower() or '.jpg'
                    filename = f"{shangpin_id}{file_extension}"
                    oss_file_path = f"{oss_folder}/{shangpin_folder}/{filename}"

                # 上传到OSS
                new_tupian_url = upload_to_oss(tupian_file, oss_file_path)

                if not new_tupian_url:
                    return Response(
                        {'code': 500, 'message': '图片上传失败', 'data': None},
                        status=status.HTTP_500_INTERNAL_SERVER_ERROR
                    )

                # 更新数据库中的图片URL
                shangpin_obj.tupian_url = oss_file_path  # 存相对路径
                has_changes = True

            # 4. 处理其他字段（只更新有变化的字段）
            field_mapping = {
                'biaoti': 'biaoqian',
                'jieshao': 'jieshao',
                'jiage': 'jiage',
                'kucun': 'kucun',
                'duiwaixiaoliang': 'duiwai_xiaoliang',  # 关键：对外销量字段
                'xiadanxuzhi': 'xiadan_xuzhi',
                'yajin': 'yajin',
            }

            for front_field, db_field in field_mapping.items():
                if front_field in request.data:
                    new_value = request.data.get(front_field)

                    # 空字符串处理
                    if new_value == '':
                        new_value = None

                    if new_value is not None:
                        # 获取当前值
                        current_value = getattr(shangpin_obj, db_field)

                        # 类型转换
                        try:
                            if db_field in ['jiage', 'yajin']:
                                # 价格和押金
                                if new_value:
                                    new_value = Decimal(str(new_value))
                                else:
                                    new_value = None
                            elif db_field in ['kucun', 'duiwai_xiaoliang']:
                                # 库存和对外销量
                                if new_value:
                                    new_value = int(float(new_value))
                                else:
                                    new_value = 0
                        except (ValueError, TypeError, InvalidOperation) as e:
                            logger.warning(f"字段{front_field}转换失败: {new_value}, 错误: {e}")
                            continue

                        # 检查是否有变化（处理None值）
                        if current_value != new_value:
                            setattr(shangpin_obj, db_field, new_value)
                            has_changes = True

            # 5. 如果没有检测到任何更改
            if not has_changes:
                return Response({
                    'code': 400,
                    'message': '没有检测到任何更改',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 6. 保存更改
            shangpin_obj.save()

            # 7. 返回更新后的数据
            response_data = {
                'tupian_url': shangpin_obj.tupian_url or '',
                'biaoti': shangpin_obj.biaoqian or '',
                'jieshao': shangpin_obj.jieshao or '',
                'jiage': str(shangpin_obj.jiage) if shangpin_obj.jiage else '0.00',
                'kucun': shangpin_obj.kucun,
                'duiwaixiaoliang': shangpin_obj.duiwai_xiaoliang,  # 返回对外销量
                'xiadanxuzhi': shangpin_obj.xiadan_xuzhi or '',
                'yajin': str(shangpin_obj.yongjin) if shangpin_obj.yongjin else None,
                'genggaishijian': shangpin_obj.update_time.strftime(
                    '%Y-%m-%d %H:%M:%S') if shangpin_obj.update_time else '',
            }

            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
            )


import os
from decimal import Decimal, InvalidOperation


class AdShangpinGuizeXiuGai(APIView):
    """
    后台规则图片更换接口 - 修复版
    修复：确保替换时使用正确的路径
    """

    permission_classes = [IsAuthenticated]
    parser_classes = (MultiPartParser, FormParser, JSONParser)

    def post(self, request):
        try:
            # 1. 权限验证
            qianzhanghao = request.data.get('zhanghao', '').strip()
            shangpin_id = request.data.get('shangpin_id')
            action = request.data.get('action', 'update').strip().lower()

            if not qianzhanghao or not shangpin_id:
                return Response(
                    {'code': 400, 'message': '参数不完整', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 验证身份
            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 AdminProfile.DoesNotExist:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 2. 查询商品
            try:
                shangpin_obj = Shangpin.objects.get(id=shangpin_id)
            except Shangpin.DoesNotExist:
                return Response(
                    {'code': 404, 'message': '商品不存在', 'data': None},
                    status=status.HTTP_404_NOT_FOUND
                )

            # 3. 处理不同操作
            if action == 'delete':
                return self._delete_guize_image(shangpin_obj)
            elif action == 'update':
                return self._update_guize_image(request, shangpin_obj)
            else:
                return Response(
                    {'code': 400, 'message': '操作类型无效', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

        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 _delete_guize_image(self, shangpin_obj):
        """删除规则图片"""
        guizetupian_url = shangpin_obj.guize_tupian

        if guizetupian_url:
            # 从OSS删除
            try:
                delete_success = delete_from_oss(guizetupian_url)
                if not delete_success:
                    logger.warning(f"OSS删除失败，但继续删除数据库记录: {guizetupian_url}")
            except Exception as e:
                logger.warning(f"删除规则图片异常: {e}")

            # 清除数据库记录
            shangpin_obj.guize_tupian = ''
            shangpin_obj.save()

        return Response({
            'code': 0,
            'message': '删除成功',
            'data': {
                'guizetupian_url': ''
            }
        })

    def _update_guize_image(self, request, shangpin_obj):
        """更新规则图片 - 修复：确保正确替换"""
        guize_file = request.FILES.get('guize_file')

        if not guize_file:
            return Response(
                {'code': 400, 'message': '请上传规则图片', 'data': None},
                status=status.HTTP_400_BAD_REQUEST
            )

        # 验证图片
        is_valid, error_msg = validate_image(guize_file)
        if not is_valid:
            return Response(
                {'code': 400, 'message': f'图片验证失败: {error_msg}', 'data': None},
                status=status.HTTP_400_BAD_REQUEST
            )

        # 处理路径
        oss_folder = 'a_long'
        spgz_folder = 'Spgz'
        file_extension = os.path.splitext(guize_file.name)[1].lower() or '.jpg'

        # 获取原规则图片URL
        old_guizetupian_url = shangpin_obj.guize_tupian

        if old_guizetupian_url:
            # 有原图：使用原路径替换
            oss_file_path = old_guizetupian_url

            # 删除原图片
            try:
                delete_from_oss(old_guizetupian_url)
            except Exception as e:
                logger.warning(f"删除原规则图片失败: {old_guizetupian_url}, 错误: {e}")
                # 继续上传新图片
        else:
            # 没有原图：创建新路径
            filename = f"{shangpin_obj.id}{file_extension}"
            oss_file_path = f"{oss_folder}/{spgz_folder}/{filename}"

        # 上传到OSS（替换或新建）
        new_guizetupian_url = upload_to_oss(guize_file, oss_file_path)

        if not new_guizetupian_url:
            return Response(
                {'code': 500, 'message': '图片上传失败', 'data': None},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )

        # 更新数据库（存相对路径）
        shangpin_obj.guize_tupian = oss_file_path  # 存相对路径，如 "a_long/Spgz/123.jpg"
        shangpin_obj.save()

        return Response({
            'code': 0,
            'message': '规则图片更新成功',
            'data': {
                'guizetupian_url': oss_file_path  # 返回相对路径
            }
        })'''

import os
import time
import random
from decimal import Decimal, InvalidOperation
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.parsers import MultiPartParser, FormParser, JSONParser
from rest_framework.permissions import IsAuthenticated
import logging

logger = logging.getLogger(__name__)


'''class AdShangpinXiuGai(APIView):
    """
    后台更改商品数据接口 - 修复版
    修复：1. 每次上传生成新文件名 2. 解决浏览器缓存问题
    """

    permission_classes = [IsAuthenticated]
    parser_classes = (MultiPartParser, FormParser, JSONParser)

    def post(self, request):
        try:
            # 1. 权限验证
            qianzhanghao = request.data.get('zhanghao', '').strip()
            shangpin_id = request.data.get('shangpin_id')

            if not qianzhanghao or not shangpin_id:
                return Response(
                    {'code': 400, 'message': '参数不完整', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 验证身份
            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 AdminProfile.DoesNotExist:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 2. 判断操作类型：删除还是修改
            action = request.data.get('action', 'update').strip().lower()

            if action == 'delete':
                return self._delete_shangpin(shangpin_id)
            else:
                return self._update_shangpin(request, shangpin_id)

        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 _delete_shangpin(self, shangpin_id):
        """删除商品逻辑"""
        try:
            # 查询商品
            try:
                shangpin_obj = Shangpin.objects.get(id=shangpin_id)
            except Shangpin.DoesNotExist:
                return Response(
                    {'code': 404, 'message': '商品不存在', 'data': None},
                    status=status.HTTP_404_NOT_FOUND
                )

            # 获取图片URL（如果有）
            tupian_url = shangpin_obj.tupian_url
            guizetupian_url = shangpin_obj.guize_tupian

            # 异步或同步删除OSS图片
            if tupian_url:
                try:
                    delete_from_oss(tupian_url)
                except Exception as e:
                    logger.warning(f"删除商品图片失败: {tupian_url}, 错误: {e}")

            if guizetupian_url:
                try:
                    delete_from_oss(guizetupian_url)
                except Exception as e:
                    logger.warning(f"删除规则图片失败: {guizetupian_url}, 错误: {e}")

            # 删除数据库记录
            shangpin_obj.delete()

            return Response({
                'code': 0,
                'message': '删除成功',
                'data': {
                    'shangpin_id': shangpin_id,
                    'deleted': True
                }
            })

        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 _update_shangpin(self, request, shangpin_id):
        """修改商品逻辑 - 修复：每次上传生成新文件名"""
        try:
            # 查询商品
            try:
                shangpin_obj = Shangpin.objects.get(id=shangpin_id)
            except Shangpin.DoesNotExist:
                return Response(
                    {'code': 404, 'message': '商品不存在', 'data': None},
                    status=status.HTTP_404_NOT_FOUND
                )

            has_changes = False

            # 获取原图片URL（如果有）
            old_tupian_url = shangpin_obj.tupian_url

            # 3. 处理商品图片上传（如果有新商品图片）
            tupian_file = request.FILES.get('tupian_file')
            new_tupian_url = None

            if tupian_file:
                # 验证图片
                is_valid, error_msg = validate_image(tupian_file)
                if not is_valid:
                    return Response(
                        {'code': 400, 'message': f'图片验证失败: {error_msg}', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                # 生成新文件名：时间戳 + 随机数 + 原扩展名
                timestamp = int(time.time() * 1000) % 100000000  # 8位时间戳
                random_num = random.randint(1000, 9999)
                file_extension = os.path.splitext(tupian_file.name)[1].lower() or '.jpg'
                new_filename = f"sp_{timestamp}_{random_num}{file_extension}"

                # 确定OSS路径
                oss_folder = 'a_long'
                shangpin_folder = 'shangpin'
                oss_file_path = f"{oss_folder}/{shangpin_folder}/{new_filename}"

                # 删除旧图片（如果存在）
                if old_tupian_url:
                    try:
                        delete_from_oss(old_tupian_url)
                        logger.info(f"已删除旧商品图片: {old_tupian_url}")
                    except Exception as e:
                        logger.warning(f"删除旧商品图片失败: {old_tupian_url}, 错误: {e}")
                        # 继续上传新图片，不中断流程

                # 上传到OSS
                new_tupian_url = upload_to_oss(tupian_file, oss_file_path)

                if not new_tupian_url:
                    return Response(
                        {'code': 500, 'message': '商品图片上传失败', 'data': None},
                        status=status.HTTP_500_INTERNAL_SERVER_ERROR
                    )

                # 更新数据库中的图片URL
                shangpin_obj.tupian_url = oss_file_path  # 存相对路径
                has_changes = True
                logger.info(f"商品图片更新成功: {oss_file_path}")

            # 4. 处理其他字段（只更新有变化的字段）
            # 注意：这里同时处理 request.data（文本字段）和可能有文件的情况
            field_mapping = {
                'biaoti': 'biaoqian',
                'jieshao': 'jieshao',
                'jiage': 'jiage',
                'kucun': 'kucun',
                'duiwaixiaoliang': 'duiwai_xiaoliang',
                'xiadanxuzhi': 'xiadan_xuzhi',
                'yajin': 'yajin',
            }

            for front_field, db_field in field_mapping.items():
                # 注意：request.data 可能包含文件和其他字段，但DRF会处理好
                if front_field in request.data:
                    new_value = request.data.get(front_field)

                    # 空字符串处理
                    if new_value == '':
                        new_value = None

                    if new_value is not None:
                        # 获取当前值
                        current_value = getattr(shangpin_obj, db_field)

                        # 类型转换
                        try:
                            if db_field in ['jiage', 'yajin']:
                                # 价格和押金
                                if new_value:
                                    new_value = Decimal(str(new_value))
                                else:
                                    new_value = None
                            elif db_field in ['kucun', 'duiwai_xiaoliang']:
                                # 库存和对外销量
                                if new_value:
                                    new_value = int(float(new_value))
                                else:
                                    new_value = 0
                        except (ValueError, TypeError, InvalidOperation) as e:
                            logger.warning(f"字段{front_field}转换失败: {new_value}, 错误: {e}")
                            continue

                        # 检查是否有变化（处理None值）
                        if current_value != new_value:
                            setattr(shangpin_obj, db_field, new_value)
                            has_changes = True

            # 5. 如果没有检测到任何更改
            if not has_changes:
                return Response({
                    'code': 400,
                    'message': '没有检测到任何更改',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 6. 保存更改
            shangpin_obj.save()

            # 7. 返回更新后的数据
            response_data = {
                'tupian_url': shangpin_obj.tupian_url or '',
                'biaoti': shangpin_obj.biaoqian or '',
                'jieshao': shangpin_obj.jieshao or '',
                'jiage': str(shangpin_obj.jiage) if shangpin_obj.jiage else '0.00',
                'kucun': shangpin_obj.kucun,
                'duiwaixiaoliang': shangpin_obj.duiwai_xiaoliang,
                'xiadanxuzhi': shangpin_obj.xiadan_xuzhi or '',
                'yajin': str(shangpin_obj.yongjin) if shangpin_obj.yongjin else None,
                'genggaishijian': shangpin_obj.update_time.strftime(
                    '%Y-%m-%d %H:%M:%S') if shangpin_obj.update_time else '',
            }

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







class AdShangpinXiuGai(APIView):
    """
    后台更改商品数据接口 - 修复版
    修复：1. 每次上传生成新文件名 2. 解决浏览器缓存问题
    新增：支持佣金、抢单要求类型、打手分红配置字段的修改
    """

    permission_classes = [permissions.IsAuthenticated]
    parser_classes = (MultiPartParser, FormParser, JSONParser)

    def post(self, request):
        try:
            # 1. 权限验证
            qianzhanghao = request.data.get('zhanghao', '').strip()
            shangpin_id = request.data.get('shangpin_id')

            if not qianzhanghao or not shangpin_id:
                return Response(
                    {'code': 400, 'message': '参数不完整', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 验证身份
            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 AdminProfile.DoesNotExist:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 2. 判断操作类型：删除还是修改
            action = request.data.get('action', 'update').strip().lower()

            if action == 'delete':
                return self._delete_shangpin(shangpin_id)
            else:
                return self._update_shangpin(request, shangpin_id)

        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 _delete_shangpin(self, shangpin_id):
        """删除商品逻辑（保持不变）"""
        try:
            try:
                shangpin_obj = Shangpin.objects.get(id=shangpin_id)
            except Shangpin.DoesNotExist:
                return Response(
                    {'code': 404, 'message': '商品不存在', 'data': None},
                    status=status.HTTP_404_NOT_FOUND
                )

            tupian_url = shangpin_obj.tupian_url
            guizetupian_url = shangpin_obj.guize_tupian

            if tupian_url:
                try:
                    delete_from_oss(tupian_url)
                except Exception as e:
                    logger.warning(f"删除商品图片失败: {tupian_url}, 错误: {e}")

            if guizetupian_url:
                try:
                    delete_from_oss(guizetupian_url)
                except Exception as e:
                    logger.warning(f"删除规则图片失败: {guizetupian_url}, 错误: {e}")

            shangpin_obj.delete()

            return Response({
                'code': 0,
                'message': '删除成功',
                'data': {
                    'shangpin_id': shangpin_id,
                    'deleted': True
                }
            })

        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 _update_shangpin(self, request, shangpin_id):
        """修改商品逻辑 - 增加对新字段的支持"""
        try:
            # 查询商品
            try:
                shangpin_obj = Shangpin.objects.get(id=shangpin_id)
            except Shangpin.DoesNotExist:
                return Response(
                    {'code': 404, 'message': '商品不存在', 'data': None},
                    status=status.HTTP_404_NOT_FOUND
                )

            has_changes = False

            # 获取原图片URL
            old_tupian_url = shangpin_obj.tupian_url

            # 3. 处理商品图片上传
            tupian_file = request.FILES.get('tupian_file')
            new_tupian_url = None

            if tupian_file:
                is_valid, error_msg = validate_image(tupian_file)
                if not is_valid:
                    return Response(
                        {'code': 400, 'message': f'图片验证失败: {error_msg}', 'data': None},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                timestamp = int(time.time() * 1000) % 100000000
                random_num = random.randint(1000, 9999)
                file_extension = os.path.splitext(tupian_file.name)[1].lower() or '.jpg'
                new_filename = f"sp_{timestamp}_{random_num}{file_extension}"

                oss_folder = 'a_long'
                shangpin_folder = 'shangpin'
                oss_file_path = f"{oss_folder}/{shangpin_folder}/{new_filename}"

                if old_tupian_url:
                    try:
                        delete_from_oss(old_tupian_url)
                        logger.info(f"已删除旧商品图片: {old_tupian_url}")
                    except Exception as e:
                        logger.warning(f"删除旧商品图片失败: {old_tupian_url}, 错误: {e}")

                new_tupian_url = upload_to_oss(tupian_file, oss_file_path)

                if not new_tupian_url:
                    return Response(
                        {'code': 500, 'message': '商品图片上传失败', 'data': None},
                        status=status.HTTP_500_INTERNAL_SERVER_ERROR
                    )

                shangpin_obj.tupian_url = oss_file_path
                has_changes = True
                logger.info(f"商品图片更新成功: {oss_file_path}")

            # 4. 处理其他字段
            field_mapping = {
                'biaoti': 'biaoqian',
                'jieshao': 'jieshao',
                'jiage': 'jiage',
                'kucun': 'kucun',
                'duiwaixiaoliang': 'duiwai_xiaoliang',
                'xiadanxuzhi': 'xiadan_xuzhi',
                #'yajin': 'yajin',
                # 🔥 新增字段映射
                'yongjin': 'yongjin',
                'yaoqiuleixing': 'yaoqiuleixing',
                'kaioi_ewai_dashou_fencheng': 'kaioi_ewai_dashou_fencheng',
                'ewai_dashou_fencheng': 'ewai_dashou_fencheng',
            }

            # 用于存储临时校验数据
            new_yaoqiuleixing = None
            new_yongjin = None
            new_kaioi_ewai = None
            new_ewai_fencheng = None

            for front_field, db_field in field_mapping.items():
                if front_field in request.data:
                    new_value = request.data.get(front_field)

                    # 空字符串处理
                    if new_value == '':
                        new_value = None

                    # 🔥 对特殊字段进行提前捕获，以便后续业务校验
                    if front_field == 'yaoqiuleixing':
                        if new_value is not None:
                            try:
                                new_yaoqiuleixing = int(new_value)
                            except (ValueError, TypeError):
                                return Response(
                                    {'code': 400, 'message': '抢单要求类型必须是数字', 'data': None},
                                    status=status.HTTP_400_BAD_REQUEST
                                )
                            if new_yaoqiuleixing not in [1, 2]:
                                return Response(
                                    {'code': 400, 'message': '抢单要求类型只能为1(会员抢单)或2(佣金抢单)', 'data': None},
                                    status=status.HTTP_400_BAD_REQUEST
                                )
                        continue  # 稍后统一处理

                    if front_field == 'yongjin':
                        if new_value is not None:
                            try:
                                new_yongjin = Decimal(str(new_value))
                                if new_yongjin < 0:
                                    raise ValueError
                            except (ValueError, InvalidOperation):
                                return Response(
                                    {'code': 400, 'message': '佣金金额必须为正数', 'data': None},
                                    status=status.HTTP_400_BAD_REQUEST
                                )
                        continue

                    if front_field == 'kaioi_ewai_dashou_fencheng':
                        if new_value is not None:
                            # 可能传过来的是字符串 'true'/'false' 或布尔值
                            if isinstance(new_value, str):
                                new_kaioi_ewai = new_value.lower() in ['true', '1', 'on']
                            else:
                                new_kaioi_ewai = bool(new_value)
                        continue

                    if front_field == 'ewai_dashou_fencheng':
                        if new_value is not None:
                            try:
                                new_ewai_fencheng = Decimal(str(new_value))
                                if new_ewai_fencheng <= 0:
                                    raise ValueError
                            except (ValueError, InvalidOperation):
                                return Response(
                                    {'code': 400, 'message': '自定义分红金额必须为正数', 'data': None},
                                    status=status.HTTP_400_BAD_REQUEST
                                )
                        continue

                    # 原有字段处理
                    if new_value is not None:
                        current_value = getattr(shangpin_obj, db_field)
                        try:
                            if db_field in ['jiage']:
                                if new_value:
                                    new_value = Decimal(str(new_value))
                                else:
                                    new_value = None
                            elif db_field in ['kucun', 'duiwai_xiaoliang']:
                                if new_value:
                                    new_value = int(float(new_value))
                                else:
                                    new_value = 0
                        except (ValueError, TypeError, InvalidOperation) as e:
                            logger.warning(f"字段{front_field}转换失败: {new_value}, 错误: {e}")
                            continue

                        if current_value != new_value:
                            setattr(shangpin_obj, db_field, new_value)
                            has_changes = True

            # 🔥 处理抢单要求类型和佣金的关联校验
            if new_yaoqiuleixing is not None:
                # 先更新抢单类型
                if shangpin_obj.yaoqiuleixing != new_yaoqiuleixing:
                    if new_yaoqiuleixing == 1:

                       pass
                    else:
                        shangpin_obj.yaoqiuleixing = new_yaoqiuleixing
                    has_changes = True

                # 如果设置为佣金抢单（2），则必须提供佣金金额
                if new_yaoqiuleixing == 2:
                    if new_yongjin is None:
                        return Response(
                            {'code': 400, 'message': '佣金抢单必须设置佣金金额', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST
                        )
                    # 更新佣金
                    if shangpin_obj.yongjin != new_yongjin:
                        shangpin_obj.yongjin = new_yongjin
                        has_changes = True
                else:
                    pass
            else:
                # 如果抢单类型未传，但佣金传了，需要根据现有类型决定是否允许修改
                if new_yongjin is not None:
                    if shangpin_obj.yaoqiuleixing == 2:
                        # 当前是佣金抢单，允许修改佣金
                        if shangpin_obj.yongjin != new_yongjin:
                            shangpin_obj.yongjin = new_yongjin
                            has_changes = True
                    else:
                        # 当前是会员抢单，不允许单独修改佣金（前端不应发生）
                        return Response(
                            {'code': 400, 'message': '当前为会员抢单，不能修改佣金金额', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST
                        )

            # 🔥 处理打手分红配置
            if new_kaioi_ewai is not None:
                if new_kaioi_ewai:  # 开启自定义分红
                    if new_ewai_fencheng is None:
                        return Response(
                            {'code': 400, 'message': '开启自定义分红必须提供分红金额', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST
                        )
                    if new_ewai_fencheng <= 0:
                        return Response(
                            {'code': 400, 'message': '分红金额必须为正数', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST
                        )
                    # 更新开关和金额
                    if shangpin_obj.kaioi_ewai_dashou_fencheng != new_kaioi_ewai:
                        shangpin_obj.kaioi_ewai_dashou_fencheng = new_kaioi_ewai
                        has_changes = True
                    if shangpin_obj.ewai_dashou_fencheng != new_ewai_fencheng:
                        shangpin_obj.ewai_dashou_fencheng = new_ewai_fencheng
                        has_changes = True
                else:  # 关闭自定义分红
                    if shangpin_obj.kaioi_ewai_dashou_fencheng != new_kaioi_ewai:
                        shangpin_obj.kaioi_ewai_dashou_fencheng = new_kaioi_ewai
                        has_changes = True
                    # 关闭时清空金额（可选）
                    if shangpin_obj.ewai_dashou_fencheng is not None:
                        shangpin_obj.ewai_dashou_fencheng = None
                        has_changes = True
            else:
                # 如果没有传递开关，但传递了分红金额，需要根据现有开关状态处理
                if new_ewai_fencheng is not None:
                    if shangpin_obj.kaioi_ewai_dashou_fencheng:
                        # 开关已开启，允许修改金额
                        if shangpin_obj.ewai_dashou_fencheng != new_ewai_fencheng:
                            shangpin_obj.ewai_dashou_fencheng = new_ewai_fencheng
                            has_changes = True
                    else:
                        # 开关未开启，不能单独修改金额
                        return Response(
                            {'code': 400, 'message': '未开启自定义分红，不能修改分红金额', 'data': None},
                            status=status.HTTP_400_BAD_REQUEST
                        )

            # 5. 如果没有检测到任何更改
            if not has_changes:
                return Response({
                    'code': 400,
                    'message': '没有检测到任何更改',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 6. 保存更改
            shangpin_obj.save()

            # 7. 返回更新后的数据（包含新字段）
            response_data = {
                'tupian_url': shangpin_obj.tupian_url or '',
                'biaoti': shangpin_obj.biaoqian or '',
                'jieshao': shangpin_obj.jieshao or '',
                'jiage': str(shangpin_obj.jiage) if shangpin_obj.jiage else '0.00',
                'kucun': shangpin_obj.kucun,
                'duiwaixiaoliang': shangpin_obj.duiwai_xiaoliang,
                'xiadanxuzhi': shangpin_obj.xiadan_xuzhi or '',
                #'yajin': str(shangpin_obj.yajin) if shangpin_obj.yajin else None,
                'genggaishijian': shangpin_obj.update_time.strftime(
                    '%Y-%m-%d %H:%M:%S') if shangpin_obj.update_time else '',
                # 🔥 新增返回字段
                'yongjin': str(shangpin_obj.yongjin) if shangpin_obj.yongjin else None,
                'yaoqiuleixing': shangpin_obj.yaoqiuleixing,
                'kaioi_ewai_dashou_fencheng': shangpin_obj.kaioi_ewai_dashou_fencheng,
                'ewai_dashou_fencheng': str(shangpin_obj.ewai_dashou_fencheng) if shangpin_obj.ewai_dashou_fencheng else None,
            }

            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
            )











class AdShangpinGuizeXiuGai(APIView):
    """
    后台规则图片更换接口 - 修复版
    修复：每次上传生成新文件名，避免浏览器缓存
    """

    permission_classes = [IsAuthenticated]
    parser_classes = (MultiPartParser, FormParser, JSONParser)

    def post(self, request):
        try:
            # 1. 权限验证
            qianzhanghao = request.data.get('zhanghao', '').strip()
            shangpin_id = request.data.get('shangpin_id')
            action = request.data.get('action', 'update').strip().lower()

            if not qianzhanghao or not shangpin_id:
                return Response(
                    {'code': 400, 'message': '参数不完整', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 验证身份
            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 AdminProfile.DoesNotExist:
                return Response(
                    {'code': 401, 'message': '身份验证失败', 'data': None},
                    status=status.HTTP_401_UNAUTHORIZED
                )

            # 2. 查询商品
            try:
                shangpin_obj = Shangpin.objects.get(id=shangpin_id)
            except Shangpin.DoesNotExist:
                return Response(
                    {'code': 404, 'message': '商品不存在', 'data': None},
                    status=status.HTTP_404_NOT_FOUND
                )

            # 3. 处理不同操作
            if action == 'delete':
                return self._delete_guize_image(shangpin_obj)
            elif action == 'update':
                return self._update_guize_image(request, shangpin_obj)
            else:
                return Response(
                    {'code': 400, 'message': '操作类型无效', 'data': None},
                    status=status.HTTP_400_BAD_REQUEST
                )

        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 _delete_guize_image(self, shangpin_obj):
        """删除规则图片"""
        guizetupian_url = shangpin_obj.guize_tupian

        if guizetupian_url:
            # 从OSS删除
            try:
                delete_success = delete_from_oss(guizetupian_url)
                '''if delete_success:
                    logger.info(f"已删除规则图片: {guizetupian_url}")
                else:
                    logger.warning(f"OSS删除失败，但继续删除数据库记录: {guizetupian_url}")'''
            except Exception as e:
                logger.warning(f"删除规则图片异常: {e}")

            # 清除数据库记录
            shangpin_obj.guize_tupian = ''
            shangpin_obj.save()

        return Response({
            'code': 0,
            'message': '删除成功',
            'data': {
                'guizetupian_url': ''
            }
        })

    def _update_guize_image(self, request, shangpin_obj):
        """更新规则图片 - 修复：每次上传生成新文件名"""
        guize_file = request.FILES.get('guize_file')

        if not guize_file:
            return Response(
                {'code': 400, 'message': '请上传规则图片', 'data': None},
                status=status.HTTP_400_BAD_REQUEST
            )

        # 验证图片
        is_valid, error_msg = validate_image(guize_file)
        if not is_valid:
            return Response(
                {'code': 400, 'message': f'图片验证失败: {error_msg}', 'data': None},
                status=status.HTTP_400_BAD_REQUEST
            )

        # 获取原规则图片URL
        old_guizetupian_url = shangpin_obj.guize_tupian

        # 生成新文件名：时间戳 + 随机数 + 原扩展名
        timestamp = int(time.time() * 1000) % 100000000  # 8位时间戳
        random_num = random.randint(1000, 9999)
        file_extension = os.path.splitext(guize_file.name)[1].lower() or '.jpg'
        new_filename = f"gz_{timestamp}_{random_num}{file_extension}"

        # 确定OSS路径
        oss_folder = 'a_long'
        guize_folder = 'guize'  # 修改为你的要求：a_long/guize/
        oss_file_path = f"{oss_folder}/{guize_folder}/{new_filename}"

        # 删除旧图片（如果存在）
        if old_guizetupian_url:
            try:
                delete_from_oss(old_guizetupian_url)
                #logger.info(f"已删除旧规则图片: {old_guizetupian_url}")
            except Exception as e:
                logger.warning(f"删除旧规则图片失败: {old_guizetupian_url}, 错误: {e}")
                # 继续上传新图片，不中断流程

        # 上传到OSS
        new_guizetupian_url = upload_to_oss(guize_file, oss_file_path)

        if not new_guizetupian_url:
            return Response(
                {'code': 500, 'message': '规则图片上传失败', 'data': None},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )

        # 更新数据库（存相对路径）
        shangpin_obj.guize_tupian = oss_file_path
        shangpin_obj.save()

        #logger.info(f"规则图片更新成功: {oss_file_path}")

        return Response({
            'code': 0,
            'message': '规则图片更新成功',
            'data': {
                'guizetupian_url': oss_file_path  # 返回相对路径
            }
        })





# views.py
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework import status
from django.utils import timezone
from django.db.models import Q, Count, Subquery, OuterRef
from django.db import connection
from django.core.paginator import Paginator
import json

from .models import Huiyuan
from yonghu.models import UserMain, AdminProfile


class HuiyuanTypeListView(APIView):
    """
    获取会员类型列表接口
    路径：/shangpin/adhyjllxcx
    方法：POST
    权限：JWT Token + 管理员验证
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # 🔥 1. 身份验证
            user = request.user

            # 检查是否是管理员
            if not hasattr(user, 'admin_profile'):
                return Response({
                    'code': 401,
                    'message': '无权限访问',
                    'data': None
                }, status=status.HTTP_401_UNAUTHORIZED)

            # 🔥 2. 获取所有会员类型
            huiyuan_list = Huiyuan.objects.all().order_by('create_time')

            # 🔥 3. 构建返回数据
            huiyuan_data = []
            for huiyuan in huiyuan_list:
                huiyuan_data.append({
                    'id': huiyuan.huiyuan_id,  # 会员ID
                    'jieshao': huiyuan.jieshao,  # 会员介绍
                    'jiage': str(huiyuan.jiage),  # 价格
                    'goumai_cishu': huiyuan.goumai_cishu,  # 购买次数
                    'create_time': huiyuan.create_time.strftime('%Y-%m-%d %H:%M:%S') if huiyuan.create_time else None
                })

            return Response({
                'code': 0,
                'message': '获取成功',
                'data': huiyuan_data
            }, status=status.HTTP_200_OK)

        except Exception as e:
            print(f"获取会员类型列表失败: {str(e)}")
            return Response({
                'code': 500,
                'message': '系统错误',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class HuiyuanRecordListView(APIView):
    """
    获取会员记录列表接口
    路径：/shangpin/adhyjlcxhq
    方法：POST
    权限：JWT Token + 管理员验证
    参数：
        - zhanghao: 管理员账号
        - huiyuan_type: 会员类型ID
        - jiluzhuangtai: 记录状态（1=未过期, 2=已过期）
        - page: 页码
        - pagesize: 每页条数
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # 🔥 1. 身份验证
            user = request.user

            # 检查是否是管理员
            if not hasattr(user, 'admin_profile'):
                return Response({
                    'code': 401,
                    'message': '无权限访问',
                    'data': None
                }, status=status.HTTP_401_UNAUTHORIZED)

            # 🔥 2. 获取参数
            zhanghao = request.data.get('zhanghao', '').strip()
            huiyuan_type = request.data.get('huiyuan_type', '').strip()
            jiluzhuangtai = request.data.get('jiluzhuangtai', 1)  # 默认未过期
            page = int(request.data.get('page', 1))
            pagesize = int(request.data.get('pagesize', 5))

            # 🔥 3. 参数验证
            if not zhanghao:
                return Response({
                    'code': 400,
                    'message': '管理员账号不能为空',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            if not huiyuan_type:
                return Response({
                    'code': 400,
                    'message': '会员类型不能为空',
                    'data': None
                }, status=status.HTTP_400_BAD_REQUEST)

            # 🔥 4. 检查会员类型是否存在
            huiyuan_obj = Huiyuan.objects.filter(huiyuan_id=huiyuan_type).first()
            if not huiyuan_obj:
                return Response({
                    'code': 404,
                    'message': '会员类型不存在',
                    'data': None
                }, status=status.HTTP_404_NOT_FOUND)

            # 🔥 5. 构建基础查询（一次性获取所有符合条件的记录ID）
            now = timezone.now()

            # 🔥 使用原生SQL优化查询（避免N+1问题）
            with connection.cursor() as cursor:
                # 先查询符合条件的总记录数
                count_sql = """
                    SELECT COUNT(*) 
                    FROM huiyuangoumai hg
                    WHERE hg.huiyuan_id = %s 
                """
                params = [huiyuan_type]

                if jiluzhuangtai == 1:  # 未过期
                    count_sql += " AND hg.daoqi_time > %s"
                    params.append(now)
                else:  # 已过期
                    count_sql += " AND hg.daoqi_time <= %s"
                    params.append(now)

                cursor.execute(count_sql, params)
                total_count = cursor.fetchone()[0]

                # 🔥 6. 分页查询（使用窗口函数提高性能）
                offset = (page - 1) * pagesize

                record_sql = """
                    SELECT 
                        hg.id,
                        hg.yonghu_id,
                        hg.huiyuan_id,
                        hg.jieshao,
                        hg.daoqi_time,
                        hg.create_time,
                        um.avatar,
                        ud.nicheng
                    FROM huiyuangoumai hg
                    LEFT JOIN user_main um ON hg.yonghu_id = um.yonghuid
                    LEFT JOIN user_dashou ud ON um.id = ud.user_id
                    WHERE hg.huiyuan_id = %s 
                """

                record_params = [huiyuan_type]

                if jiluzhuangtai == 1:  # 未过期
                    record_sql += " AND hg.daoqi_time > %s"
                    record_params.append(now)
                else:  # 已过期
                    record_sql += " AND hg.daoqi_time <= %s"
                    record_params.append(now)

                record_sql += " ORDER BY hg.create_time DESC LIMIT %s OFFSET %s"
                record_params.extend([pagesize, offset])

                cursor.execute(record_sql, record_params)
                records = cursor.fetchall()

            # 🔥 7. 处理查询结果
            record_list = []
            for record in records:
                record_list.append({
                    'id': record[0],
                    'yonghuid': record[1],  # 用户ID
                    'huiyuan_id': record[2],
                    'jieshao': record[3],
                    'daoqi_time': record[4].strftime('%Y-%m-%d %H:%M:%S') if record[4] else None,
                    'create_time': record[5].strftime('%Y-%m-%d %H:%M:%S') if record[5] else None,
                    'touxiang': record[6],  # 头像相对URL
                    'nicheng': record[7] or record[1],  # 昵称或用户ID
                    'yonghu_type': 2  # 🔥 默认打手类型（实际应该根据user_type判断）
                })

            # 🔥 8. 判断是否还有更多数据
            has_more = (page * pagesize) < total_count

            # 🔥 9. 获取会员类型统计信息（所有会员类型的当前状态总数）
            huiyuan_types = Huiyuan.objects.all()
            huiyuan_stats = []

            for huiyuan in huiyuan_types:
                # 使用COUNT查询统计
                stats_sql = """
                    SELECT COUNT(*) 
                    FROM huiyuangoumai 
                    WHERE huiyuan_id = %s 
                """
                stats_params = [huiyuan.huiyuan_id]

                if jiluzhuangtai == 1:  # 未过期
                    stats_sql += " AND daoqi_time > %s"
                    stats_params.append(now)
                else:  # 已过期
                    stats_sql += " AND daoqi_time <= %s"
                    stats_params.append(now)

                with connection.cursor() as cursor:
                    cursor.execute(stats_sql, stats_params)
                    count = cursor.fetchone()[0]

                huiyuan_stats.append({
                    'id': huiyuan.huiyuan_id,
                    'jieshao': huiyuan.jieshao,
                    'count': count
                })

            return Response({
                'code': 0,
                'message': '获取成功',
                'data': {
                    'list': record_list,
                    'total': total_count,
                    'current_page': page,
                    'page_size': pagesize,
                    'has_more': has_more,
                    'huiyuan_stats': huiyuan_stats,  # 🔥 所有会员类型的统计
                    'current_huiyuan': {
                        'id': huiyuan_obj.huiyuan_id,
                        'jieshao': huiyuan_obj.jieshao,
                        'count': total_count
                    }
                }
            }, status=status.HTTP_200_OK)

        except ValueError as e:
            print(f"参数错误: {str(e)}")
            return Response({
                'code': 400,
                'message': '参数错误',
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)

        except Exception as e:
            print(f"获取会员记录失败: {str(e)}")
            import traceback
            traceback.print_exc()
            return Response({
                'code': 500,
                'message': '系统错误',
                'data': None
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)



import decimal

class ZuzhangFenhongView(APIView):
    """
    组长分红记录接口
    路径：/shangpin/zuzhangfenhong
    方法：POST
    权限：JWT认证，仅限组长身份
    请求参数：
        {
            "page": 1,          # 页码，默认1
            "page_size": 5       # 每页条数，默认5
        }
    返回：
        {
            "code": 200,
            "msg": "success",
            "data": {
                "fenhong_zonge": "1234.56",       # 分红总额
                "yaoqing_guanshi": 10,             # 邀请管事数
                "fenhong_cishu": 50,                # 分红次数
                "total": 50,                         # 总记录数
                "has_more": false,                    # 是否有下一页
                "list": [...]                          # 记录列表
            }
        }
    """
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        current_user = request.user

        # 1. 验证组长身份
        try:
            zuzhang = UserZuzhang.objects.get(user=current_user)
        except UserZuzhang.DoesNotExist:
            return Response({
                'code': 403,
                'msg': '当前用户不是组长身份',
                'data': None
            }, status=status.HTTP_403_FORBIDDEN)

        # 2. 请求参数
        page = int(request.data.get('page', 1))
        page_size = int(request.data.get('page_size', 5))
        page = max(page, 1)
        page_size = max(page_size, 1)

        # 3. 统计数据
        # 3.1 分红总额（从组长扩展表）
        fenhong_zonge = zuzhang.fenyong_zonge

        # 3.2 邀请管事数（统计邀请人等于当前用户ID的管事记录）
        yaoqing_guanshi = UserGuanshi.objects.filter(yaoqingren=current_user.yonghuid).count()

        # 3.3 分红次数（总记录数）
        base_queryset = Gsfenhong.objects.filter(zuzhang_id=current_user.yonghuid).order_by('-create_time')
        fenhong_cishu = base_queryset.count()

        # 4. 分页查询
        start = (page - 1) * page_size
        end = start + page_size
        records = base_queryset[start:end]

        # 5. 批量获取管事用户信息（只查 boss_profile 获取昵称）
        guanshi_ids = list(set(rec.guanshi for rec in records if rec.guanshi))
        guanshi_info_map = self._get_guanshi_info(guanshi_ids)

        # 6. 组装列表数据
        list_data = []
        for rec in records:
            # 打手信息（直接从记录中取快照）
            dashou_avatar = rec.avatar or ''
            dashou_nicheng = rec.nicheng or ''
            dashou_yonghuid = rec.dashouid or ''

            # 管事信息
            guanshi_id = rec.guanshi
            guanshi_info = guanshi_info_map.get(guanshi_id, {'avatar': '', 'nicheng': ''})
            guanshi_avatar = guanshi_info['avatar']
            guanshi_nicheng = guanshi_info['nicheng']

            # 组长分红金额
            fenhong = rec.zuzhang_fenhong
            if fenhong is None:
                fenhong = decimal.Decimal('0.00')
            fenhong_str = str(fenhong.quantize(decimal.Decimal('0.00')))

            # 时间格式化
            create_time = rec.create_time.strftime('%Y-%m-%d %H:%M:%S') if rec.create_time else ''

            list_data.append({
                'dashou_avatar': dashou_avatar,
                'dashou_nicheng': dashou_nicheng,
                'dashou_yonghuid': dashou_yonghuid,
                'guanshi_avatar': guanshi_avatar,
                'guanshi_nicheng': guanshi_nicheng,
                'guanshi_yonghuid': guanshi_id,
                'fenhong': fenhong_str,
                'create_time': create_time,
            })

        # 7. 是否有更多数据
        has_more = (end < fenhong_cishu)

        return Response({
            'code': 200,
            'msg': 'success',
            'data': {
                'fenhong_zonge': str(fenhong_zonge.quantize(decimal.Decimal('0.00'))),
                'yaoqing_guanshi': yaoqing_guanshi,
                'fenhong_cishu': fenhong_cishu,
                'total': fenhong_cishu,
                'has_more': has_more,
                'list': list_data,
            }
        })

    def _get_guanshi_info(self, guanshi_ids):
        """
        批量获取管事用户的头像和昵称
        昵称从老板扩展表（boss_profile）获取，头像从主表获取
        返回字典：{用户ID: {'avatar': 相对路径, 'nicheng': 昵称}}
        """
        if not guanshi_ids:
            return {}

        # 查询用户主表，并预加载 boss_profile
        users = UserMain.objects.filter(yonghuid__in=guanshi_ids).select_related(
            'boss_profile'
        ).only(
            'yonghuid', 'avatar',
            'boss_profile__nickname'
        )

        info = {}
        for user in users:
            avatar = user.avatar or ''
            # 从 boss_profile 获取昵称
            if hasattr(user, 'boss_profile') and user.boss_profile:
                nicheng = user.boss_profile.nickname or ''
            else:
                # 如果没有 boss_profile，使用默认昵称
                nicheng = f"用户{user.yonghuid[-4:]}"
            info[user.yonghuid] = {'avatar': avatar, 'nicheng': nicheng}

        # 对于未查询到的用户，提供默认值
        for gid in guanshi_ids:
            if gid not in info:
                info[gid] = {'avatar': '', 'nicheng': f"用户{gid[-4:]}"}

        return info





from dingdan.models import Lilubiao

# 常量定义（可根据需要调整）
INTEGRAL_PRICE = decimal.Decimal('10.00')  # 积分购买固定价格（元）


'''class CzhqdyView(APIView):
    """
    获取可用抵扣身份接口
    路径：/shangpin/czhqdy
    方法：POST
    权限：JWT认证
    请求参数：
        leixing: int  # 1=会员，2=押金，3=积分
        huiyuan_id: str  # 当 leixing=1 时必传，会员ID
        yajin_jine: decimal  # 当 leixing=2 时必传，押金金额（元）
    返回：
        {
            "code": 200,
            "msg": "success",
            "data": [
                {
                    "id": 1,               # 身份ID：1打手 2管事 3组长
                    "jieshao": "打手佣金抵扣",
                    "xuyao": "22.22"         # 所需抵扣金额（保留两位小数）
                },
                ...
            ]
        }
    """
    permission_classes = [permissions.IsAuthenticated]

    # 身份ID与对应扩展表模型、余额字段、费率查询条件的映射
    IDENTITY_CONFIG = [
        {
            'id': 1,
            'name': '打手佣金抵扣',
            'profile_attr': 'dashou_profile',  # UserMain 的反向 related_name
            'balance_field': 'yue',
            'rate_key': '5',
            'model': UserDashou,
        },
        {
            'id': 2,
            'name': '管事分红抵扣',
            'profile_attr': 'guanshi_profile',
            'balance_field': 'yue',
            'rate_key': '6',
            'model': UserGuanshi,
        },
        {
            'id': 3,
            'name': '组长分红抵扣',
            'profile_attr': 'zuzhang_profile',
            'balance_field': 'ketixian_jine',
            'rate_key': '8',
            'model': UserZuzhang,
        },
    ]

    def post(self, request):
        # 获取参数
        leixing = request.data.get('leixing')
        huiyuan_id = request.data.get('huiyuan_id')
        yajin_jine = request.data.get('yajin_jine')

        # 参数校验
        if leixing not in [1, 2, 3,4]:
            return Response({'code': 400, 'msg': 'leixing 必须为 '}, status=status.HTTP_400_BAD_REQUEST)

        if leixing == 1 and not huiyuan_id:
            return Response({'code': 400, 'msg': '购买会员时必须提供 huiyuan_id'}, status=status.HTTP_400_BAD_REQUEST)

        if leixing == 2:
            if not yajin_jine:
                return Response({'code': 400, 'msg': '购买押金时必须提供 yajin_jine'}, status=status.HTTP_400_BAD_REQUEST)
            try:
                yajin_jine = decimal.Decimal(str(yajin_jine))
                if yajin_jine <= 0:
                    raise ValueError
            except:
                return Response({'code': 400, 'msg': 'yajin_jine 必须为正数'}, status=status.HTTP_400_BAD_REQUEST)




        # 获取当前用户
        user = request.user

        # 获取目标价格（需支付的原价）
        target_price = None
        if leixing == 1:
            # 会员
            try:
                huiyuan = Huiyuan.objects.get(huiyuan_id=huiyuan_id)
                target_price = huiyuan.jiage
            except Huiyuan.DoesNotExist:
                return Response({'code': 404, 'msg': '会员不存在'}, status=status.HTTP_404_NOT_FOUND)
        elif leixing == 2:
            # 押金
            target_price = yajin_jine

        elif leixing == 4:
            from dingdan.models import Fadan  # 罚单模型
            # 其他 UserDashou、UserGuanshi、UserZuzhang、Lilubiao、Czjilu 等已有
            # 罚款缴纳
            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, beichufa_id=request.user.yonghuid)
                target_price = fadan.fakuanjine
            except Fadan.DoesNotExist:
                return Response({'code': 404, 'msg': '罚单不存在或不属于当前用户'}, status=status.HTTP_404_NOT_FOUND)
        else:  # leixing == 3
            # 积分（固定价格）
            target_price = INTEGRAL_PRICE

        # 获取所有费率（打手、管事、组长）
        rates = {}
        for key in ['5', '6', '8']:
            try:
                rate_obj = Lilubiao.objects.get(fadanpingtai=key)
                rates[key] = rate_obj.lilu
            except Lilubiao.DoesNotExist:
                # 如果某个费率不存在，则跳过该身份（后续不会返回）
                rates[key] = None

        # 构建可用身份列表
        available_list = []

        for ident in self.IDENTITY_CONFIG:
            # 检查用户是否有该扩展表
            profile = getattr(user, ident['profile_attr'], None)
            if not profile:
                continue

            # 获取余额
            balance = getattr(profile, ident['balance_field'], decimal.Decimal('0.00'))

            # 获取费率
            rate = rates.get(ident['rate_key'])
            if rate is None:
                continue  # 费率未配置，跳过该身份

            # 计算所需抵扣金额： target_price / (1 - rate) ，向上取整到分
            # 注意 rate 是小数，如 0.08 表示 8%
            try:
                # 防止除零
                if rate >= 1:
                    continue
                required = target_price / (decimal.Decimal('1.0') - rate)
                # 向上取整到分（保留两位小数，最后一位进位）
                # 使用 quantize 向上舍入： ROUND_CEILING
                required = required.quantize(decimal.Decimal('0.01'), rounding=decimal.ROUND_CEILING)
            except Exception as e:
                continue  # 计算异常，跳过

            # 余额是否足够
            if balance >= required:
                available_list.append({
                    'id': ident['id'],
                    'jieshao': ident['name'],
                    'xuyao': str(required),
                })

        return Response({
            'code': 200,
            'msg': 'success',
            'data': available_list
        })



from dingdan.models import Fadan


from decimal import Decimal, ROUND_CEILING
# 常量定义（可根据需要调整）
INTEGRAL_PRICE = Decimal('10.00')  # 积分购买固定价格（元）
INTEGRAL_INCREMENT = 5  # 每次积分补充增加5分
MAX_INTEGRAL = 10  # 最大积分限制

# 身份映射配置
IDENTITY_CONFIG = {
    1: {
        'name': '打手佣金',
        'model': UserDashou,
        'balance_field': 'yue',
        'status_field': 'zhanghaozhuangtai',  # 1正常
        'rate_key': '5',
    },
    2: {
        'name': '管事分红',
        'model': UserGuanshi,
        'balance_field': 'yue',
        'status_field': 'zhuangtai',  # 1正常
        'rate_key': '6',
    },
    3: {
        'name': '组长分红',
        'model': UserZuzhang,
        'balance_field': 'ketixian_jine',
        'status_field': 'zhuangtai',  # 1正常
        'rate_key': '8',
    },
}


class DsqrgmdhView(APIView):
    """
    余额抵扣支付接口
    路径：/shangpin/dsqrgmdh
    方法：POST
    权限：JWT认证
    请求参数：
        leixing: int      # 购买类型：1会员 2押金 3积分
        shenfen_id: int   # 抵扣身份：1打手 2管事 3组长
        huiyuan_id: str   # 当 leixing=1 时必传，会员ID
        yajin_jine: decimal  # 当 leixing=2 时必传，押金金额（元）
    返回：
        {
            "code": 200,
            "msg": "success",
            "data": {
                # 根据购买类型返回对应字段
                "yajin": 1000,               # 押金更新后（leixing=2）
                "jifen": 10,                  # 积分更新后（leixing=3）
                "huiyuan": { ... }             # 会员购买记录（leixing=1）
                # 以及其他可能需要的数据
            }
        }
    """
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        # 获取参数
        leixing = request.data.get('leixing')
        shenfen_id = request.data.get('shenfen_id')
        huiyuan_id = request.data.get('huiyuan_id')
        yajin_jine = request.data.get('yajin_jine')

        # ----- 参数基本校验 -----
        if leixing not in [1, 2, 3,4]:
            return Response({'code': 400, 'msg': 'leixing 必须为 1/2/3/4'}, status=status.HTTP_400_BAD_REQUEST)
        if shenfen_id not in [1, 2, 3]:
            return Response({'code': 400, 'msg': 'shenfen_id 必须为 1/2/3'}, status=status.HTTP_400_BAD_REQUEST)

        if leixing == 1 and not huiyuan_id:
            return Response({'code': 400, 'msg': '购买会员时必须提供 huiyuan_id'}, status=status.HTTP_400_BAD_REQUEST)
        if leixing == 2:
            if not yajin_jine:
                return Response({'code': 400, 'msg': '购买押金时必须提供 yajin_jine'}, status=status.HTTP_400_BAD_REQUEST)
            try:
                yajin_jine = Decimal(str(yajin_jine))
                if yajin_jine <= 0:
                    raise ValueError
                if yajin_jine > Decimal('10000'):
                    return Response({'code': 400, 'msg': '押金金额不能超过10000元'}, status=status.HTTP_400_BAD_REQUEST)
            except:
                return Response({'code': 400, 'msg': 'yajin_jine 必须为正数'}, status=status.HTTP_400_BAD_REQUEST)

        # ----- 获取目标价格（需支付的原价） -----
        target_price = None
        if leixing == 1:
            try:
                huiyuan = Huiyuan.objects.get(huiyuan_id=huiyuan_id)
                target_price = huiyuan.jiage
            except Huiyuan.DoesNotExist:
                return Response({'code': 404, 'msg': '会员不存在'}, status=status.HTTP_404_NOT_FOUND)
        elif leixing == 2:
            target_price = yajin_jine

        elif leixing == 4:
            action_desc = "罚款缴纳"
        else:  # leixing == 3
            target_price = INTEGRAL_PRICE

        # ----- 获取对应身份费率 -----
        identity = IDENTITY_CONFIG.get(shenfen_id)
        try:
            rate_obj = Lilubiao.objects.get(fadanpingtai=identity['rate_key'])
            rate = rate_obj.lilu  # Decimal
            if rate >= 1:
                return Response({'code': 400, 'msg': f"{identity['name']}费率异常"}, status=status.HTTP_400_BAD_REQUEST)
        except Lilubiao.DoesNotExist:
            return Response({'code': 400, 'msg': f"{identity['name']}费率未配置"}, status=status.HTTP_400_BAD_REQUEST)

        # ----- 计算所需抵扣金额（向上取整到分） -----
        try:
            required = target_price / (Decimal('1.0') - rate)
            required = required.quantize(Decimal('0.01'), rounding=ROUND_CEILING)
        except Exception as e:
            return Response({'code': 500, 'msg': f'金额计算错误: {str(e)}'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        # ----- 获取当前用户 -----
        user = request.user
        yonghuid = user.yonghuid

        # ----- 获取对应身份扩展表并验证状态和余额 -----
        try:
            profile = identity['model'].objects.get(user=user)
        except identity['model'].DoesNotExist:
            return Response({'code': 403, 'msg': f'您不是{identity["name"]}身份'})

        # 验证账号状态
        status_value = getattr(profile, identity['status_field'])
        if status_value != 1:
            return Response({'code': 403, 'msg': f'{identity["name"]}账号状态异常，无法使用'})

        # 验证余额是否足够
        balance = getattr(profile, identity['balance_field'])
        if balance < required:
            return Response({'code': 400, 'msg': f'{identity["name"]}余额不足，需要{required}元，当前{balance}元'}, status=status.HTTP_400_BAD_REQUEST)

        # ----- 开始事务处理 -----
        try:
            with transaction.atomic():
                # 锁定扩展表记录（防止并发扣除）
                locked_profile = identity['model'].objects.select_for_update().get(id=profile.id)

                # 再次验证余额（安全）
                current_balance = getattr(locked_profile, identity['balance_field'])
                if current_balance < required:
                    raise ValueError(f"{identity['name']}余额不足，需要{required}元，当前{current_balance}元")

                # 扣除余额
                setattr(locked_profile, identity['balance_field'], current_balance - required)
                locked_profile.save(update_fields=[identity['balance_field']])

                # ----- 生成订单ID -----
                timestamp = str(int(time.time() * 1000))[-12:]
                rand_str = ''.join(random.choices(string.ascii_uppercase + string.digits, k=4))
                dingdan_id = f"CZ{timestamp}{rand_str}"

                # 构建订单说明
                if leixing == 1:
                    action_desc = f"购买会员 {huiyuan.jieshao}"
                elif leixing == 2:
                    action_desc = f"充值押金 {yajin_jine}元"

                elif leixing == 4:
                    from dingdan.models import Fadan
                    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, beichufa_id=request.user.yonghuid)
                        target_price = fadan.fakuanjine
                    except Fadan.DoesNotExist:
                        return Response({'code': 404, 'msg': '罚单不存在'}, status=status.HTTP_404_NOT_FOUND)

                else:
                    action_desc = "补充积分"

                shuoming = f"{identity['name']}抵扣 {action_desc}，抵扣金额{required}元"

                # 创建充值记录
                czjilu = Czjilu.objects.create(
                    dingdan_id=dingdan_id,
                    huiyuan_id=huiyuan_id if leixing == 1 else None,
                    zhuangtai=1,  # 已完成
                    yonghuid=yonghuid,
                    jine=required,  # 实际扣除的金额
                    leixing=leixing,
                    shuoming=shuoming,
                )

                # ----- 根据购买类型执行具体业务逻辑 -----
                response_data = {}

                if leixing == 1:  # 会员
                    # 处理会员购买/续费
                    huiyuan_record, is_first_buy = self._process_member_purchase(yonghuid, huiyuan_id, huiyuan)
                    response_data['huiyuan'] = {
                        'huiyuanid': huiyuan_id,
                        'huiyuanming': huiyuan.jieshao,
                        'daoqi': huiyuan_record.daoqi_time.strftime('%Y-%m-%d %H:%M:%S') if hasattr(huiyuan_record, 'daoqi_time') else '',
                    }

                    # 如果首次购买任何会员，给打手加10积分
                    if is_first_buy:
                        try:
                            dashou = UserDashou.objects.get(user=user)
                            dashou.jifen += 10
                            dashou.save(update_fields=['jifen'])
                            response_data['jifen'] = dashou.jifen
                        except UserDashou.DoesNotExist:
                            pass

                elif leixing == 2:  # 押金
                    # 更新打手押金
                    try:
                        dashou = UserDashou.objects.select_for_update().get(user=user)
                        dashou.yajin += yajin_jine  # 注意：增加的是原价，不是抵扣金额
                        dashou.save(update_fields=['yajin'])
                        response_data['yajin'] = dashou.yajin
                    except UserDashou.DoesNotExist:
                        return Response({'code': 500, 'msg': '打手信息不存在，无法充值押金'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)



                elif leixing == 4:  # 🔥 罚款：只更新罚单状态，不重复扣款

                    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, beichufa_id=request.user.yonghuid)

                    except Fadan.DoesNotExist:

                        return Response({'code': 404, 'msg': '罚单不存在或不属于当前用户'},
                                        status=status.HTTP_404_NOT_FOUND)

                    if fadan.zhuangtai not in [1, 3]:
                        return Response({'code': 400, 'msg': '罚单状态不可缴纳'}, status=status.HTTP_400_BAD_REQUEST)

                    fadan.zhuangtai = 2  # 已缴纳

                    fadan.save(update_fields=['zhuangtai'])

                    response_data['fadan_id'] = fadan.id

                    response_data['fadan_status'] = fadan.zhuangtai
                    from utils.fadan_utils import fadan_fenhong
                    fadan_fenhong(fadan.id)

                else:  # leixing == 3 积分
                    # 更新打手积分
                    try:
                        dashou = UserDashou.objects.select_for_update().get(user=user)
                        new_jifen = dashou.jifen + INTEGRAL_INCREMENT
                        dashou.jifen = min(new_jifen, MAX_INTEGRAL)  # 不超过10分
                        dashou.save(update_fields=['jifen'])
                        response_data['jifen'] = dashou.jifen
                    except UserDashou.DoesNotExist:
                        return Response({'code': 500, 'msg': '打手信息不存在，无法补充积分'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)



        except Exception as e:
            import traceback
            traceback.print_exc()
            return Response({'code': 500, 'msg': f'支付处理失败: {str(e)}'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        # ----- 返回成功响应，附带更新后的数据 -----
        # 补充其他可能需要的数据（如更新后的余额等）
        # 可以查询最新的余额返回
        final_profile = identity['model'].objects.get(user=user)
        response_data['balance'] = str(getattr(final_profile, identity['balance_field']))

        return Response({
            'code': 200,
            'msg': 'success',
            'data': response_data,
        })

    def _process_member_purchase(self, yonghuid, huiyuan_id, huiyuan_obj):
        """
        处理会员购买/续费
        返回 (Huiyuangoumai对象, is_first_buy_any)
        """
        is_first_buy_any = False
        try:
            # 检查是否已有该会员记录
            record = Huiyuangoumai.objects.filter(
                yonghu_id=yonghuid,
                huiyuan_id=huiyuan_id
            ).first()

            if record:
                # 续费
                record.daoqi_time += timedelta(days=30)
                record.huiyuan_zhuangtai = 1
                record.save(update_fields=['daoqi_time', 'huiyuan_zhuangtai'])
            else:
                # 新购
                # 检查用户是否购买过任何会员（用于判断是否首次购买）
                other_count = Huiyuangoumai.objects.filter(yonghu_id=yonghuid).exclude(huiyuan_id=huiyuan_id).count()
                if other_count == 0:
                    is_first_buy_any = True

                record = Huiyuangoumai.objects.create(
                    yonghu_id=yonghuid,
                    huiyuan_id=huiyuan_id,
                    jieshao=huiyuan_obj.jieshao,
                    huiyuan_zhuangtai=1,
                    daoqi_time=timezone.now() + timedelta(days=30)
                )
            return record, is_first_buy_any
        except Exception as e:
            # 如果出现唯一性冲突（极低概率），重试一次
            if 'unique' in str(e).lower() or 'duplicate' in str(e).lower():
                # 直接查询已存在的记录
                record = Huiyuangoumai.objects.get(yonghu_id=yonghuid, huiyuan_id=huiyuan_id)
                return record, False
            raise'''



from dingdan.models import Fadan  # 用于罚款类型
class CzhqdyView(APIView):
    """
    获取可用抵扣身份接口
    路径：/shangpin/czhqdy
    方法：POST
    权限：JWT认证
    请求参数：
        leixing: int  # 1=会员，2=押金，3=积分，4=罚款
        huiyuan_id: str  # 当 leixing=1 时必传，会员ID
        yajin_jine: decimal  # 当 leixing=2 时必传，押金金额（元）
        fadan_id: int      # 当 leixing=4 时必传，罚单ID
    返回：
        {
            "code": 200,
            "msg": "success",
            "data": [
                {
                    "id": 1,               # 身份ID：1打手佣金 2管事分红 3组长分红 4打手押金
                    "jieshao": "打手佣金抵扣",
                    "xuyao": "22.22"         # 所需抵扣金额（保留两位小数）
                },
                ...
            ]
        }
    """
    permission_classes = [permissions.IsAuthenticated]

    # 身份ID与对应扩展表模型、余额字段、费率查询条件的映射
    IDENTITY_CONFIG = [
        {
            'id': 1,
            'name': '打手佣金抵扣',
            'profile_attr': 'dashou_profile',  # UserMain 的反向 related_name
            'balance_field': 'yue',
            'rate_key': '5',
            'model': UserDashou,
        },
        {
            'id': 2,
            'name': '管事分红抵扣',
            'profile_attr': 'guanshi_profile',
            'balance_field': 'yue',
            'rate_key': '6',
            'model': UserGuanshi,
        },
        {
            'id': 3,
            'name': '组长分红抵扣',
            'profile_attr': 'zuzhang_profile',
            'balance_field': 'ketixian_jine',
            'rate_key': '8',
            'model': UserZuzhang,
        },
        # 新增打手押金抵扣
        {
            'id': 4,
            'name': '打手押金抵扣',
            'profile_attr': 'dashou_profile',   # 与打手佣金共用扩展表
            'balance_field': 'yajin',           # 押金字段
            'rate_key': '11',                   # 押金提现费率对应的 fadanpingtai
            'model': UserDashou,
        },
    ]

    def post(self, request):
        # 获取参数
        leixing = request.data.get('leixing')
        huiyuan_id = request.data.get('huiyuan_id')
        yajin_jine = request.data.get('yajin_jine')
        fadan_id = request.data.get('fadan_id')

        # 参数校验
        if leixing not in [1, 2, 3, 4]:
            return Response({'code': 400, 'msg': 'leixing 必须为 1,2,3,4'}, status=status.HTTP_400_BAD_REQUEST)

        if leixing == 1 and not huiyuan_id:
            return Response({'code': 400, 'msg': '购买会员时必须提供 huiyuan_id'}, status=status.HTTP_400_BAD_REQUEST)

        if leixing == 2:
            if not yajin_jine:
                return Response({'code': 400, 'msg': '购买押金时必须提供 yajin_jine'}, status=status.HTTP_400_BAD_REQUEST)
            try:
                yajin_jine = decimal.Decimal(str(yajin_jine))
                if yajin_jine <= 0:
                    raise ValueError
            except:
                return Response({'code': 400, 'msg': 'yajin_jine 必须为正数'}, status=status.HTTP_400_BAD_REQUEST)

        if leixing == 4 and not fadan_id:
            return Response({'code': 400, 'msg': '缴纳罚款时必须提供 fadan_id'}, status=status.HTTP_400_BAD_REQUEST)

        # 获取当前用户
        user = request.user

        # 获取目标价格（需支付的原价）
        target_price = None
        if leixing == 1:
            # 会员
            try:
                huiyuan = Huiyuan.objects.get(huiyuan_id=huiyuan_id)
                target_price = huiyuan.jiage
            except Huiyuan.DoesNotExist:
                return Response({'code': 404, 'msg': '会员不存在'}, status=status.HTTP_404_NOT_FOUND)
        elif leixing == 2:
            # 押金
            target_price = yajin_jine
        elif leixing == 3:
            # 积分（固定价格）
            target_price = INTEGRAL_PRICE
        elif leixing == 4:
            # 罚款缴纳
            try:
                fadan = Fadan.objects.get(id=fadan_id, beichufa_id=user.yonghuid)
                target_price = fadan.fakuanjine
            except Fadan.DoesNotExist:
                return Response({'code': 404, 'msg': '罚单不存在或不属于当前用户'}, status=status.HTTP_404_NOT_FOUND)

        # 获取所有费率（打手佣金、管事分红、组长分红、打手押金）
        rates = {}
        for key in ['5', '6', '8', '11']:
            try:
                rate_obj = Lilubiao.objects.get(fadanpingtai=key)
                rates[key] = rate_obj.lilu
            except Lilubiao.DoesNotExist:
                rates[key] = None  # 未配置则跳过

        # 构建可用身份列表
        available_list = []

        for ident in self.IDENTITY_CONFIG:
            # 检查用户是否有该扩展表
            profile = getattr(user, ident['profile_attr'], None)
            if not profile:
                continue

            # 获取余额
            balance = getattr(profile, ident['balance_field'], decimal.Decimal('0.00'))

            # 获取费率
            rate = rates.get(ident['rate_key'])
            if rate is None:
                continue  # 费率未配置，跳过该身份

            # 计算所需抵扣金额： target_price / (1 - rate) ，向上取整到分
            try:
                if rate >= 1:
                    continue  # 防止除零及不合理费率
                required = target_price / (decimal.Decimal('1.0') - rate)
                # 向上取整到分（保留两位小数，最后一位进位）
                required = required.quantize(decimal.Decimal('0.01'), rounding=decimal.ROUND_CEILING)
            except Exception:
                continue  # 计算异常，跳过

            # 余额是否足够
            if balance >= required:
                available_list.append({
                    'id': ident['id'],
                    'jieshao': ident['name'],
                    'xuyao': str(required),
                })

        return Response({
            'code': 200,
            'msg': 'success',
            'data': available_list
        })

from decimal import Decimal, ROUND_CEILING
# ========== 修改点1: 导入最新的分红处理方法 ==========
from yonghu.fadan_fenhong_utils import process_fadan_fenhong

INTEGRAL_INCREMENT = 5
MAX_INTEGRAL = 10

IDENTITY_CONFIG = {
    1: {
        'name': '打手佣金',
        'model': UserDashou,
        'balance_field': 'yue',
        'status_field': 'zhanghaozhuangtai',
        'rate_key': '5',
    },
    2: {
        'name': '管事分红',
        'model': UserGuanshi,
        'balance_field': 'yue',
        'status_field': 'zhuangtai',
        'rate_key': '6',
    },
    3: {
        'name': '组长分红',
        'model': UserZuzhang,
        'balance_field': 'ketixian_jine',
        'status_field': 'zhuangtai',
        'rate_key': '8',
    },
    4: {
        'name': '打手押金',
        'model': UserDashou,
        'balance_field': 'yajin',
        'status_field': 'zhanghaozhuangtai',
        'rate_key': '11',
    },
}


class DsqrgmdhView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        try:
            leixing = request.data.get('leixing')
            shenfen_id = request.data.get('shenfen_id')
            huiyuan_id = request.data.get('huiyuan_id')
            yajin_jine = request.data.get('yajin_jine')
            fadan_id = request.data.get('fadan_id')

            logger.info(f"抵扣支付请求: leixing={leixing}, shenfen_id={shenfen_id}, huiyuan_id={huiyuan_id}, yajin_jine={yajin_jine}, fadan_id={fadan_id}")

            if leixing not in [1, 2, 3, 4]:
                return Response({'code': 400, 'msg': 'leixing 必须为 1/2/3/4'}, status=status.HTTP_400_BAD_REQUEST)
            if shenfen_id not in [1, 2, 3, 4]:
                return Response({'code': 400, 'msg': 'shenfen_id 必须为 1/2/3/4'}, status=status.HTTP_400_BAD_REQUEST)

            if leixing == 1 and not huiyuan_id:
                return Response({'code': 400, 'msg': '购买会员时必须提供 huiyuan_id'}, status=status.HTTP_400_BAD_REQUEST)
            if leixing == 2:
                if not yajin_jine:
                    return Response({'code': 400, 'msg': '购买押金时必须提供 yajin_jine'}, status=status.HTTP_400_BAD_REQUEST)
                try:
                    yajin_jine = Decimal(str(yajin_jine))
                    if yajin_jine <= 0:
                        raise ValueError
                    if yajin_jine > Decimal('10000'):
                        return Response({'code': 400, 'msg': '押金金额不能超过10000元'}, status=status.HTTP_400_BAD_REQUEST)
                except:
                    return Response({'code': 400, 'msg': 'yajin_jine 必须为正数'}, status=status.HTTP_400_BAD_REQUEST)

            target_price = None
            if leixing == 1:
                try:
                    huiyuan = Huiyuan.objects.get(huiyuan_id=huiyuan_id)
                    target_price = huiyuan.jiage
                except Huiyuan.DoesNotExist:
                    return Response({'code': 404, 'msg': '会员不存在'}, status=status.HTTP_404_NOT_FOUND)
            elif leixing == 2:
                target_price = yajin_jine
            elif leixing == 3:
                target_price = INTEGRAL_PRICE
            elif leixing == 4:
                if not fadan_id:
                    return Response({'code': 400, 'msg': '缺少罚单ID'}, status=status.HTTP_400_BAD_REQUEST)
                try:
                    fadan_obj = Fadan.objects.get(id=fadan_id, beichufa_id=request.user.yonghuid)
                    target_price = fadan_obj.fakuanjine
                except Fadan.DoesNotExist:
                    return Response({'code': 404, 'msg': '罚单不存在或不属于当前用户'}, status=status.HTTP_404_NOT_FOUND)

            identity = IDENTITY_CONFIG.get(shenfen_id)
            try:
                rate_obj = Lilubiao.objects.get(fadanpingtai=identity['rate_key'])
                rate = rate_obj.lilu
                if rate >= 1:
                    return Response({'code': 400, 'msg': f"{identity['name']}费率异常"}, status=status.HTTP_400_BAD_REQUEST)
            except Lilubiao.DoesNotExist:
                return Response({'code': 400, 'msg': f"{identity['name']}费率未配置"}, status=status.HTTP_400_BAD_REQUEST)

            logger.info(f"目标价格={target_price}, 费率={rate}")

            try:
                required = target_price / (Decimal('1.0') - rate)
                required = required.quantize(Decimal('0.01'), rounding=ROUND_CEILING)
                logger.info(f"所需抵扣金额={required}")
            except Exception as e:
                logger.error(f"金额计算错误: {str(e)}", exc_info=True)
                return Response({'code': 500, 'msg': f'金额计算错误: {str(e)}'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

            user = request.user
            yonghuid = user.yonghuid

            try:
                profile = identity['model'].objects.get(user=user)
            except identity['model'].DoesNotExist:
                return Response({'code': 403, 'msg': f'您不是{identity["name"]}身份'})

            status_value = getattr(profile, identity['status_field'])
            if status_value != 1:
                return Response({'code': 403, 'msg': f'{identity["name"]}账号状态异常，无法使用'})

            balance = getattr(profile, identity['balance_field'])
            if balance < required:
                return Response({'code': 400, 'msg': f'{identity["name"]}余额不足，需要{required}元，当前{balance}元'}, status=status.HTTP_400_BAD_REQUEST)

            try:
                with transaction.atomic():
                    locked_profile = identity['model'].objects.select_for_update().get(id=profile.id)
                    current_balance = getattr(locked_profile, identity['balance_field'])
                    if current_balance < required:
                        raise ValueError(f"{identity['name']}余额不足，需要{required}元，当前{current_balance}元")

                    setattr(locked_profile, identity['balance_field'], current_balance - required)
                    locked_profile.save(update_fields=[identity['balance_field']])
                    logger.info(f"扣款成功: {identity['name']} 扣除 {required} 元，剩余 {current_balance - required} 元")

                    timestamp = str(int(time.time() * 1000))[-12:]
                    rand_str = ''.join(random.choices(string.ascii_uppercase + string.digits, k=4))
                    dingdan_id = f"CZ{timestamp}{rand_str}"

                    if leixing == 1:
                        action_desc = f"购买会员 {huiyuan.jieshao}"
                    elif leixing == 2:
                        action_desc = f"充值押金 {yajin_jine}元"
                    elif leixing == 3:
                        action_desc = "补充积分"
                    elif leixing == 4:
                        action_desc = f"缴纳罚款 {target_price}元"

                    shuoming = f"{identity['name']}抵扣 {action_desc}，抵扣金额{required}元"

                    czjilu = Czjilu.objects.create(
                        dingdan_id=dingdan_id,
                        huiyuan_id=huiyuan_id if leixing == 1 else None,
                        zhuangtai=1,
                        yonghuid=yonghuid,
                        jine=required,
                        leixing=leixing,
                        shuoming=shuoming,
                    )

                    response_data = {}

                    if leixing == 1:
                        huiyuan_record, is_first_buy = self._process_member_purchase(yonghuid, huiyuan_id, huiyuan)
                        response_data['huiyuan'] = {
                            'huiyuanid': huiyuan_id,
                            'huiyuanming': huiyuan.jieshao,
                            'daoqi': huiyuan_record.daoqi_time.strftime('%Y-%m-%d %H:%M:%S') if hasattr(huiyuan_record, 'daoqi_time') else '',
                        }
                        if is_first_buy:
                            try:
                                dashou = UserDashou.objects.get(user=user)
                                dashou.jifen += 10
                                dashou.save(update_fields=['jifen'])
                                response_data['jifen'] = dashou.jifen
                            except UserDashou.DoesNotExist:
                                pass

                    elif leixing == 2:
                        try:
                            dashou = UserDashou.objects.select_for_update().get(user=user)
                            dashou.yajin += yajin_jine
                            dashou.save(update_fields=['yajin'])
                            response_data['yajin'] = dashou.yajin
                        except UserDashou.DoesNotExist:
                            return Response({'code': 500, 'msg': '打手信息不存在，无法充值押金'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

                    elif leixing == 4:
                        if fadan_obj.zhuangtai not in [1, 3]:
                            return Response({'code': 400, 'msg': '罚单状态不可缴纳'}, status=status.HTTP_400_BAD_REQUEST)
                        fadan_obj.zhuangtai = 2
                        fadan_obj.save(update_fields=['zhuangtai'])
                        response_data['fadan_id'] = fadan_obj.id
                        response_data['fadan_status'] = fadan_obj.zhuangtai

                        # ========== 修改点2: 使用最新的分红处理方法 ==========
                        success, msg = process_fadan_fenhong(fadan_obj.id)
                        if not success:
                            logger.error(f"罚单 {fadan_obj.id} 分红处理失败: {msg}")
                        else:
                            logger.info(f"罚单 {fadan_obj.id} 分红处理成功: {msg}")

                    else:  # leixing == 3
                        try:
                            dashou = UserDashou.objects.select_for_update().get(user=user)
                            new_jifen = dashou.jifen + INTEGRAL_INCREMENT
                            dashou.jifen = min(new_jifen, MAX_INTEGRAL)
                            dashou.save(update_fields=['jifen'])
                            response_data['jifen'] = dashou.jifen
                        except UserDashou.DoesNotExist:
                            return Response({'code': 500, 'msg': '打手信息不存在，无法补充积分'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

            except Exception as e:
                logger.error(f"事务处理异常: {str(e)}", exc_info=True)
                return Response({'code': 500, 'msg': f'支付处理失败: {str(e)}'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

            final_profile = identity['model'].objects.get(user=user)
            response_data['balance'] = str(getattr(final_profile, identity['balance_field']))

            return Response({
                'code': 200,
                'msg': 'success',
                'data': response_data,
            })

        except Exception as e:
            logger.error(f"接口顶层异常: {str(e)}", exc_info=True)
            return Response({'code': 500, 'msg': f'系统错误: {str(e)}'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def _process_member_purchase(self, yonghuid, huiyuan_id, huiyuan_obj):
        is_first_buy_any = False
        try:
            record = Huiyuangoumai.objects.filter(
                yonghu_id=yonghuid,
                huiyuan_id=huiyuan_id
            ).first()

            if record:
                record.daoqi_time += timedelta(days=30)
                record.huiyuan_zhuangtai = 1
                record.save(update_fields=['daoqi_time', 'huiyuan_zhuangtai'])
            else:
                other_count = Huiyuangoumai.objects.filter(yonghu_id=yonghuid).exclude(huiyuan_id=huiyuan_id).count()
                if other_count == 0:
                    is_first_buy_any = True
                record = Huiyuangoumai.objects.create(
                    yonghu_id=yonghuid,
                    huiyuan_id=huiyuan_id,
                    jieshao=huiyuan_obj.jieshao,
                    huiyuan_zhuangtai=1,
                    daoqi_time=timezone.now() + timedelta(days=30)
                )
            return record, is_first_buy_any
        except Exception as e:
            if 'unique' in str(e).lower() or 'duplicate' in str(e).lower():
                record = Huiyuangoumai.objects.get(yonghu_id=yonghuid, huiyuan_id=huiyuan_id)
                return record, False
            raise