Files
Django/jituan/views_order_deal.py
XingQue 0e102fbcba feat: 成交指标新表+可控自动结算(默认关,仅新进结算中eligible)
按设计文档:SettlementTime起表;关开关清eligible;定时任务只结到期eligible单;打款走统一结单;指标从stats_since起幂等记账。不打开旧全局ORDER_AUTO_SETTLEMENT。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-27 01:28:44 +08:00

117 lines
4.7 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
"""
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]},
})