199 lines
8.4 KiB
Python
199 lines
8.4 KiB
Python
"""客服:成交指标配置 / 商家·打手指标查询。"""
|
|
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 | whitelist_list | whitelist_save | whitelist_delete
|
|
"""
|
|
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)
|
|
data = deal_cfg.config_to_dict(row)
|
|
data['whitelist'] = deal_cfg.list_merchant_whitelist(club_id)
|
|
return Response({'code': 0, 'msg': 'ok', 'data': data})
|
|
if action == 'save':
|
|
try:
|
|
operator = getattr(request.user, 'UserUID', '') or ''
|
|
data = deal_cfg.save_deal_config(club_id, request.data, updated_by=operator)
|
|
data['whitelist'] = deal_cfg.list_merchant_whitelist(club_id)
|
|
return Response({'code': 0, 'msg': '已保存', 'data': data})
|
|
except ValueError as e:
|
|
return Response({'code': 400, 'msg': str(e)})
|
|
if action == 'whitelist_list':
|
|
return Response({
|
|
'code': 0,
|
|
'msg': 'ok',
|
|
'data': {'list': deal_cfg.list_merchant_whitelist(club_id)},
|
|
})
|
|
if action == 'whitelist_save':
|
|
try:
|
|
operator = getattr(request.user, 'UserUID', '') or ''
|
|
row = deal_cfg.save_merchant_whitelist(
|
|
club_id,
|
|
(request.data.get('merchant_uid') or '').strip(),
|
|
skip_auto_settle=bool(request.data.get('skip_auto_settle')),
|
|
skip_dispatch_block=bool(request.data.get('skip_dispatch_block')),
|
|
remark=(request.data.get('remark') or '').strip(),
|
|
updated_by=operator,
|
|
)
|
|
return Response({'code': 0, 'msg': '白名单已更新', 'data': row})
|
|
except ValueError as e:
|
|
return Response({'code': 400, 'msg': str(e)})
|
|
if action == 'whitelist_delete':
|
|
ok = deal_cfg.delete_merchant_whitelist(
|
|
club_id, (request.data.get('merchant_uid') or '').strip(),
|
|
)
|
|
return Response({
|
|
'code': 0 if ok else 400,
|
|
'msg': '已删除' if ok else '未找到该白名单',
|
|
})
|
|
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),
|
|
})
|