"""客服:成交指标配置 / 商家·打手指标查询。""" from rest_framework.parsers import JSONParser from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from rest_framework.views import APIView from backend.utils import verify_kefu_permission, has_merchant_order_permission from jituan.services.club_context import resolve_club_id_from_request from jituan.services import order_deal as deal_cfg from jituan.services import deal_stats as stats_svc def _auth_order(request): username = (request.data.get('username') or request.data.get('phone') or '').strip() if not username: return None, Response({'code': 400, 'msg': '缺少username'}) kefu, permissions = verify_kefu_permission(request, username) if kefu is None: return None, permissions codes = set(permissions or []) user = getattr(request, 'user', None) if getattr(user, 'IsSuperuser', False) or '000001' in codes: return kefu, None if has_merchant_order_permission(permissions) or '002ab' in codes: return kefu, None return None, Response({'code': 403, 'msg': '无订单管理权限'}) class OrderDealConfigView(APIView): """ POST /jituan/houtai/order-deal-config action: get | save """ permission_classes = [IsAuthenticated] parser_classes = [JSONParser] def post(self, request): kefu, err = _auth_order(request) if err: return err club_id = (resolve_club_id_from_request(request) or '').strip() if not club_id: return Response({'code': 400, 'msg': '请先选择俱乐部'}) action = (request.data.get('action') or 'get').strip().lower() if action == 'get': row = deal_cfg.get_or_create_deal_config(club_id) return Response({'code': 0, 'msg': 'ok', 'data': deal_cfg.config_to_dict(row)}) if action == 'save': try: operator = getattr(request.user, 'UserUID', '') or '' data = deal_cfg.save_deal_config(club_id, request.data, updated_by=operator) return Response({'code': 0, 'msg': '已保存', 'data': data}) except ValueError as e: return Response({'code': 400, 'msg': str(e)}) return Response({'code': 400, 'msg': '无效 action'}) class MerchantDealStatView(APIView): """POST /jituan/houtai/merchant-deal-stat action: list|detail""" permission_classes = [IsAuthenticated] parser_classes = [JSONParser] def post(self, request): kefu, err = _auth_order(request) if err: return err club_id = (resolve_club_id_from_request(request) or '').strip() from jituan.models import MerchantDealStat action = (request.data.get('action') or 'list').strip().lower() uid = (request.data.get('merchant_uid') or '').strip() if action == 'detail' and uid: row = MerchantDealStat.query.filter(club_id=club_id, merchant_uid=uid).first() return Response({ 'code': 0, 'msg': 'ok', 'data': stats_svc.serialize_merchant_stat(row) if row else { 'merchant_uid': uid, 'order_count': 0, 'deal_rate': 0, 'refund_rate': 0, 'fine_rate': 0, 'avg_deal_hours': 0, }, }) qs = MerchantDealStat.query.filter(club_id=club_id).order_by('-order_count')[:200] return Response({ 'code': 0, 'msg': 'ok', 'data': {'list': [stats_svc.serialize_merchant_stat(r) for r in qs]}, }) class DashouDealStatView(APIView): """POST /jituan/houtai/dashou-deal-stat action: list|detail""" permission_classes = [IsAuthenticated] parser_classes = [JSONParser] def post(self, request): kefu, err = _auth_order(request) if err: return err club_id = (resolve_club_id_from_request(request) or '').strip() from jituan.models import DashouDealStat action = (request.data.get('action') or 'list').strip().lower() uid = (request.data.get('dashou_uid') or '').strip() if action == 'detail' and uid: row = DashouDealStat.query.filter(club_id=club_id, dashou_uid=uid).first() return Response({ 'code': 0, 'msg': 'ok', 'data': stats_svc.serialize_dashou_stat(row) if row else { 'dashou_uid': uid, 'order_count': 0, 'deal_rate': 0, 'fined_rate': 0, }, }) qs = DashouDealStat.query.filter(club_id=club_id).order_by('-order_count')[:200] return Response({ 'code': 0, 'msg': 'ok', 'data': {'list': [stats_svc.serialize_dashou_stat(r) for r in qs]}, }) class MiniappMyDealStatView(APIView): """ POST /dingdan/wo-de-deal-stat 小程序订单列表顶:结算率/罚款率。 body.role: merchant | dashou(默认按身份推断) 商家客服看所属商家指标;无样本返回 data=null。 """ permission_classes = [IsAuthenticated] parser_classes = [JSONParser] def post(self, request): club_id = (resolve_club_id_from_request(request) or '').strip() if not club_id: return Response({'code': 400, 'msg': '缺少俱乐部', 'data': None}) user = request.user uid = getattr(user, 'UserUID', '') or '' role = (request.data.get('role') or '').strip().lower() if role not in ('merchant', 'dashou'): # 推断:活跃子客服 → merchant;否则看商家认证 / 打手 from merchant_ops.services.authz import get_active_staff_member, is_merchant_owner if get_active_staff_member(user) or is_merchant_owner(user): role = 'merchant' else: role = 'dashou' if role == 'merchant': merchant_uid = uid from merchant_ops.services.authz import get_active_staff_member, is_merchant_owner, member_has_perm member = get_active_staff_member(user) if member and not is_merchant_owner(user): if not member_has_perm(member, 'order_view_all') and not member_has_perm(member, 'order_view_self'): return Response({'code': 403, 'msg': '无订单查看权限', 'data': None}) merchant_uid = member.merchant_id from jituan.models import MerchantDealStat row = MerchantDealStat.query.filter(club_id=club_id, merchant_uid=merchant_uid).first() return Response({ 'code': 0, 'msg': 'ok', 'data': stats_svc.miniapp_merchant_deal_payload(row), }) from jituan.models import DashouDealStat row = DashouDealStat.query.filter(club_id=club_id, dashou_uid=uid).first() return Response({ 'code': 0, 'msg': 'ok', 'data': stats_svc.miniapp_dashou_deal_payload(row), })