"""users.views.kefu_orders - auto-generated by split script."""
"""users.views.kefu - auto-generated by split script."""
import os
import sys
import json
import re
import time
import uuid
import random
import string
import requests
import hashlib
import traceback
import decimal
import jwt
import ipaddress
import xmltodict
from datetime import datetime, timedelta
from decimal import Decimal
import defusedxml.ElementTree as ET

from django.conf import settings
from django.db import models, transaction, IntegrityError, DatabaseError, connection
from django.db.models import Q, F, Sum, Count, Case, When, IntegerField, Prefetch
from django.core.cache import cache
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.core.exceptions import ObjectDoesNotExist
from django.shortcuts import get_object_or_404
from django.utils import timezone
from django.http import HttpResponse
from django.views import View
from django.views.decorators.csrf import csrf_exempt
from django.contrib.auth.hashers import make_password

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 MultiPartParser, FormParser, JSONParser
from rest_framework.throttling import AnonRateThrottle
from rest_framework_simplejwt.tokens import RefreshToken
from rest_framework_simplejwt.authentication import JWTAuthentication

from gvsdsdk.fluent import db, func, FQ

from utils.oss_utils import validate_image, upload_to_oss, delete_from_oss
from utils.money import yuan_to_fen
from utils.fadan_utils import check_fadan_qiangdan_eligible
from utils.invitationcode_utils import CreateInvitationCode, VerifyInvitationCode
from users.fadan_fenhong_utils import process_fadan_fenhong

from orders.utils import (
    update_daily_payout,
    settle_shangjia_order_guanshi_fenhong
)
from backend.utils import (
    update_dashou_daily_by_action, update_guanshi_daily_by_action,
    update_shangjia_daily, update_zuzhang_daily_by_action,
    verify_kefu_permission, has_perm_code, has_merchant_order_permission,
    has_platform_order_permission,
)
from jituan.services.admin_context import is_kefu_backend_account, is_system_super_admin
from rank.utils import get_tag_fee, create_shenhe_jilu, validate_shenheguan

from ..models import (
    UserBoss, UserDashou, UserShangjia, UserGuanshi,
    UserZuzhang, UserKefu, AdminProfile, OfficialAccountUser,
    TixianAutoRecord, TixianShenheJilu, Tixianjilu, Xiugaijilu,
    RankingRecord
)
from users.business_models import User
from ..tixian_shenhe_services import (
    load_audit_meta_map, refund_balance, sync_audit_and_jilu_status,
    mark_transfer_success, release_collect_quota_for_record,
    close_audit_wechat_failed, query_wechat_transfer_bill,
    check_shijidaozhang_within_limit,
    check_dashou_trial_blocks_commission_withdraw,
    WX_STATE_FAIL, WX_STATE_SUCCESS, WX_STATE_WAIT, WX_STATE_CANCELING,
)
from ..tixian_shenhe_views import process_audit_collect

from orders.models import (
    Order, PlatformOrderExt, MerchantOrderExt, CommissionRate,
    PenaltyRecord, PenaltyEvidenceImage, RefundRecord, PlayerDeliveryImage,
    Penalty, PenaltyAppealImage
)
from products.models import (
    ShangpinLeixing, Huiyuan, Huiyuangoumai, Gsfenhong, Czjilu
)
from config.models import Qunpeizhi
from backend.models import MerchantDailyStats
from rank.models import (
    KaohePayTemp, Chenghao, ShenheJilu,
    KaoheCishuFeiyong, YonghuChenghao
)
from users.models import UserShenheguan
from products.utils import update_shangpin_daily_stat
from shop.utils import update_dianpu_daily_stat
from rank.utils import create_shenhe_jilu_from_temp

import logging

logger = logging.getLogger(__name__)


def _club_label_map(club_ids):
    """club_id -> 展示名"""
    ids = [c for c in set(club_ids or []) if c]
    if not ids:
        return {}
    try:
        from jituan.models import Club
        return {
            c.club_id: (c.name or c.club_id)
            for c in Club.objects.filter(club_id__in=ids)
        }
    except Exception:
        return {cid: cid for cid in ids}


def _attach_order_club_fields(item, order, name_map=None):
    cid = (getattr(order, 'ClubID', None) or '').strip()
    item['club_id'] = cid
    item['club_name'] = (name_map or {}).get(cid) or cid or ''
    return item



class KefuGetOrderListView(APIView):
    """
    客服获取平台订单列表接口（发单平台=1，非跨平台）
    需要权限：002ab（平台订单管理）
    请求参数：
        username: 客服账号（用于权限校验）
        page: 页码
        pageSize: 每页条数
        dingdan_id: 订单ID（精确搜索）
        laoban_id: 老板ID（搜索平台扩展表中的老板）
        dashou_id: 打手ID（搜索主表中的接单打手）
        leixing: 商品类型ID
        zhuangtai: 状态（多个用逗号分隔，如 "1,7"）
        date: 日期（YYYY-MM-DD），筛选订单创建时间
        nicheng: 游戏昵称（订单主表的 nicheng 字段）
        jieshao: 订单介绍（订单主表的 jieshao 字段）
        clkf: 处理客服（订单主表的 clkf 字段）
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        start_total = time.time()

        # 1. 获取前端参数
        username = request.data.get('phone', '').strip()
        if not username:
            return Response({'code': 400, 'msg': '缺少username'})

        # 2. 公共权限校验
        kefu, permissions = verify_kefu_permission(request, None)
        if kefu is None:
            return permissions

        if not has_platform_order_permission(permissions):
            return Response({'code': 403, 'msg': '您无权查看平台订单列表（需要 002ab 或本店超级管理 000001）'})

        # 4. 获取分页和筛选参数
        page = int(request.data.get('page', 1))
        page_size = int(request.data.get('pageSize', 20))

        dingdan_id = request.data.get('dingdan_id', '').strip()
        laoban_id = request.data.get('laoban_id', '').strip()
        dashou_id = request.data.get('dashou_id', '').strip()
        leixing = request.data.get('leixing')
        zhuangtai = request.data.get('zhuangtai', '')
        date = request.data.get('date', '').strip()
        # 新增筛选条件
        nicheng = request.data.get('nicheng', '').strip()
        jieshao = request.data.get('jieshao', '').strip()
        clkf = request.data.get('clkf', '').strip()

        # ---------- 查询条件 ----------
        # 基础条件：平台发单 + 兼容历史 Platform 为空
        from jituan.services.club_context import platform_order_base_q
        base_q = platform_order_base_q()

        if dingdan_id:
            q_conditions = base_q & Q(OrderID=dingdan_id)
        else:
            q_conditions = base_q
            if leixing is not None and str(leixing).strip() != '':
                try:
                    leixing_int = int(leixing)
                    q_conditions &= Q(ProductTypeID=leixing_int)
                except (ValueError, TypeError):
                    pass
            if zhuangtai and zhuangtai != 'all':
                try:
                    status_list = [int(s.strip()) for s in zhuangtai.split(',') if s.strip()]
                    if status_list:
                        q_conditions &= Q(Status__in=status_list)
                except (ValueError, TypeError):
                    pass
            if dashou_id:
                q_conditions &= Q(PlayerID=dashou_id)
            if laoban_id:
                q_conditions &= Q(pingtai_kuozhan__BossID=laoban_id)
            if date:
                q_conditions &= Q(CreateTime__date=date)
            # 新增筛选条件
            if nicheng:
                q_conditions &= Q(Nickname__icontains=nicheng)
            if jieshao:
                q_conditions &= Q(Description__icontains=jieshao)
            if clkf:
                q_conditions &= Q(AssignedCS__icontains=clkf)

            from orders.services.merchant_order_list_filters import wants_auto_settle_pending
            if wants_auto_settle_pending(request.data):
                q_conditions &= Q(Status=8, AutoSettleEligible=True, AutoExpireAt__isnull=False)

        from jituan.services.club_context import (
            count_order_status_buckets,
            order_scope_qs,
            paginate_fluent_query,
        )
        from orders.models import PlatformOrderExt

        # 按俱乐部过滤订单列表
        stats_qs = order_scope_qs(request).filter(q_conditions)
        stats = stats_qs.aggregate(
            total_orders=Count('id'),
            completed_orders=Count('id', filter=Q(Status=3)),
            refund_orders=Count('id', filter=Q(Status=5)),
            pending_orders=Count('id', filter=Q(Status__in=[4, 8]))
        )
        status_counts = count_order_status_buckets(q_conditions, request)

        list_qs = order_scope_qs(request).filter(q_conditions).order_by('-CreateTime')
        total_count, orders_page = paginate_fluent_query(list_qs, page, page_size)
        if total_count > 0 and not orders_page:
            start = (max(1, page) - 1) * page_size
            orders_page = list(list_qs._qs[start:start + page_size])

        order_ids = [o.OrderID for o in orders_page if o.OrderID]
        ext_map = {}
        if order_ids:
            for ext in PlatformOrderExt.query.filter(Order__OrderID__in=order_ids).select_related('Order'):
                if ext.Order:
                    ext_map[ext.Order.OrderID] = ext

        laoban_ids = [
            ext.BossID for ext in ext_map.values() if ext.BossID
        ]
        nickname_map = {}
        if laoban_ids:
            users = User.query.filter(UserUID__in=laoban_ids).select_related('BossProfile').only(
                'UserUID', 'BossProfile__nickname'
            )
            for user in users:
                nickname_map[user.UserUID] = (user.BossProfile.nickname or '') if getattr(user, 'BossProfile', None) else ''

        from jituan.services.order_deal import order_auto_settle_payload
        club_names = _club_label_map([(getattr(o, 'ClubID', None) or '') for o in orders_page])
        result_list = []
        for order in orders_page:
            ext = ext_map.get(order.OrderID)
            laoban_id = ext.BossID if ext else ''
            youxi_nicheng = nickname_map.get(laoban_id, order.Nickname or '')
            item = {
                'dingdan_id': order.OrderID or '',
                'jieshao': order.Description or '',
                'zhuangtai': order.Status,
                'leixing': order.ProductTypeID,
                'fadanpingtai': order.Platform,
                'jiage': float(order.Amount) if order.Amount else 0.00,
                'tupian_url': order.ImageURL or '',
                'fadanshijian': order.CreateTime.strftime('%Y-%m-%d %H:%M:%S') if order.CreateTime else '',
                'youxi_nicheng': youxi_nicheng,
                'yaoqiuleixing': order.GrabRequirement,
                'huiyuan_id': order.MembershipID or '',
                'yajin': float(order.CommissionReq) if order.CommissionReq is not None else None,
            }
            _attach_order_club_fields(item, order, club_names)
            item.update(order_auto_settle_payload(order))
            result_list.append(item)

        from jituan.services.club_user_access import list_response_meta

        response_data = {
            'stats': {
                'totalOrders': stats['total_orders'] or 0,
                'completedOrders': stats['completed_orders'] or 0,
                'refundOrders': stats['refund_orders'] or 0,
                'pendingOrders': stats['pending_orders'] or 0
            },
            'statusCounts': status_counts,
            'list': result_list,
            'total': total_count,
            'page': page,
            'pageSize': page_size,
            **list_response_meta(request),
        }

        logger.info(f"平台订单接口总耗时: {time.time()-start_total:.3f}s")
        return Response({'code': 0, 'data': response_data})


class KefuGetShangjiaOrderListView(APIView):
    """
    客服获取商家订单列表接口（发单平台=2，非跨平台）
    需要权限：002ac（商家订单管理）—— 如不区分可使用 002ab
    请求参数：
        username: 客服账号（用于权限校验）
        page: 页码
        pageSize: 每页条数
        dingdan_id: 订单ID（精确搜索）
        shangjia_id: 商家ID（搜索商家扩展表中的商家ID）
        dashou_id: 打手ID（搜索主表中的接单打手）
        leixing: 商品类型ID
        zhuangtai: 状态（多个用逗号分隔，如 "1,7"）
        date: 日期（YYYY-MM-DD），筛选订单创建时间
        nicheng: 游戏昵称（订单主表的 nicheng 字段）
        jieshao: 订单介绍（订单主表的 jieshao 字段）
        clkf: 处理客服（订单主表的 clkf 字段）
        shangjia_nicheng: 商家昵称（商家扩展表中的昵称）
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        start_total = time.time()

        # 1. 获取前端参数（兼容 phone / username）
        username = request.data.get('username', '').strip() or request.data.get('phone', '').strip()
        if not username:
            return Response({'code': 400, 'msg': '缺少username'})

        # 2. 权限校验（与 menu-access 同一算法、同一用户）
        kefu, permissions = verify_kefu_permission(request, None)
        if kefu is None:
            return permissions

        if not has_merchant_order_permission(permissions):
            from backend.utils import _AllPermissions
            if isinstance(permissions, _AllPermissions):
                codes = ['*']
            else:
                codes = list(permissions or [])
            return Response({
                'code': 403,
                'msg': (
                    f'您无权查看商家订单列表（需要 002ac/002ab/003aa，'
                    f'当前俱乐部权限码：{",".join(codes) or "无"}）'
                ),
            })

        # 4. 获取分页和筛选参数
        page = int(request.data.get('page', 1))
        page_size = int(request.data.get('pageSize', 20))

        dingdan_id = request.data.get('dingdan_id', '').strip()
        shangjia_id = request.data.get('shangjia_id', '').strip()
        dashou_id = request.data.get('dashou_id', '').strip()
        leixing = request.data.get('leixing')
        zhuangtai = request.data.get('zhuangtai', '')
        date = request.data.get('date', '').strip()
        # 新增筛选条件
        nicheng = request.data.get('nicheng', '').strip()
        jieshao = request.data.get('jieshao', '').strip()
        clkf = request.data.get('clkf', '').strip()
        shangjia_nicheng = request.data.get('shangjia_nicheng', '').strip()

        # ---------- 查询条件 ----------
        from jituan.services.club_context import merchant_order_base_q
        base_q = merchant_order_base_q()

        if dingdan_id:
            q_conditions = base_q & Q(OrderID=dingdan_id)
        else:
            q_conditions = base_q
            if leixing is not None and str(leixing).strip() != '':
                try:
                    leixing_int = int(leixing)
                    q_conditions &= Q(ProductTypeID=leixing_int)
                except (ValueError, TypeError):
                    pass
            if zhuangtai and zhuangtai != 'all':
                try:
                    status_list = [int(s.strip()) for s in zhuangtai.split(',') if s.strip()]
                    if status_list:
                        q_conditions &= Q(Status__in=status_list)
                except (ValueError, TypeError):
                    pass
            if dashou_id:
                q_conditions &= Q(PlayerID=dashou_id)
            if shangjia_id:
                q_conditions &= Q(shangjia_kuozhan__MerchantID=shangjia_id)
            if date:
                q_conditions &= Q(CreateTime__date=date)
            if nicheng:
                q_conditions &= Q(Nickname__icontains=nicheng)
            if jieshao:
                q_conditions &= Q(Description__icontains=jieshao)
            if clkf:
                q_conditions &= Q(AssignedCS__icontains=clkf)
            if shangjia_nicheng:
                # 通过商家扩展表关联 UserShangjia 的昵称
                q_conditions &= Q(shangjia_kuozhan__MerchantID__in=User.query.filter(
                    ShopProfile__nicheng__icontains=shangjia_nicheng
                ).values_list('UserUID', flat=True))

            from orders.services.merchant_order_list_filters import wants_auto_settle_pending
            if wants_auto_settle_pending(request.data):
                q_conditions &= Q(Status=8, AutoSettleEligible=True, AutoExpireAt__isnull=False)

        from jituan.services.club_context import (
            count_order_status_buckets,
            order_scope_qs,
            paginate_fluent_query,
        )
        from orders.models import MerchantOrderExt

        stats_qs = order_scope_qs(request).filter(q_conditions)
        stats = stats_qs.aggregate(
            total_orders=Count('id'),
            completed_orders=Count('id', filter=Q(Status=3)),
            refund_orders=Count('id', filter=Q(Status=5)),
            pending_orders=Count('id', filter=Q(Status__in=[4, 8]))
        )
        status_counts = count_order_status_buckets(q_conditions, request)

        list_qs = order_scope_qs(request).filter(q_conditions).order_by('-CreateTime')
        total_count, orders_page = paginate_fluent_query(list_qs, page, page_size)
        if total_count > 0 and not orders_page:
            start = (max(1, page) - 1) * page_size
            orders_page = list(list_qs._qs[start:start + page_size])

        order_ids = [o.OrderID for o in orders_page if o.OrderID]
        ext_map = {}
        if order_ids:
            for ext in MerchantOrderExt.query.filter(Order__OrderID__in=order_ids).select_related('Order'):
                if ext.Order:
                    ext_map[ext.Order.OrderID] = ext

        shangjia_ids = [
            ext.MerchantID for ext in ext_map.values() if ext.MerchantID
        ]
        nickname_map = {}
        if shangjia_ids:
            users = User.query.filter(UserUID__in=shangjia_ids).select_related('ShopProfile').only(
                'UserUID', 'ShopProfile__nicheng'
            )
            for user in users:
                nickname_map[user.UserUID] = user.ShopProfile.nicheng or '' if hasattr(user, 'ShopProfile') else ''

        from jituan.services.order_deal import order_auto_settle_payload
        club_names = _club_label_map([(getattr(o, 'ClubID', None) or '') for o in orders_page])
        result_list = []
        for order in orders_page:
            ext = ext_map.get(order.OrderID)
            shangjia_id = ext.MerchantID if ext else ''
            youxi_nicheng = order.Nickname or ''
            item = {
                'dingdan_id': order.OrderID or '',
                'jieshao': order.Description or '',
                'zhuangtai': order.Status,
                'leixing': order.ProductTypeID,
                'fadanpingtai': order.Platform,
                'jiage': float(order.Amount) if order.Amount else 0.00,
                'tupian_url': order.ImageURL or '',
                'fadanshijian': order.CreateTime.strftime('%Y-%m-%d %H:%M:%S') if order.CreateTime else '',
                'youxi_nicheng': youxi_nicheng,
                'shangjia_id': shangjia_id,
                'shangjia_nicheng': nickname_map.get(shangjia_id, ''),
            }
            _attach_order_club_fields(item, order, club_names)
            item.update(order_auto_settle_payload(order))
            result_list.append(item)

        from jituan.services.club_user_access import list_response_meta

        response_data = {
            'stats': {
                'totalOrders': stats['total_orders'] or 0,
                'completedOrders': stats['completed_orders'] or 0,
                'refundOrders': stats['refund_orders'] or 0,
                'pendingOrders': stats['pending_orders'] or 0
            },
            'statusCounts': status_counts,
            'list': result_list,
            'total': total_count,
            'page': page,
            'pageSize': page_size,
            **list_response_meta(request),
        }

        logger.info(f"商家订单接口总耗时: {time.time()-start_total:.3f}s")
        return Response({'code': 0, 'data': response_data})


class KefuChangeDashouView(APIView):
    """
    客服更换打手接口
    请求：POST /yonghu/kefughds
    参数：{
        "phone": "客服手机号",
        "dingdan_id": "订单ID",
        "new_dashou_id": "新打手ID"
    }
    认证：JWT
    返回：code=0 成功
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        # 1. 获取参数
        phone = request.data.get('phone', '').strip()
        dingdan_id = request.data.get('dingdan_id', '').strip()
        new_dashou_id = request.data.get('new_dashou_id', '').strip()

        if not phone or not dingdan_id or not new_dashou_id:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 2. 客服身份验证
        current_user = request.user
        if getattr(current_user, 'Phone', '') != phone:
            logger.warning(f"手机号不匹配: {phone}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if not is_kefu_backend_account(current_user):
            logger.warning(f"用户类型非客服: {current_user.UserUID}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        is_admin = is_system_super_admin(current_user) or current_user.UserType == 'admin'
        kefu = None
        if not is_admin:
            try:
                kefu = current_user.KefuProfile
            except ObjectDoesNotExist:
                logger.warning(f"客服扩展表不存在: {current_user.UserUID}")
                return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

            if kefu.zhuangtai != 1:
                logger.warning(f"客服账号已禁用: {current_user.UserUID}")
                return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 3. 查询订单
        try:
            order = Order.query.get(OrderID=dingdan_id)
            from jituan.services.club_user_access import forbid_if_order_mutate_out_of_scope
            _ms = forbid_if_order_mutate_out_of_scope(request, order)
            if _ms:
                return _ms

        except Order.DoesNotExist:
            return Response({'code': 404, 'msg': '订单不存在'}, status=status.HTTP_404_NOT_FOUND)

        # 4. 验证订单状态是否允许更换打手（进行中2 或 结算中8）
        if order.Status not in [2, 8]:
            return Response({'code': 400, 'msg': '订单状态不允许更换打手'}, status=status.HTTP_400_BAD_REQUEST)

        # 5. 查询新打手
        try:
            new_dashou_user = User.query.select_related('DashouProfile').get(UserUID=new_dashou_id)
        except User.DoesNotExist:
            return Response({'code': 404, 'msg': '打手不存在'}, status=status.HTTP_404_NOT_FOUND)

        # 6. 验证打手扩展表
        try:
            new_dashou_profile = new_dashou_user.DashouProfile
        except ObjectDoesNotExist:
            return Response({'code': 404, 'msg': '打手信息不完整'}, status=status.HTTP_404_NOT_FOUND)

        # 7. 验证打手状态（打手状态和账号状态必须为1）
        if new_dashou_profile.zhuangtai != 1 or new_dashou_profile.zhanghaozhuangtai != 1:
            return Response({'code': 400, 'msg': '打手状态不允许接单'}, status=status.HTTP_400_BAD_REQUEST)
        # 8. 验证打手积分是否足够（至少5分）
        if new_dashou_profile.jifen < 5:
            return Response({'code': 400, 'msg': '打手积分不足，无法接单'}, status=status.HTTP_400_BAD_REQUEST)

        # 8. 根据订单的抢单要求类型进行额外验证
        yaoqiuleixing = order.GrabRequirement

        if yaoqiuleixing == 1:  # 会员抢单
            huiyuan_id = order.MembershipID
            if not huiyuan_id:
                return Response({'code': 400, 'msg': '订单会员ID为空'}, status=status.HTTP_400_BAD_REQUEST)

            try:
                # 查询打手的会员购买记录
                huiyuan_goumai = Huiyuangoumai.query.get(
                    huiyuan_id=huiyuan_id,
                    yonghu_id=new_dashou_id  # 假设 yonghu_id 字段存储用户ID
                )
            except Huiyuangoumai.DoesNotExist:
                return Response({'code': 400, 'msg': '打手未购买该订单要求的会员'}, status=status.HTTP_400_BAD_REQUEST)

            # 检查会员是否过期（调用模型方法）
            is_expired = huiyuan_goumai.jiance_shifou_daoqi()
            if is_expired or huiyuan_goumai.huiyuan_zhuangtai != 1:
                return Response({'code': 400, 'msg': '打手的会员已过期'}, status=status.HTTP_400_BAD_REQUEST)

        elif yaoqiuleixing == 2:  # 押金抢单
            order_yajin = order.CommissionReq  # 假设订单的 yongjin 字段存储押金要求
            if order_yajin is None:
                return Response({'code': 400, 'msg': '订单押金为空'}, status=status.HTTP_400_BAD_REQUEST)

            if new_dashou_profile.yajin < order_yajin:
                return Response({'code': 400, 'msg': '打手押金不足'}, status=status.HTTP_400_BAD_REQUEST)
        else:
            return Response({'code': 400, 'msg': '订单抢单要求类型错误'}, status=status.HTTP_400_BAD_REQUEST)

        # 9. 所有验证通过，开始更换打手（使用事务）
        with transaction.atomic():
            # 9.1 更新新打手扩展表
            new_dashou_profile.zhuangtai = 0  # 设为接单中
            new_dashou_profile.jiedanzongliang += 1
            new_dashou_profile.jinrijiedan += 1
            new_dashou_profile.jinyuejiedan += 1
            new_dashou_profile.save()

            # 9.2 处理原打手（如果存在）
            old_dashou_id = order.PlayerID
            if old_dashou_id:
                try:
                    old_dashou_user = User.query.get(UserUID=old_dashou_id)
                    old_dashou_profile = old_dashou_user.DashouProfile
                    old_dashou_profile.zhuangtai = 1  # 恢复空闲
                    old_dashou_profile.tuikuanliang += 1  # 原打手退款总量+1（业务逻辑）
                    old_dashou_profile.save()
                    logger.info(f"原打手 {old_dashou_id} 状态已更新")
                except (User.DoesNotExist, ObjectDoesNotExist):
                    logger.warning(f"原打手 {old_dashou_id} 不存在或信息不完整，跳过更新")
                except Exception as e:
                    logger.error(f"更新原打手时异常: {str(e)}", exc_info=True)

            # 9.3 更新订单
            order.PlayerID = new_dashou_id
            order.Status = 2  # 进行中
            order.AssignedCS = current_user.UserUID  # 记录处理客服ID
            order.save()

            try:
                from orders.services.team_recruit import on_order_change_player
                on_order_change_player(order.OrderID, actor_uid=getattr(current_user, 'UserUID', '') or 'kefu')
            except Exception as e:
                logger.error(f'组队换打手作废失败: {e}')

        return Response({'code': 0, 'msg': '更换打手成功'})


class KefuRecoverOrderView(APIView):
    """
    客服恢复订单接口（仅状态9可恢复）
    请求：POST /yonghu/kefuhf
    参数：{
        "phone": "客服手机号",
        "dingdan_id": "订单ID"
    }
    认证：JWT
    返回：code=0 成功
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        # 1. 获取参数
        phone = request.data.get('phone', '').strip()
        dingdan_id = request.data.get('dingdan_id', '').strip()

        if not phone or not dingdan_id:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 2. 客服身份验证
        current_user = request.user
        if getattr(current_user, 'Phone', '') != phone:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if not is_kefu_backend_account(current_user):
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        is_admin = is_system_super_admin(current_user) or current_user.UserType == 'admin'
        kefu = None
        if not is_admin:
            try:
                kefu = current_user.KefuProfile
            except ObjectDoesNotExist:
                return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

            if kefu.zhuangtai != 1:
                return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 3. 查询订单
        try:
            order = Order.query.get(OrderID=dingdan_id)
            from jituan.services.club_user_access import forbid_if_order_mutate_out_of_scope
            _ms = forbid_if_order_mutate_out_of_scope(request, order)
            if _ms:
                return _ms

        except Order.DoesNotExist:
            return Response({'code': 404, 'msg': '订单不存在'}, status=status.HTTP_404_NOT_FOUND)

        # 4. 验证订单状态是否为9（未付款）
        if order.Status != 9:
            return Response({'code': 400, 'msg': '订单状态不允许恢复'}, status=status.HTTP_400_BAD_REQUEST)

        # 5. 根据是否有指定ID决定新状态
        if order.AssignedID:
            new_status = 7  # 指定中
        else:
            new_status = 1  # 下单中

        # 6. 更新订单
        order.Status = new_status
        order.AssignedCS = current_user.UserUID
        order.save()

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


class KefuPlatformRefundView(APIView):
    """
    客服平台订单退款接口（调用微信支付）
    请求：POST /yonghu/kefupttk
    参数：{
        "phone": "客服手机号",
        "dingdan_id": "订单ID",
        "tuikuan_liyou": "退款理由（可选）"
    }
    认证：JWT
    返回：code=0 成功，code=其他 失败
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        # 1. 获取参数
        phone = request.data.get('phone', '').strip()
        dingdan_id = request.data.get('dingdan_id', '').strip()
        tuikuan_liyou = request.data.get('tuikuan_liyou', '').strip()

        if not phone or not dingdan_id:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 2. 客服身份验证
        current_user = request.user
        if getattr(current_user, 'Phone', '') != phone:
            logger.warning(f"手机号不匹配: {phone}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if not is_kefu_backend_account(current_user):
            logger.warning(f"用户类型非客服: {current_user.UserUID}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        is_admin = is_system_super_admin(current_user) or current_user.UserType == 'admin'
        kefu = None
        if not is_admin:
            try:
                kefu = current_user.KefuProfile
            except ObjectDoesNotExist:
                logger.warning(f"客服扩展表不存在: {current_user.UserUID}")
                return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

            if kefu.zhuangtai != 1:
                logger.warning(f"客服账号已禁用: {current_user.UserUID}")
                return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 3. 查询订单并加锁
        try:
            with transaction.atomic():
                order = Order.query.select_related('pingtai_kuozhan').select_for_update().get(OrderID=dingdan_id)

                from jituan.services.club_user_access import forbid_if_order_mutate_out_of_scope
                _ms = forbid_if_order_mutate_out_of_scope(request, order)
                if _ms:
                    return _ms

                # 4. 验证平台订单
                if order.Platform != 1:
                    return Response({'code': 400, 'msg': '该订单不是平台订单'}, status=status.HTTP_400_BAD_REQUEST)

                # 5. 验证状态允许退款（根据模型，状态值：1下单中，2进行中，3已完成，4退款审核，5已退款，6退款失败，7指定中，8结算中）
                allowed_statuses = [1, 2, 4, 7, 8]  # 允许退款的已支付或处理中状态
                if order.Status not in allowed_statuses:
                    return Response({'code': 400, 'msg': '订单状态不允许退款'}, status=status.HTTP_400_BAD_REQUEST)

                # 6. 获取微信交易号（如果存在）
                wechat_transaction_id = getattr(order, 'WechatTransactionID', None)

                # 7. 调用微信退款接口
                refund_result = self.call_wechat_refund(
                    dingdan_id=order.OrderID,
                    jine=order.Amount,
                    transaction_id=wechat_transaction_id
                )

                if refund_result['code'] != 0:
                    # 微信退款失败，直接返回错误，数据库不更新
                    logger.error(f"微信退款失败，订单 {dingdan_id}，原因：{refund_result['msg']}")
                    return Response({'code': 400, 'msg': refund_result['msg']}, status=status.HTTP_400_BAD_REQUEST)

                # 8. 更新订单状态为5（已退款）
                order.Status = 5
                order.AssignedCS = current_user.Phone  # 记录处理客服手机号
                if tuikuan_liyou:
                    order.RefundReason = tuikuan_liyou
                order.save()

                # 9. 更新打手数据
                jiedan_dashou_id = order.PlayerID
                if jiedan_dashou_id:
                    try:
                        dashou_user = User.query.get(UserUID=jiedan_dashou_id)
                        dashou_profile = dashou_user.DashouProfile
                        dashou_profile.tuikuanliang += 1
                        dashou_profile.zhuangtai = 1  # 打手状态设为空闲
                        dashou_profile.save()
                        logger.info(f"平台退款：打手 {jiedan_dashou_id} 退款订单+1")
                    except (User.DoesNotExist, ObjectDoesNotExist):
                        logger.warning(f"平台退款：打手 {jiedan_dashou_id} 不存在或扩展表缺失，跳过更新")

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

                        update_shangpin_daily_stat(
                            shangpin_id=order.ProductID,
                            caozuo_leixing=3,  # 3 = 退款
                            dingdan_jiage=order.Amount,
                            pingtai_shouyi=pingtai_shouyi,
                            dianpu_zongshouyi=dianpu_shouyi
                        )
                        logger.info(f"商品统计更新完成，商品ID: {order.ProductID}")

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

                # 10. 更新退款记录表（假设存在 RefundRecord 模型，字段需根据实际调整）

                #更新支出记录
                update_daily_payout(order.Amount, getattr(order, 'ClubID', None))


                try:
                    refund_record, created = RefundRecord.query.get_or_create(
                        OrderID=dingdan_id,
                        defaults={
                            'PlayerID': jiedan_dashou_id or '',
                            'ApplicantID': '',
                            'ProcessorID': phone,
                            'Reason': tuikuan_liyou or '客服退款',
                            'ApplyStatus': 1,  # 成功
                            'Amount': order.Amount,
                            'PlayerCommission': order.PlayerCommission or 0,
                            'Description': order.Description or '',
                            'Remark': '客服平台退款',
                            'Nickname': order.Nickname or '',
                        }
                    )
                    if not created:
                        refund_record.ApplyStatus = 1
                        refund_record.ProcessorID = phone
                        if tuikuan_liyou:
                            refund_record.Reason = tuikuan_liyou
                        refund_record.save()
                except Exception as e:
                    logger.error(f"平台退款更新退款记录异常: {str(e)}", exc_info=True)

                # 11. 更新客服统计数据（管理员无客服扩展表，跳过）
                if kefu is not None:
                    kefu.jinrichuli += 1
                    kefu.jinyuechuli += 1
                    kefu.zongchuli += 1
                    kefu.save()

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

            logger.info(f"平台退款成功，订单 {dingdan_id}，退款单号 {refund_result.get('refund_id')}")
            return Response({'code': 0, 'msg': '退款成功'})

        except Order.DoesNotExist:
            return Response({'code': 404, 'msg': '订单不存在'}, status=status.HTTP_404_NOT_FOUND)
        except Exception as e:
            logger.error(f"平台退款接口异常: {str(e)}", exc_info=True)
            return Response({'code': 500, 'msg': '服务器内部错误'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def call_wechat_refund(self, dingdan_id, jine, transaction_id=None):
        """
        平台订单退款：付呗单走付呗；微信直连单按订单 Club 的「收款」配置 V2 退款（不用全局 settings、不用提现 V3）。
        不处理支付宝。
        """
        from jituan.services.pay_refund_router import try_fubei_refund
        from jituan.services.wechat_pay import club_id_from_order
        from jituan.services.wechat_v2_refund import refund_wechat_v2_by_club

        club_id = club_id_from_order(dingdan_id)
        fb = try_fubei_refund(
            out_trade_no=dingdan_id,
            amount_yuan=jine,
            club_id=club_id,
        )
        if fb is not None:
            return fb

        return refund_wechat_v2_by_club(
            out_trade_no=dingdan_id,
            amount_yuan=jine,
            club_id=club_id,
            transaction_id=transaction_id,
            reason='客服退款',
        )

    def generate_nonce_str(self):
        return ''.join(random.choices(string.ascii_letters + string.digits, k=32))

    def generate_refund_no(self, dingdan_id):
        timestamp = str(int(time.time()))
        rand = ''.join(random.choices('0123456789', k=4))
        return f"{dingdan_id}REF{timestamp}{rand}"

    def dict_to_xml(self, data):
        xml = ['<xml>']
        for k, v in data.items():
            xml.append(f'<{k}>{v}</{k}>')
        xml.append('</xml>')
        return ''.join(xml)


class KefuRejectRefundView(APIView):
    """
    客服拒绝退款接口
    请求：POST /yonghu/kefujjtk
    参数：{
        "phone": "客服手机号",
        "dingdan_id": "订单ID",
        "jujue_liyou": "拒绝理由（可选）"
    }
    认证：JWT
    返回：code=0 成功
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        # 1. 获取参数
        phone = request.data.get('phone', '').strip()
        dingdan_id = request.data.get('dingdan_id', '').strip()
        jujue_liyou = request.data.get('jujue_liyou', '').strip()

        if not phone or not dingdan_id:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 2. 客服身份验证
        current_user = request.user
        if getattr(current_user, 'Phone', '') != phone:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if not is_kefu_backend_account(current_user):
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        is_admin = is_system_super_admin(current_user) or current_user.UserType == 'admin'
        kefu = None
        if not is_admin:
            try:
                kefu = current_user.KefuProfile
            except ObjectDoesNotExist:
                return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

            if kefu.zhuangtai != 1:
                return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 3. 查询订单并加锁
        try:
            with transaction.atomic():
                order = Order.objects.select_for_update().get(OrderID=dingdan_id)

                from jituan.services.club_user_access import forbid_if_order_mutate_out_of_scope
                _ms = forbid_if_order_mutate_out_of_scope(request, order)
                if _ms:
                    return _ms

                # 4. 验证订单状态为退款审核中（4）
                if order.Status != 4:
                    return Response({'code': 400, 'msg': '订单状态不是退款审核中'}, status=status.HTTP_400_BAD_REQUEST)

                # 获取必要字段
                jiedan_dashou_id = order.PlayerID
                dashou_fencheng = order.PlayerCommission
                fadan_pingtai = order.Platform

                # 5. 验证打手分成金额是否存在
                if dashou_fencheng is None:
                    return Response({'code': 400, 'msg': '订单缺少打手分成金额'}, status=status.HTTP_400_BAD_REQUEST)

                # 6. 更新订单状态为退款失败（6）
                order.Status = 6
                order.AssignedCS = current_user.Phone  # 记录处理客服手机号
                if jujue_liyou:
                    order.RefundReason = jujue_liyou
                order.save()

                # 7. 给打手结算（返还分成）
                if jiedan_dashou_id:
                    try:
                        dashou_user = User.query.get(UserUID=jiedan_dashou_id)
                        dashou_profile = dashou_user.DashouProfile
                        from jituan.services.fund_freeze import credit_dashou_order_settle
                        credit_dashou_order_settle(
                            order=order,
                            dashou_profile=dashou_profile,
                            user_id=jiedan_dashou_id,
                            amount=dashou_fencheng,
                        )
                        logger.info(f"拒绝退款：打手 {jiedan_dashou_id} 获得分成 {dashou_fencheng}")
                    except (User.DoesNotExist, AttributeError):
                        logger.warning(f"拒绝退款：打手 {jiedan_dashou_id} 不存在或扩展表缺失，跳过结算")

                # 8. 如果是商家发单，更新商家成交订单数量
                if fadan_pingtai == 2:
                    try:
                        # 获取商家订单扩展表
                        shangjia_kuozhan = order.shangjia_kuozhan
                        shangjia_id = shangjia_kuozhan.MerchantID
                        if shangjia_id:
                            shangjia_user = User.query.get(UserUID=shangjia_id)
                            shangjia_profile = shangjia_user.ShopProfile
                            shangjia_profile.chengjiao += 1
                            shangjia_profile.save()
                            logger.info(f"拒绝退款：商家 {shangjia_id} 成交订单+1")

                            # ✅ 新方法（行为驱动，更安全）
                            update_shangjia_daily(
                                yonghuid=shangjia_id,
                                amount=Decimal(str(order.Amount)),
                                action=2,  # 2 = 结算
                                order_id=dingdan_id,
                            )
                    except (ObjectDoesNotExist, User.DoesNotExist, AttributeError):
                        logger.warning(f"拒绝退款：商家信息不存在，跳过商家更新")

                # 9. 更新退款记录表
                try:
                    refund_record = RefundRecord.query.get(OrderID=dingdan_id)
                    refund_record.ApplyStatus = 2          # 2表示拒绝
                    refund_record.ProcessorID = phone
                    refund_record.RejectReason = jujue_liyou    # 记录驳回理由（假设模型有此字段）
                    refund_record.save()
                    logger.info(f"拒绝退款：更新退款记录表，订单 {dingdan_id}")
                except RefundRecord.DoesNotExist:
                    # 如果退款记录不存在，可以创建一条记录（可选）
                    RefundRecord.query.create(
                        OrderID=dingdan_id,
                        PlayerID=jiedan_dashou_id or '',
                        ApplicantID='',
                        ProcessorID=phone,
                        Reason=jujue_liyou or '客服拒绝退款',
                        ApplyStatus=2,
                        Amount=order.Amount,
                        PlayerCommission=dashou_fencheng or 0,
                        Description=order.Description or '',
                        Remark='客服拒绝退款',
                        Nickname=order.Nickname or '',
                        RejectReason=jujue_liyou or '',
                    )
                except Exception as e:
                    logger.error(f"拒绝退款更新退款记录异常: {str(e)}", exc_info=True)

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

                # 10. 更新客服统计数据（管理员无客服扩展表，跳过）
                if kefu is not None:
                    kefu.jinrichuli += 1
                    kefu.jinyuechuli += 1
                    kefu.zongchuli += 1
                    kefu.save()

            return Response({'code': 0, 'msg': '拒绝退款成功'})

        except Order.DoesNotExist:
            return Response({'code': 404, 'msg': '订单不存在'}, status=status.HTTP_404_NOT_FOUND)
        except Exception as e:
            logger.error(f"拒绝退款接口异常: {str(e)}", exc_info=True)
            return Response({'code': 500, 'msg': '服务器内部错误'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class KefuMerchantRefundView(APIView):
    """
    客服商家订单退款接口（发单平台=2）
    请求：POST /yonghu/kefusjtk
    参数：{
        "phone": "客服手机号",
        "dingdan_id": "订单ID",
        "tuikuan_liyou": "退款理由（可选）"
    }
    认证：JWT
    返回：code=0 成功
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        phone = request.data.get('phone', '').strip()
        dingdan_id = request.data.get('dingdan_id', '').strip()
        tuikuan_liyou = request.data.get('tuikuan_liyou', '').strip()

        if not phone or not dingdan_id:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 客服身份验证（同前，省略以节省篇幅，但实际必须完整）
        current_user = request.user
        # ... 验证
        if getattr(current_user, 'Phone', '') != phone:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if not is_kefu_backend_account(current_user):
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        is_admin = is_system_super_admin(current_user) or current_user.UserType == 'admin'
        kefu = None
        if not is_admin:
            try:
                kefu = current_user.KefuProfile
            except ObjectDoesNotExist:
                return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

            if kefu.zhuangtai != 1:
                return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)


        # 查询订单，预加载商家扩展表
        try:
            order = Order.query.select_related('shangjia_kuozhan').get(OrderID=dingdan_id)
            from jituan.services.club_user_access import forbid_if_order_mutate_out_of_scope
            _ms = forbid_if_order_mutate_out_of_scope(request, order)
            if _ms:
                return _ms

        except Order.DoesNotExist:
            return Response({'code': 404, 'msg': '订单不存在'}, status=status.HTTP_404_NOT_FOUND)

        # 验证商家订单
        if order.Platform != 2:
            return Response({'code': 400, 'msg': '该订单不是商家订单'}, status=status.HTTP_400_BAD_REQUEST)

        # 验证状态允许退款
        allowed_statuses = [1, 7, 2, 8, 4]
        if order.Status not in allowed_statuses:
            return Response({'code': 400, 'msg': '订单状态不允许退款'}, status=status.HTTP_400_BAD_REQUEST)

        # 获取必要数据
        jiedan_dashou_id = order.PlayerID
        jine = order.Amount
        if jine is None:
            return Response({'code': 400, 'msg': '订单金额缺失'}, status=status.HTTP_400_BAD_REQUEST)

        try:
            shangjia_kuozhan = order.shangjia_kuozhan
            shangjia_id = shangjia_kuozhan.MerchantID
        except ObjectDoesNotExist:
            return Response({'code': 400, 'msg': '订单商家信息不存在'}, status=status.HTTP_400_BAD_REQUEST)

        with transaction.atomic():
            # 更新订单
            order.Status = 5
            order.AssignedCS = current_user.Phone
            if tuikuan_liyou:
                order.RefundReason = tuikuan_liyou
            order.save()

            # 更新打手
            if jiedan_dashou_id:
                try:
                    dashou_user = User.query.get(UserUID=jiedan_dashou_id)
                    dashou_profile = dashou_user.DashouProfile
                    dashou_profile.tuikuanliang += 1
                    dashou_profile.zhuangtai = 1
                    dashou_profile.save()
                except (User.DoesNotExist, ObjectDoesNotExist):
                    logger.warning(f"商家退款：打手 {jiedan_dashou_id} 不存在，跳过更新")

            # 更新商家（客服额度出资的订单不退商家余额，仅释放子客服额度）
            try:
                from merchant_ops.services.wallet import is_staff_quota_order
                shangjia_user = User.query.get(UserUID=shangjia_id)
                shangjia_profile = shangjia_user.ShopProfile
                shangjia_profile.tuikuan += 1
                if not is_staff_quota_order(dingdan_id):
                    shangjia_profile.yue += jine
                shangjia_profile.save()
            except (User.DoesNotExist, ObjectDoesNotExist):
                logger.warning(f"商家退款：商家 {shangjia_id} 不存在，跳过更新")

            # 更新退款记录表
            try:
                refund_record = RefundRecord.query.get(OrderID=dingdan_id)
                refund_record.ApplyStatus = 1
                refund_record.ProcessorID = phone
                refund_record.save()
            except RefundRecord.DoesNotExist:
                pass

            # 更新客服统计
            update_shangjia_daily(
                yonghuid=shangjia_id,
                amount=Decimal(str(order.Amount)),
                action=3,  # 3 = 退款
                order_id=dingdan_id,
            )


            # 调用打手每日统计（成交）
            try:
                update_dashou_daily_by_action(
                    yonghuid=order.PlayerID,
                    amount=order.PlayerCommission,
                    action=3  # 3 表示退款（退款）
                )
                logger.info(f"打手 {order.PlayerID} 每日统计更新成功")
            except Exception as e:
                logger.error(f"打手每日统计更新失败: {e}")
                # 不影响主流程



            # 管理员无客服扩展表，跳过计数器更新
            is_admin = is_system_super_admin(current_user) or current_user.UserType == 'admin'
            if not is_admin:
                kefu = current_user.KefuProfile
                kefu.jinrichuli += 1
                kefu.jinyuechuli += 1
                kefu.zongchuli += 1
                kefu.save()

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


class KefuRejectSettlementView(APIView):
    """
    客服拒绝结算接口（仅平台订单，状态2/8）
    请求：POST /yonghu/kefujjjs
    参数：{
        "phone": "客服手机号",
        "dingdan_id": "订单ID",
        "tkly": "拒绝结算理由（必填）"
    }
    认证：JWT
    返回：code=0 成功，其他失败
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        # 1. 获取参数
        phone = request.data.get('phone', '').strip()
        dingdan_id = request.data.get('dingdan_id', '').strip()
        tkly = request.data.get('tkly', '').strip()

        if not phone or not dingdan_id or not tkly:
            return Response({'code': 401, 'msg': '参数不完整'}, status=status.HTTP_401_UNAUTHORIZED)

        # 2. 客服身份验证
        current_user = request.user
        if getattr(current_user, 'Phone', '') != phone:
            logger.warning(f"手机号不匹配: {phone}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        if not is_kefu_backend_account(current_user):
            logger.warning(f"用户类型非客服: {current_user.UserUID}")
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        is_admin = is_system_super_admin(current_user) or current_user.UserType == 'admin'
        kefu = None
        if not is_admin:
            try:
                kefu = current_user.KefuProfile
            except ObjectDoesNotExist:
                logger.warning(f"客服扩展表不存在: {current_user.UserUID}")
                return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

            if kefu.zhuangtai != 1:
                logger.warning(f"客服账号已禁用: {current_user.UserUID}")
                return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 3. 查询订单，预加载平台扩展表
        try:
            order = Order.query.select_related('pingtai_kuozhan').get(OrderID=dingdan_id)
            from jituan.services.club_user_access import forbid_if_order_mutate_out_of_scope
            _ms = forbid_if_order_mutate_out_of_scope(request, order)
            if _ms:
                return _ms

        except Order.DoesNotExist:
            return Response({'code': 404, 'msg': '订单不存在'}, status=status.HTTP_404_NOT_FOUND)

        # 4. 校验订单条件：平台发单（1）且状态为2或8
        if order.Platform != 1 or order.Status not in [2, 8]:
            return Response({'code': 400, 'msg': '仅平台发单且状态为进行中(2)或结算中(8)的订单可拒绝结算'}, status=status.HTTP_400_BAD_REQUEST)

        jiedan_dashou_id = order.PlayerID
        if not jiedan_dashou_id:
            return Response({'code': 400, 'msg': '订单暂无接单打手'}, status=status.HTTP_400_BAD_REQUEST)

        # 5. 使用事务更新
        with transaction.atomic():
            # 5.1 更新订单主表
            order.Status = 5                     # 已退款
            order.RefundReason = tkly                        # 拒绝理由
            order.AssignedCS = phone                        # 记录客服手机号
            order.save()

            # 5.2 更新平台订单扩展表：标记为拒绝结算（假设字段 jjjs_biaoshi）
            # 注意：需要确保 PlatformOrderExt 模型中已添加 jjjs_biaoshi 字段，IntegerField，默认0
            if hasattr(order, 'pingtai_kuozhan') and order.pingtai_kuozhan:
                pingtai_ext = order.pingtai_kuozhan
                pingtai_ext.RejectSettlementFlag = 1          # 1表示拒绝结算
                pingtai_ext.save()
            else:
                # 理论上应该存在，但若不存在则记录日志
                logger.warning(f"订单 {dingdan_id} 缺少平台扩展表，无法标记拒绝结算")

            # 5.3 更新打手扩展表
            try:
                dashou_user = User.query.get(UserUID=jiedan_dashou_id)
                dashou_profile = dashou_user.DashouProfile
                dashou_profile.zhuangtai = 1          # 打手状态设为空闲
                dashou_profile.tuikuanliang += 1      # 退款订单总量+1
                dashou_profile.save()
                logger.info(f"拒绝结算：打手 {jiedan_dashou_id} 退款订单+1，状态空闲")
            except (User.DoesNotExist, ObjectDoesNotExist):
                logger.warning(f"拒绝结算：打手 {jiedan_dashou_id} 不存在或扩展表缺失，跳过更新")
            except Exception as e:
                logger.error(f"拒绝结算更新打手异常: {str(e)}", exc_info=True)

            # 5.4 更新客服扩展表统计数据


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



            if kefu is not None:
                kefu.jinrichuli += 1
                kefu.jinyuechuli += 1
                kefu.zongchuli += 1
                kefu.save()

        return Response({'code': 0, 'msg': '拒绝结算成功'})


class KefuTransferHallView(APIView):
    """
    客服恢复大厅（转移大厅）接口
    请求：POST /yonghu/kefuzydt
    参数：{
        "phone": "客服手机号",
        "dingdan_id": "订单ID"
    }
    认证：JWT
    返回：code=0 成功
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        # 1. 获取参数
        phone = request.data.get('phone', '').strip()
        dingdan_id = request.data.get('dingdan_id', '').strip()

        if not phone or not dingdan_id:
            return Response({'code': 401, 'msg': '参数不完整'}, status=status.HTTP_401_UNAUTHORIZED)

        # 2. 客服身份验证（同前，略，但必须完整实现）
        current_user = request.user
        if getattr(current_user, 'Phone', '') != phone:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)
        if not is_kefu_backend_account(current_user):
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)
        is_admin = is_system_super_admin(current_user) or current_user.UserType == 'admin'
        kefu = None
        if not is_admin:
            try:
                kefu = current_user.KefuProfile
                if kefu.zhuangtai != 1:
                    return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)
            except ObjectDoesNotExist:
                return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 3. 查询订单
        try:
            order = Order.query.get(OrderID=dingdan_id)
            from jituan.services.club_user_access import forbid_if_order_mutate_out_of_scope
            _ms = forbid_if_order_mutate_out_of_scope(request, order)
            if _ms:
                return _ms

        except Order.DoesNotExist:
            return Response({'code': 404, 'msg': '订单不存在'}, status=status.HTTP_404_NOT_FOUND)

        # 4. 校验订单状态（允许状态：2,8,4）
        if order.Status not in [2, 8, 4]:
            return Response({'code': 400, 'msg': '订单状态不允许转移大厅'}, status=status.HTTP_400_BAD_REQUEST)


        if order.PlayerID:
            UserDashou.query.filter(user__UserUID=order.PlayerID).update(zhuangtai=1)
        else:
            pass        

        # 5. 根据是否有指定ID决定新状态
        if order.AssignedID:
            new_status = 7   # 指定中
        else:
            new_status = 1   # 下单中

        # 6. 使用事务更新
        with transaction.atomic():
            # 清空接单打手ID，更新状态，记录客服
            order.PlayerID = None
            order.Status = new_status
            order.AssignedCS = phone
            order.save()

        return Response({'code': 0, 'msg': '转移大厅成功'})


class KefuCancelDesignationView(APIView):
    """
    客服取消指定接口（仅状态7）
    请求：POST /yonghu/kefuqxzd
    参数：{
        "phone": "客服手机号",
        "dingdan_id": "订单ID"
    }
    认证：JWT
    返回：code=0 成功
    """
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        # 1. 获取参数
        phone = request.data.get('phone', '').strip()
        dingdan_id = request.data.get('dingdan_id', '').strip()

        if not phone or not dingdan_id:
            return Response({'code': 401, 'msg': '参数不完整'}, status=status.HTTP_401_UNAUTHORIZED)

        # 2. 客服身份验证（同前，略，但必须完整实现）
        current_user = request.user
        if getattr(current_user, 'Phone', '') != phone:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)
        if not is_kefu_backend_account(current_user):
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)
        is_admin = is_system_super_admin(current_user) or current_user.UserType == 'admin'
        kefu = None
        if not is_admin:
            try:
                kefu = current_user.KefuProfile
                if kefu.zhuangtai != 1:
                    return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)
            except ObjectDoesNotExist:
                return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 3. 查询订单
        try:
            order = Order.query.get(OrderID=dingdan_id)
            from jituan.services.club_user_access import forbid_if_order_mutate_out_of_scope
            _ms = forbid_if_order_mutate_out_of_scope(request, order)
            if _ms:
                return _ms

        except Order.DoesNotExist:
            return Response({'code': 404, 'msg': '订单不存在'}, status=status.HTTP_404_NOT_FOUND)

        # 4. 校验订单状态为7（指定中）
        
        if order.Status != 7:
            print(999)
            return Response({'code': 400, 'msg': '仅状态为指定中(7)的订单可取消指定'}, status=status.HTTP_400_BAD_REQUEST)

        # 5. 使用事务更新
        with transaction.atomic():
            # 状态改为1（下单中），清空指定ID，记录客服
            order.Status = 1
            order.AssignedID = None
            order.AssignedCS = phone
            order.save()

        return Response({'code': 0, 'msg': '取消指定成功'})


class KefuGetOrderDetailView(APIView):
    permission_classes = [IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        phone = request.data.get('phone', '').strip()
        dingdan_id = request.data.get('dingdan_id', '').strip()

        if not phone or not dingdan_id:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

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

        # 验证手机号
        if getattr(current_user, 'Phone', '') != phone:
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 验证用户类型
        if not is_kefu_backend_account(current_user):
            return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)

        # 客服扩展表
        is_admin = is_system_super_admin(current_user) or current_user.UserType == 'admin'
        kefu = None
        if not is_admin:
            try:
                kefu = current_user.KefuProfile
                if kefu.zhuangtai != 1:
                    return Response({'code': 401, 'msg': '认证失败'}, status=status.HTTP_401_UNAUTHORIZED)
            except Exception as e:
                logger.exception(f"[kefuhqddxq] 获取客服扩展表异常 user={getattr(current_user, 'yonghuid', '?')}")
                return Response({'code': 500, 'msg': '服务器错误'}, status=500)

        # 3. 查询订单
        try:
            dingdan_obj = Order.query.select_related(
                'pingtai_kuozhan', 'shangjia_kuozhan'
            ).get(OrderID=dingdan_id)
        except Order.DoesNotExist:
            return Response({'code': 404, 'msg': '订单不存在'}, status=404)
        except Exception as e:
            logger.exception(f"[kefuhqddxq] 订单查询异常 dingdan_id={dingdan_id}")
            return Response({'code': 500, 'msg': '服务器错误'}, status=500)

        from jituan.services.club_user_access import (
            forbid_if_order_out_of_scope,
            forbid_if_order_mutate_out_of_scope,
            order_belongs_to_request,
        )
        deny = forbid_if_order_out_of_scope(request, dingdan_obj)
        if deny:
            return deny
        _detail_can_mutate = forbid_if_order_mutate_out_of_scope(request, dingdan_obj) is None

        # 4. 构建基础数据
        try:
            _cid = (getattr(dingdan_obj, 'ClubID', None) or '').strip()
            _cname = _club_label_map([_cid]).get(_cid, _cid)
            response_data = {
                'dingdan_id': dingdan_obj.OrderID or '',
                'club_id': _cid,
                'club_name': _cname,
                'can_mutate': bool(_detail_can_mutate and order_belongs_to_request(dingdan_obj, request)),
                'zhuangtai': dingdan_obj.Status or 0,
                'fadanpingtai': dingdan_obj.Platform or 0,
                'jiage': float(dingdan_obj.Amount) if dingdan_obj.Amount else 0.00,
                'dashou_fencheng': float(dingdan_obj.PlayerCommission) if dingdan_obj.PlayerCommission else 0.00,
                'jiedan_dashou_id': dingdan_obj.PlayerID or '',
                'dashou_liuyan': dingdan_obj.PlayerRemark or '',
                'zhiding_id': dingdan_obj.AssignedID or '',
                'shangpin_id': dingdan_obj.ProductID or '',
                'leixing': dingdan_obj.ProductTypeID or 0,
                'tupian_url': dingdan_obj.ImageURL or '',
                'jieshao': dingdan_obj.Description or '',
                'beizhu': dingdan_obj.Remark or '',
                'tkly': dingdan_obj.RefundReason or '',
                'nicheng': dingdan_obj.Nickname or '',
                'clkf': dingdan_obj.AssignedCS or '',
                'chuangjianshijian': dingdan_obj.CreateTime.strftime('%Y-%m-%d %H:%M:%S') if dingdan_obj.CreateTime else '',
                'genggaishijian': dingdan_obj.UpdateTime.strftime('%Y-%m-%d %H:%M:%S') if dingdan_obj.UpdateTime else '',
                'yaoqiuleixing': dingdan_obj.GrabRequirement,
                'huiyuan_id': dingdan_obj.MembershipID or '',
                'yajin': float(dingdan_obj.CommissionReq) if dingdan_obj.CommissionReq is not None else None,
            }
        except Exception as e:
            logger.exception(f"[kefuhqddxq] 构建基础数据异常 dingdan_id={dingdan_id}")
            return Response({'code': 500, 'msg': '服务器错误'}, status=500)

        # 5. 扩展表数据
        try:
            fadan_pingtai = dingdan_obj.Platform
            if fadan_pingtai == 1:
                if hasattr(dingdan_obj, 'pingtai_kuozhan') and dingdan_obj.pingtai_kuozhan:
                    pingtai = dingdan_obj.pingtai_kuozhan
                    response_data['pingtai_kuozhan'] = {
                        'laoban_id': pingtai.BossID or '',
                        'laoban_pingjia': pingtai.BossReview or '',
                    }
                else:
                    response_data['pingtai_kuozhan'] = {'laoban_id': '', 'laoban_pingjia': ''}
            elif fadan_pingtai == 2:
                if hasattr(dingdan_obj, 'shangjia_kuozhan') and dingdan_obj.shangjia_kuozhan:
                    shangjia = dingdan_obj.shangjia_kuozhan
                    response_data['shangjia_kuozhan'] = {
                        'shangjia_id': shangjia.MerchantID or '',
                        'sjnicheng': shangjia.MerchantNickname or '',
                        'shangjia_pingjia': shangjia.MerchantReview or '',
                        'cfliyou': shangjia.PenaltyReason or '',
                        'sqzhuangtai': shangjia.PenaltyApplyStatus if shangjia.PenaltyApplyStatus is not None else 0,
                        'bhliyou': shangjia.RejectReason or '',
                    }
                else:
                    response_data['shangjia_kuozhan'] = {
                        'shangjia_id': '', 'sjnicheng': '', 'shangjia_pingjia': '',
                        'cfliyou': '', 'sqzhuangtai': 0, 'bhliyou': ''
                    }
        except Exception as e:
            logger.exception(f"[kefuhqddxq] 扩展数据异常 dingdan_id={dingdan_id}")
            return Response({'code': 500, 'msg': '服务器错误'}, status=500)

        # 6. 打手图片
        try:
            dashou_images = PlayerDeliveryImage.query.filter(OrderID=dingdan_id).values_list('ImageURL', flat=True)
            response_data['dashou_images'] = [img for img in dashou_images if img]
        except Exception as e:
            logger.exception(f"[kefuhqddxq] 打手图片查询异常 dingdan_id={dingdan_id}")
            response_data['dashou_images'] = []

        # 7. 退款理由 + 证据图
        try:
            tuikuan_record = RefundRecord.query.filter(OrderID=dingdan_id).order_by('-CreateTime').first()
            response_data['tuikuan_liyou'] = tuikuan_record.Reason if tuikuan_record and tuikuan_record.Reason else ''
        except Exception as e:
            logger.exception(f"[kefuhqddxq] 退款理由查询异常 dingdan_id={dingdan_id}")
            response_data['tuikuan_liyou'] = ''
        try:
            from orders.models import RefundEvidenceImage
            response_data['tuikuan_tupian'] = list(
                RefundEvidenceImage.query.filter(OrderID=dingdan_id)
                .exclude(ImageURL__isnull=True)
                .exclude(ImageURL='')
                .values_list('ImageURL', flat=True)
            )
        except Exception as e:
            logger.exception(f"[kefuhqddxq] 退款图片查询异常 dingdan_id={dingdan_id}")
            response_data['tuikuan_tupian'] = []

        # 8. 指定打手响应
        ZHIDING_HF_TEXT = {1: '想接', 2: '不想接', 3: '等会接'}
        hf = getattr(dingdan_obj, 'AssignedResponse', None)
        response_data['zhiding_hf'] = hf
        response_data['zhiding_hf_text'] = ZHIDING_HF_TEXT.get(hf, '') if hf else ''
        response_data['zhiding_hf_sj'] = (
            dingdan_obj.AssignedResponseAt.strftime('%Y-%m-%d %H:%M:%S')
            if getattr(dingdan_obj, 'AssignedResponseAt', None) else ''
        )
        response_data['zhiding_dhj_sm'] = getattr(dingdan_obj, 'AssignedLaterNote', '') or ''

        # 9. 关联罚款（打手）
        from utils.penalty_status import PENALTY_STATUS_LABELS as PENALTY_STATUS
        try:
            from orders.models import Penalty
            dashou_id = dingdan_obj.PlayerID or dingdan_obj.AssignedID or ''
            fakuan_qs = Penalty.query.filter(RelatedOrderID=dingdan_id)
            if dashou_id:
                fakuan_qs = fakuan_qs.filter(PenalizedUserID=dashou_id)
            fakuan_list = []
            for p in fakuan_qs.order_by('-CreateTime')[:5]:
                fakuan_list.append({
                    'amount': str(p.FineAmount or '0.00'),
                    'status': p.Status,
                    'status_text': PENALTY_STATUS.get(p.Status, ''),
                    'reason': p.Reason or '',
                    'create_time': p.CreateTime.strftime('%Y-%m-%d %H:%M:%S') if p.CreateTime else '',
                })
            response_data['fakuan_list'] = fakuan_list
            latest = fakuan_list[0] if fakuan_list else None
            response_data['fakuan_info'] = latest
            response_data['is_fadaned'] = Penalty.query.filter(
                RelatedOrderID=dingdan_id, ApplicantID=getattr(current_user, 'UserUID', '')
            ).exists()
        except Exception as e:
            logger.exception(f"[kefuhqddxq] 罚款查询异常 dingdan_id={dingdan_id}")
            response_data['fakuan_list'] = []
            response_data['fakuan_info'] = None
            response_data['is_fadaned'] = False

        try:
            from jituan.services.order_deal import order_auto_settle_payload
            response_data.update(order_auto_settle_payload(dingdan_obj))
        except Exception as e:
            logger.warning('[kefuhqddxq] 自动结算字段附加失败 dingdan_id=%s: %s', dingdan_id, e)

        return Response({'code': 0, 'data': response_data})


class KefuForceCompleteView(APIView):
    """
    客服强制结单接口（仅本地订单）
    请求：POST /yonghu/kefuqiangzhijiedan
    参数：{"phone": "客服手机号", "dingdan_id": "订单ID"}
    认证：JWT，仅限状态正常的客服
    逻辑：
        1. 验证客服身份及状态
        2. 查询订单并加锁（事务内）
        3. 校验订单状态是否为8（结算中）
        4. 校验订单必须有接单打手且打手分成金额有效
        5. 给打手增加余额、成交统计、今日/本月收益
        6. 如果是商家发单，更新商家成交订单数量
        7. 更新订单状态为3（已完成）
        8. 更新客服处理统计
        9. 返回成功
    """
    permission_classes = [permissions.IsAuthenticated]
    parser_classes = [JSONParser]

    def post(self, request):
        phone = request.data.get('phone', '').strip()
        dingdan_id = request.data.get('dingdan_id', '').strip()

        if not phone or not dingdan_id:
            return Response({'code': 401, 'msg': '参数缺失'})

        # 1. 客服身份验证
        current_user = request.user
        if getattr(current_user, 'Phone', '') != phone:
            return Response({'code': 401, 'msg': '认证失败'})

        if not is_kefu_backend_account(current_user):
            return Response({'code': 401, 'msg': '认证失败'})

        is_admin = is_system_super_admin(current_user) or current_user.UserType == 'admin'
        kefu = None
        if not is_admin:
            try:
                kefu = current_user.KefuProfile
            except ObjectDoesNotExist:
                return Response({'code': 401, 'msg': '认证失败'})

            if kefu.zhuangtai != 1:
                return Response({'code': 401, 'msg': '客服状态异常'})

        # 2. 订单处理（事务内）
        try:
            with transaction.atomic():
                order = Order.objects.select_for_update().get(OrderID=dingdan_id)

                from jituan.services.club_user_access import forbid_if_order_mutate_out_of_scope
                _ms = forbid_if_order_mutate_out_of_scope(request, order)
                if _ms:
                    return _ms

                # 3. 校验订单状态
                if order.Status != 8:
                    return Response({'code': 400, 'msg': f'订单状态不是结算中，当前状态: {order.Status}'})

                # 4. 校验必要字段
                dashou_id = order.PlayerID
                dashou_fencheng = order.PlayerCommission
                if not dashou_id:
                    return Response({'code': 400, 'msg': '订单无接单打手'})
                if not dashou_fencheng or dashou_fencheng <= 0:
                    return Response({'code': 400, 'msg': '打手分成金额无效'})

                # 5. 给打手结算（组队分账优先；均走冻结入账网关）
                try:
                    dashou_user = User.query.get(UserUID=dashou_id)
                    dashou_profile = dashou_user.DashouProfile
                except (User.DoesNotExist, AttributeError):
                    return Response({'code': 400, 'msg': '打手不存在或扩展表缺失'})

                freeze_result = {
                    'available': str(dashou_fencheng),
                    'frozen': '0.00',
                    'skipped_freeze': True,
                    'team_settled': False,
                }
                team_done = False
                try:
                    from orders.services.team_recruit import (
                        settle_team_or_legacy, get_active_recruit, lock_recruit, team_should_split,
                    )
                    from orders.models import TeamRecruit, TeamSettleLedger
                    rec = get_active_recruit(order.OrderID)
                    if rec and rec.status == TeamRecruit.STATUS_RECRUITING:
                        lock_recruit(rec.id, actor_uid='system', reason='force_settle_lock')
                    team_done = settle_team_or_legacy(order, set_idle_leader=True)
                except Exception as e:
                    logger.error('强制结单组队分账异常 %s: %s', dingdan_id, e, exc_info=True)
                    from orders.models import TeamSettleLedger
                    # 必须抛出让 atomic 回滚，禁止 return 提交半成品入账
                    if TeamSettleLedger.query.filter(order_id=dingdan_id).exists():
                        raise RuntimeError(f'组队分账异常且已有入账记录: {e}') from e
                    try:
                        from orders.services.team_recruit import team_should_split, get_active_recruit
                        if get_active_recruit(dingdan_id) or team_should_split(order):
                            raise RuntimeError(f'组队分账失败: {e}') from e
                    except RuntimeError:
                        raise
                    except Exception:
                        pass
                    team_done = False

                if team_done:
                    freeze_result['team_settled'] = True
                    freeze_result['skipped_freeze'] = False
                    logger.info('强制结单组队分账完成 order=%s', dingdan_id)
                else:
                    try:
                        from orders.services.team_recruit import get_active_recruit
                        if get_active_recruit(dingdan_id):
                            raise RuntimeError('存在有效组队但分账未完成，已阻止全额打给队长')
                    except RuntimeError:
                        raise
                    except Exception:
                        pass
                    from jituan.services.fund_freeze import credit_dashou_order_settle
                    settle_ret = credit_dashou_order_settle(
                        order=order,
                        dashou_profile=dashou_profile,
                        user_id=dashou_id,
                        amount=dashou_fencheng,
                    )
                    freeze_result = {
                        'available': str(settle_ret.get('available') or 0),
                        'frozen': str(settle_ret.get('frozen') or 0),
                        'skipped_freeze': bool(settle_ret.get('skipped_freeze')),
                        'skip_reason': settle_ret.get('skip_reason'),
                        'club_id': settle_ret.get('club_id'),
                        'ledger_id': settle_ret.get('ledger_id'),
                        'team_settled': False,
                    }
                    logger.info(
                        '强制结单打手入账 order=%s dashou=%s available=%s frozen=%s skip=%s reason=%s club=%s',
                        dingdan_id, dashou_id,
                        freeze_result['available'], freeze_result['frozen'],
                        freeze_result['skipped_freeze'], freeze_result.get('skip_reason'),
                        freeze_result.get('club_id'),
                    )

                # 6. 如果是商家发单，更新商家成交订单数量
                if order.Platform == 2:
                    try:
                        # 通过 MerchantOrderExt 获取商家ID
                        shangjia_ext = order.shangjia_kuozhan  # 假设 related_name='shangjia_kuozhan'
                        if shangjia_ext and shangjia_ext.shangjia_id:
                            shangjia_user = User.query.get(UserUID=shangjia_ext.shangjia_id)
                            shangjia_profile = shangjia_user.ShopProfile
                            shangjia_profile.chengjiao = F('chengjiao') + 1
                            shangjia_profile.save(update_fields=['chengjiao'])

                            # （行为驱动，更安全）
                            update_shangjia_daily(
                                yonghuid=shangjia_ext.shangjia_id,
                                amount=Decimal(str(order.Amount)),
                                action=2,  # 2 = 结算
                                order_id=dingdan_id,
                            )

                    except ObjectDoesNotExist:
                        # 没有商家扩展记录则忽略
                        pass

                # 7. 更新订单状态
                order.Status = 3
                order.AssignedCS = phone
                order.save(update_fields=['Status', 'AssignedCS'])


                if order.Platform == 1:

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

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

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

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

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

                # 8. 更新客服统计（超管/管理员无 KefuProfile 时跳过，不影响结单）
                if kefu is not None:
                    kefu.jinrichuli = F('jinrichuli') + 1
                    kefu.jinyuechuli = F('jinyuechuli') + 1
                    kefu.zongchuli = F('zongchuli') + 1
                    kefu.save(update_fields=['jinrichuli', 'jinyuechuli', 'zongchuli'])

            return Response({'code': 0, 'msg': '强制结单成功', 'data': freeze_result})

        except Order.DoesNotExist:
            return Response({'code': 404, 'msg': '订单不存在'})
        except Exception as e:
            logger.error(f"强制结单异常: {str(e)}", exc_info=True)
            return Response({'code': 500, 'msg': '服务器内部错误'})
