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

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

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

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

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

from orders.utils import (
    calc_shangjia_order_fencheng,
    update_daily_payout,
    settle_shangjia_order_guanshi_fenhong
)
from shop.utils import calculate_pingtai_and_dianpu_shouyi, validate_shangpin_and_dianpu, update_dianpu_daily_stat
from products.utils import update_shangpin_daily_stat
from backend.utils import update_shangjia_daily, update_dashou_daily_by_action, pick_leixing_id, datetime_aliases, fmt_datetime
from merchant_ops.constants import (
    ACTION_SETTLE, ACTION_CANCEL, ACTION_REFUND_APPLY, ACTION_DISPATCH, ACTION_PENALTY_APPLY,
)
from merchant_ops.services.action_log import (
    record_order_action_from_request, leixing_id_from_order,
)
from rank.services import record_dashou_biaoxian
from rank.utils import check_dashou_biaoqian_required

from orders.notice_tasks import dingdan_guangbo

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



logger = logging.getLogger(__name__)

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

    @staticmethod
    def _can_access(request):
        """商家老板、有效子客服（含代理调用）方可获取"""
        if getattr(request, '_staff_member', None) is not None:
            return True
        from merchant_ops.services.authz import (
            get_active_staff_member, is_merchant_owner, member_has_perm, staff_order_read_perm,
        )
        if is_merchant_owner(request.user):
            return True
        member = get_active_staff_member(request.user)
        return bool(member and staff_order_read_perm(member))

    def post(self, request):

        if not self._can_access(request):
            return Response({'code': 403, 'msg': '非商家或有效客服，无权获取订单类型', 'data': []})

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

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

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

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

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

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

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



class ShangjiaPaifaView(APIView):
    permission_classes = [IsAuthenticated]

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

        try:
            data = request.data

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

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

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

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

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

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

            # ----- 6. 押金 / 会员模式决定 -----
            final_yongjin = None
            if commission_enabled and commission_value_str:
                try:
                    cv = float(commission_value_str)
                    if cv > 0:
                        final_yaoqiu_type = 2
                        final_yongjin = Decimal(str(cv))
                        final_huiyuan_id = ''
                        logger.info(f"押金模式: 佣金={cv}")
                    else:
                        final_yaoqiu_type = shangpin_type.yaoqiuleixing or 1
                        final_huiyuan_id = str(huiyuan_id) if huiyuan_id else ''
                        logger.warning("佣金为0，降级为会员模式")
                except ValueError:
                    final_yaoqiu_type = shangpin_type.yaoqiuleixing or 1
                    final_huiyuan_id = str(huiyuan_id) if huiyuan_id else ''
                    logger.warning("佣金格式错误，降级为会员模式")
            else:
                final_yaoqiu_type = shangpin_type.yaoqiuleixing or 1
                final_huiyuan_id = str(huiyuan_id) if huiyuan_id else ''
                logger.info(f"会员模式: 类型={final_yaoqiu_type}")

            # ----- 7. 称号（可选：不传/空值/无效/不存在均视为无标签）-----
            chenghao_obj = None
            label_id_str = str(label_id).strip() if label_id is not None else ''
            if label_id_str and label_id_str not in ('0', 'null', 'undefined'):
                try:
                    lid = int(label_id_str)
                    if lid > 0:
                        chenghao_obj = Chenghao.query.filter(id=lid).first()
                        if chenghao_obj:
                            logger.info(f"订单将关联称号: {chenghao_obj.mingcheng}")
                        else:
                            logger.info(f"标签不存在，按无标签派单: {label_id}")
                except (ValueError, TypeError):
                    logger.info(f"标签ID无效，按无标签派单: {label_id}")

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

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

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

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

            # ----- 10. 利率（打手+管事分成，打手优先） -----
            club_id = resolve_club_id_from_request(request)
            dashou_fencheng, guanshi_fencheng = calc_shangjia_order_fencheng(jiage, club_id=club_id)

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

            # ----- 12. 事务：创建订单、更新商家统计 -----
            dingdan = None
            try:
                with transaction.atomic():
                    dingdan = Order.query.create(
                        OrderID=generate_dingdan_id(),
                        Status=7 if zhiding_dashou else 1,
                        Platform=2,
                        Amount=jiage,
                        PlayerCommission=dashou_fencheng,
                        ManagerCommission=guanshi_fencheng,
                        AssignedID=zhiding_uid if zhiding_dashou else '',
                        ProductID=0,
                        ProductTypeID=int(shangpin_type_id),
                        GrabRequirement=final_yaoqiu_type,
                        CommissionReq=final_yongjin,
                        MembershipID=final_huiyuan_id,
                        Description=dingdan_jieshao[:2000],
                        Remark=dingdan_beizhu[:1000],
                        Nickname=laoban_name[:50],
                        ImageURL=request.user.Avatar,
                        User1ID=f"Sj{request.user.UserUID}",
                        ClubID=club_id,
                        ExternalOrderID=waibu_dingdan_id or None,
                    )
                    logger.info(f"订单主表创建: {dingdan.OrderID}")

                    MerchantOrderExt.query.create(
                        Order=dingdan,
                        MerchantID=request.user.UserUID,
                        MerchantNickname=shangjia.nicheng,
                    )

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

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

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

            # ========== 以下操作均在事务外，避免异步任务查不到订单 ==========
            # Celery 广播任务（异步）
            try:
                order_info = {
                    'OrderID': dingdan.OrderID,
                    'game_type': self._get_game_type_name(dingdan.ProductTypeID),
                    'amount': str(dingdan.Amount),
                    'order_desc': (dingdan.Description or '')[:50],
                }
                dingdan_guangbo.delay(order_info)
                logger.info(f"已提交广播任务: {dingdan.OrderID}")
            except Exception as e:
                logger.error(f"广播任务提交失败: {e}", exc_info=True)

            logger.info(f"商家派单成功: {dingdan.OrderID}, 金额={jiage}")
            record_order_action_from_request(
                request,
                ACTION_DISPATCH,
                dingdan.OrderID,
                merchant_id=request.user.UserUID,
                amount=jiage,
                leixing_id=getattr(dingdan, 'ProductTypeID', None),
            )
            return Response({'code': 200, 'msg': '派单成功', 'data': {'jine': str(dingdan.Amount)}})

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

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

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

    permission_classes = [IsAuthenticated]

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

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

            # 商品类型 / 关键字 / 时间段等见 apply_merchant_order_list_filters
        except (ValueError, TypeError):
            return Response({
                'code': 2,
                'msg': '参数格式错误',
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)

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

        try:
            from orders.services.merchant_order_list_filters import apply_merchant_order_list_filters

            # 4. 构建基础查询（该商家的所有订单）
            base_qs = MerchantOrderExt.query.filter(
                MerchantID=yonghuid
            ).select_related('Order')

            filter_payload = dict(data)
            filter_payload['_merchant_id_filter'] = yonghuid

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

            # 6–7. 类型 / 关键字 / 时间段 / 客服筛选
            base_qs = apply_merchant_order_list_filters(base_qs, filter_payload)

            # 8. 待结算统计（全量聚合，非分页求和）
            from orders.services.merchant_order_stats import (
                build_merchant_order_stats, merchant_ext_qs, filter_by_staff_member,
            )
            stats_qs = merchant_ext_qs(yonghuid)
            stats_qs = apply_merchant_order_list_filters(stats_qs, filter_payload)
            order_stats = build_merchant_order_stats(stats_qs)

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

            from jituan.services.club_context import resolve_club_id_from_request
            from orders.services.merchant_order_list_enrich import enrich_merchant_order_list_items

            club_id = resolve_club_id_from_request(request)
            order_list = enrich_merchant_order_list_items(current_page_orders, club_id=club_id)

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

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

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


class ShangjiaShujuTongjiView(APIView):
    """
    商家经营数据统计（订单表聚合）
    POST /dingdan/sjshujutj
  """
    permission_classes = [IsAuthenticated]

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

        try:
            shangjia = current_user.ShopProfile
            if shangjia.zhuangtai != 1:
                return Response({'code': 403, 'msg': '商家状态异常', 'data': None}, status=403)
        except Exception:
            return Response({'code': 403, 'msg': '非商家用户', 'data': None}, status=403)

        data = request.data or {}
        from orders.services.merchant_order_list_filters import apply_merchant_order_list_filters
        from orders.services.merchant_order_stats import merchant_ext_qs, build_merchant_order_stats

        filter_payload = dict(data)
        filter_payload['_merchant_id_filter'] = yonghuid
        qs = merchant_ext_qs(yonghuid)
        qs = apply_merchant_order_list_filters(qs, filter_payload)
        order_stats = build_merchant_order_stats(qs)

        penalty_stats = None
        try:
            from orders.models import Penalty, PenaltyRecord
            from django.db.models import Q, Sum, Count
            _fakuan_agg = Penalty.query.filter(ApplicantID=yonghuid, Status__in=[1, 3]).aggregate(
                count=Count('id'),
                amt=Sum('FineAmount'),
            )
            fakuan_pending = _fakuan_agg['count']
            fakuan_pending_amt = _fakuan_agg['amt']
            jifen_pending = PenaltyRecord.query.filter(
                ApplicantID=yonghuid,
            ).filter(Q(ApplyStatus=0) | Q(ApplyStatus=3)).count()
            penalty_stats = {
                'fakuan_pending': fakuan_pending,
                'fakuan_pending_amount': str(fakuan_pending_amt or '0.00'),
                'jifen_pending': jifen_pending,
            }
        except Exception:
            penalty_stats = {
                'fakuan_pending': 0,
                'fakuan_pending_amount': '0.00',
                'jifen_pending': 0,
            }

        return Response({
            'code': 0,
            'msg': '成功',
            'data': {
                'order': order_stats,
                'penalty': penalty_stats,
                'can_view_finance': True,
            },
        })




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

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

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

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

        try:
            # 3. 查询商家订单扩展表，验证权限并获取基础订单数据
            shangjia_kuozhan = MerchantOrderExt.query.filter(
                MerchantID=yonghuid,
                Order__OrderID=dingdan_id
            ).select_related('Order').first()

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

            order = shangjia_kuozhan.Order

            # 4. 交付图片列表
            dashou_tupian_list = PlayerDeliveryImage.query.filter(
                OrderID=dingdan_id
            ).order_by('CreateTime').values_list('ImageURL', flat=True)
            dashou_jiaofu = list(dashou_tupian_list)

            # 5. 打手详细信息（头像、昵称、用户ID）
            dashou_yonghuid = order.PlayerID or ''
            dashou_nicheng = ''
            dashou_avatar = ''
            if dashou_yonghuid:
                dashou_user = User.query.filter(
                    UserUID=dashou_yonghuid
                ).select_related('DashouProfile').first()
                if dashou_user:
                    dashou_avatar = dashou_user.Avatar or ''
                    if hasattr(dashou_user, 'DashouProfile') and dashou_user.DashouProfile:
                        dashou_nicheng = dashou_user.DashouProfile.nicheng or ''

            # 6. 罚款数据（组队均摊：聚合全部罚单；展示总额+明细）
            from orders.services.team_recruit import list_team_split_penalties
            split_list = list_team_split_penalties(dingdan_id, include_rejected=True)
            fadan_qs = Penalty.query.filter(RelatedOrderID=dingdan_id).order_by('id')
            if split_list:
                fadan_list = split_list
            else:
                fadan_list = list(
                    fadan_qs.filter(PenalizedUserID=dashou_yonghuid)[:1]
                ) or list(fadan_qs[:1])
            fadan_obj = fadan_list[0] if fadan_list else None
            fadan_dict = None
            fadan_items = []
            if fadan_list:
                total_fine = 0.0
                total_bonus = 0.0
                rate = 0.0
                for p in fadan_list:
                    total_fine += float(p.FineAmount or 0)
                    total_bonus += float(p.ApplicantBonusAmount or 0)
                    if p.ApplicantBonusRate:
                        rate = float(p.ApplicantBonusRate)
                    fadan_items.append({
                        'id': p.id,
                        'beichufa_id': p.PenalizedUserID or '',
                        'fakuanjine': float(p.FineAmount or 0),
                        'zhuangtai': p.Status,
                        'yingde_fenhong': float(p.ApplicantBonusAmount or 0),
                    })
                ct = fmt_datetime(fadan_obj.CreateTime)
                ut = fmt_datetime(fadan_obj.UpdateTime)
                zhengju_imgs = [
                    {'id': t.id, 'url': t.ImageURL}
                    for t in PenaltyAppealImage.query.filter(Penalty=fadan_obj, Purpose=1)
                ]
                shensu_imgs = [
                    {'id': t.id, 'url': t.ImageURL}
                    for t in PenaltyAppealImage.query.filter(Penalty=fadan_obj, Purpose=2)
                ]
                reason = (fadan_obj.Reason or '').replace('【组队均摊】', '', 1)
                fadan_dict = {
                    'id': fadan_obj.id,
                    'chufaliyou': reason,
                    'fakuanjine': total_fine,
                    'yingxiang_qiangdan': fadan_obj.AffectsGrabbing,
                    'zhuangtai': fadan_obj.Status,
                    'shensuliyou': fadan_obj.AppealReason or '',
                    'tongyi_chufaliyou': fadan_obj.ApproveReason or '',
                    'bohuiliyou': fadan_obj.RejectReason or '',
                    'yingde_fenhong': total_bonus,
                    'fenhong_lilv': rate,
                    'fenhong_yiruzhang': all(bool(p.BonusCredited) for p in fadan_list),
                    'zhengju_tupian': zhengju_imgs,
                    'shensu_tupian': shensu_imgs,
                    'is_team_split': len(fadan_list) > 1 or (fadan_obj.Reason or '').startswith('【组队均摊】'),
                    'items': fadan_items,
                    'CreateTime': ct,
                    'create_time': ct,
                    'UpdateTime': ut,
                    'update_time': ut,
                }

            # 7. 商家分红利率：已有罚单用锁定值；否则按商家所在俱乐部预览
            fenhong_lilv = 0.0
            try:
                if fadan_obj and fadan_obj.ApplicantBonusRate:
                    fenhong_lilv = float(fadan_obj.ApplicantBonusRate)
                else:
                    from users.fadan_fenhong_utils import get_merchant_fenhong_lilv
                    from jituan.services.club_write import resolve_club_id_for_write
                    merchant_club_id = resolve_club_id_for_write(request, current_user)
                    fenhong_lilv = get_merchant_fenhong_lilv(yonghuid, club_id=merchant_club_id)
            except Exception as e:
                logger.warning(f'获取分红利率失败: {e}')

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

            # 9. 构建返回数据
            response_data = {
                # 基础订单字段
                'dingdan_id': order.OrderID,
                'zhuangtai': order.Status or 0,
                'jine': float(order.Amount) if order.Amount else 0.0,
                'jieshao': order.Description or '',
                'beizhu': order.Remark or '',
                'nicheng': order.Nickname or '',
                **datetime_aliases(order.CreateTime),

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

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

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

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

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

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

                # 拼多多订单号（商家/客服可见）
                'waibu_dingdan_id': order.ExternalOrderID or '',
                'laoban_shouji': getattr(shangjia_kuozhan, 'BossPhone', '') or '',
            }

            try:
                response_data['tuikuan_tupian'] = list(
                    RefundEvidenceImage.query.filter(OrderID=dingdan_id)
                    .exclude(ImageURL__isnull=True)
                    .exclude(ImageURL='')
                    .values_list('ImageURL', flat=True)
                )
            except Exception:
                response_data['tuikuan_tupian'] = []

            try:
                from jituan.services.order_deal import order_auto_settle_payload
                response_data.update(order_auto_settle_payload(order))
            except Exception as e:
                logger.warning('自动结算展示字段附加失败: %s', e)

            try:
                from merchant_ops.services.order_enrich import enrich_order_detail_data
                enrich_order_detail_data(response_data, dingdan_id)
            except Exception as e:
                logger.warning(f'派单客服信息附加失败: {e}')

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

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



class ShangjiaJiesuanView(APIView):
    """商家结单接口"""
    permission_classes = [permissions.IsAuthenticated]

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

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

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

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

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

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

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

                # 验证订单是否属于当前商家
                shangjia_kuozhan = MerchantOrderExt.query.filter(
                    Order=order,
                    MerchantID=yonghuid
                ).first()

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

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

                # 获取订单字段
                jine = order.Amount or Decimal('0')
                dashou_fencheng = order.PlayerCommission or Decimal('0')
                jiedan_dashou_id = order.PlayerID

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

                # ========== 本地订单正常结算给打手 ==========
                # 查询打手信息
                try:
                    dashou_user = User.query.get(UserUID=jiedan_dashou_id)
                    dashou = dashou_user.DashouProfile
                except (User.DoesNotExist, UserDashou.DoesNotExist):
                    return Response({
                        'code': 8,
                        'msg': '接单打手不存在或信息不完整',
                        'data': None
                    }, status=status.HTTP_400_BAD_REQUEST)

                # 原子更新打手数据（可提现走冻结网关；未开启时与原先全额进 yue 一致）
                from jituan.services.fund_freeze import credit_dashou_order_settle
                from orders.services.team_recruit import settle_team_or_legacy, get_active_recruit, lock_recruit
                from orders.models import TeamRecruit, TeamSettleLedger
                team_done = False
                try:
                    rec = get_active_recruit(order.OrderID)
                    if rec and rec.status == TeamRecruit.STATUS_RECRUITING:
                        lock_recruit(rec.id, actor_uid='system', reason='merchant_settle_force_lock')
                    team_done = settle_team_or_legacy(order, set_idle_leader=True)
                except Exception as e:
                    logger.error('商家结单组队分账失败 %s: %s', dingdan_id, e)
                    if TeamSettleLedger.query.filter(order_id=dingdan_id).exists() or get_active_recruit(dingdan_id):
                        return Response({
                            'code': 8,
                            'msg': f'组队分账失败，已阻止全额打给队长: {e}',
                            'data': None
                        }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
                if not team_done:
                    if get_active_recruit(order.OrderID):
                        return Response({
                            'code': 8,
                            'msg': '存在有效组队但分账未完成，已阻止全额打给队长',
                            'data': None
                        }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
                    credit_dashou_order_settle(
                        order=order,
                        dashou_profile=dashou,
                        user_id=jiedan_dashou_id,
                        amount=dashou_fencheng,
                    )

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

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

                # 处理评分（所有情况都处理）
                if pingfen > 0:
                    pingfen_obj, created = PlayerRating.query.get_or_create(
                        PlayerID=jiedan_dashou_id,
                        defaults={'TotalScore': pingfen, 'RatingCount': 1}
                    )
                    if not created:
                        PlayerRating.query.filter(id=pingfen_obj.id).update(
                            TotalScore=F('TotalScore') + pingfen,
                            RatingCount=F('RatingCount') + 1,
                        )

                # 更新商家订单扩展表的评价
                MerchantOrderExt.query.filter(id=shangjia_kuozhan.id).update(
                    MerchantReview=liuyan,
                )

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

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

                # 商家订单管事分红（仅 Platform=2）
                if order.Platform == 2:
                    settle_shangjia_order_guanshi_fenhong(order, jiedan_dashou_id)

                record_order_action_from_request(
                    request,
                    ACTION_SETTLE,
                    dingdan_id,
                    merchant_id=yonghuid,
                    amount=jine,
                    leixing_id=leixing_id_from_order(order),
                )

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

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




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

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

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

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

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

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

                # 6. 验证订单状态（13=链接待填单，可撤销释放额度）
                if dingdan.Status not in [1, 7, 13]:
                    return Response({
                        'code': 6,
                        'msg': '当前订单状态不可撤销',
                        'data': None
                    }, status=status.HTTP_400_BAD_REQUEST)

                # 7. 验证订单所属商家（使用反向查询）
                shangjia_kuozhan = MerchantOrderExt.query.filter(
                    Order__OrderID=dingdan_id,
                    MerchantID=current_user.UserUID
                ).first()

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

                # 8. 创建退款记录（注意：申请状态直接设为1-成功）
                RefundRecord.query.create(
                    OrderID=dingdan_id,
                    ApplicantID=current_user.UserUID,
                    Reason=chexiao_liyou,
                    ApplyStatus=1,  # 直接成功
                    Amount=dingdan.Amount,
                    PlayerCommission=dingdan.PlayerCommission,
                    Description=dingdan.Description,
                    Remark=dingdan.Remark,
                    Nickname=dingdan.Nickname,

                )

                # 9. 更新商家扩展表（客服额度单不退商家余额，只释放额度）
                from merchant_ops.services.wallet import is_staff_quota_order
                staff_quota_order = is_staff_quota_order(dingdan_id)
                shangjia_updates = {
                    'tuikuan': F('tuikuan') + 1,
                    'jinridingdan': F('jinridingdan') - 1,
                    'jinyuedingdan': F('jinyuedingdan') - 1,
                    'jinriliushui': F('jinriliushui') - dingdan.Amount,
                    'jinyueliushui': F('jinyueliushui') - dingdan.Amount,
                }
                if not staff_quota_order:
                    shangjia_updates['yue'] = F('yue') + dingdan.Amount
                UserShangjia.query.filter(id=shangjia.id).update(**shangjia_updates)

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

                dingdan.save()

                # 行为驱动
                update_shangjia_daily(
                    yonghuid=request.user.UserUID,
                    amount=Decimal(str(dingdan.Amount)),
                    action=3,  # 3 = 退款
                    order_id=dingdan_id,
                )

                record_order_action_from_request(
                    request,
                    ACTION_CANCEL,
                    dingdan_id,
                    merchant_id=request.user.UserUID,
                    amount=dingdan.Amount,
                    leixing_id=leixing_id_from_order(dingdan),
                    remark=chexiao_liyou[:200] if chexiao_liyou else '',
                )

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

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

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


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

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

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

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

        if not isinstance(tuikuan_tupian_urls, list):
            tuikuan_tupian_urls = []
        valid_urls = [str(u).strip() for u in tuikuan_tupian_urls if u and str(u).strip()]

        # 4. 参数验证（文字 + 至少1张证据图）
        if not dingdan_id or not tuikuan_liyou:
            return Response({
                'code': 4,
                'msg': '订单ID和退款原因不能为空',
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)
        if not valid_urls:
            return Response({
                'code': 4,
                'msg': '请至少上传1张退款相关图片',
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)
        if len(valid_urls) > 9:
            return Response({
                'code': 4,
                'msg': '退款图片最多9张',
                'data': None
            }, status=status.HTTP_400_BAD_REQUEST)

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

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

                # 7. 验证订单所属商家
                shangjia_kuozhan = MerchantOrderExt.query.filter(
                    Order__OrderID=dingdan_id,
                    MerchantID=current_user.UserUID
                ).first()

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

                # ========== 8. 处理退款记录（修改点：先查询是否存在） ==========
                refund_record, created = RefundRecord.query.get_or_create(
                    OrderID=dingdan_id,
                    defaults={
                        'PlayerID': dingdan.PlayerID,
                        'ApplicantID': current_user.UserUID,
                        'Reason': tuikuan_liyou,
                        'ApplyStatus': 0,  # 待处理
                        'Amount': dingdan.Amount,
                        'PlayerCommission': dingdan.PlayerCommission,
                        'Description': dingdan.Description,
                        'Remark': dingdan.Remark,
                        'Nickname': dingdan.Nickname,
                    }
                )
                if not created:
                    # 记录已存在，更新退款理由和申请时间
                    refund_record.Reason = tuikuan_liyou
                    refund_record.save(update_fields=['Reason', 'UpdateTime'])
                    logger.info(f"订单 {dingdan_id} 已有退款记录，已更新退款理由")

                # 8b. 退款证据图：覆盖写入（重新申请时替换旧图）
                RefundEvidenceImage.query.filter(OrderID=dingdan_id).delete()
                RefundEvidenceImage.objects.bulk_create([
                    RefundEvidenceImage(
                        OrderID=dingdan_id,
                        UserID=current_user.UserUID,
                        ImageURL=url,
                    )
                    for url in valid_urls
                ])

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

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

                record_order_action_from_request(
                    request,
                    ACTION_REFUND_APPLY,
                    dingdan_id,
                    merchant_id=current_user.UserUID,
                    amount=dingdan.Amount,
                    leixing_id=leixing_id_from_order(dingdan),
                    remark=tuikuan_liyou[:200] if tuikuan_liyou else '',
                )

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

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


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

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

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

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

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

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

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

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

                # 验证订单所属商家
                shangjia_kuozhan = MerchantOrderExt.query.filter(
                    Order__OrderID=dingdan_id,
                    MerchantID=current_user.UserUID
                ).first()

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

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

                # 创建处罚记录
                chufajilu = PenaltyRecord.query.create(
                    PlayerID=dashou_id,
                    ApplicantID=current_user.UserUID,
                    PenaltyReason=chufa_liyou,
                    ApplyStatus=0,  # 待处理
                    DeductedPoints=5,  # 扣除5积分
                    OrderID=dingdan_id,
                    ClubID=resolve_penalty_record_club_id(
                        order_id=dingdan_id,
                        player_id=dashou_id,
                        request=request,
                        applicant_id=current_user.UserUID,
                        user=current_user,
                    ),
                )
                # 🔴【新增】在创建处罚记录后立即扣除打手积分
                # 注意：这里使用前面已经获取的dashou对象（打手扩展表）
                jifen_kouchu = chufajilu.DeductedPoints  # 扣除的积分，这里是5
                if jifen_kouchu > 0:
                    # 检查打手积分是否足够（UserDashou 字段为 jifen）
                    if dashou.jifen < jifen_kouchu:
                        dashou.jifen = 0
                    else:
                        dashou.jifen -= jifen_kouchu
                    dashou.save()

                # 🔴【新增】保存处罚图片到数据库
                if chufa_tupian_urls and isinstance(chufa_tupian_urls, list):
                    _valid_urls = [u.strip() for u in chufa_tupian_urls if u and u.strip()]
                    if _valid_urls:
                        PenaltyEvidenceImage.objects.bulk_create([
                            PenaltyEvidenceImage(
                                OrderID=dingdan_id,
                                UserID=current_user.UserUID,
                                ImageURL=url,
                            )
                            for url in _valid_urls
                        ])

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

                record_order_action_from_request(
                    request,
                    ACTION_PENALTY_APPLY,
                    dingdan_id,
                    merchant_id=current_user.UserUID,
                    amount=None,
                    leixing_id=leixing_id_from_order(
                        Order.query.filter(OrderID=dingdan_id).first()
                    ),
                    remark=(chufa_liyou or '')[:200],
                )

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

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

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





