修复了商家客服接口
This commit is contained in:
59
merchant_ops/services/order_query.py
Normal file
59
merchant_ops/services/order_query.py
Normal file
@@ -0,0 +1,59 @@
|
||||
"""子客服订单查询:按权限隔离,不返回商家全量(除非 order_view_all)。"""
|
||||
from django.db.models import Q
|
||||
|
||||
from backend.utils import pick_leixing_id
|
||||
from merchant_ops.models import MerchantOrderDispatch
|
||||
from merchant_ops.services.authz import member_has_perm
|
||||
from orders.models import MerchantOrderExt
|
||||
|
||||
|
||||
def staff_can_view_all_orders(member):
|
||||
return member_has_perm(member, 'order_view_all')
|
||||
|
||||
|
||||
def staff_order_ext_qs(member, zhuangtai_list=None):
|
||||
"""商家名下订单;无 order_view_all 时仅本人派单记录。"""
|
||||
qs = MerchantOrderExt.query.filter(
|
||||
MerchantID=member.merchant_id,
|
||||
).select_related('Order')
|
||||
if zhuangtai_list is not None:
|
||||
qs = qs.filter(Order__Status__in=zhuangtai_list)
|
||||
if not staff_can_view_all_orders(member):
|
||||
own_ids = list(
|
||||
MerchantOrderDispatch.query.filter(staff_member_id=member.id).values_list('order_id', flat=True)
|
||||
)
|
||||
qs = qs.filter(Order__OrderID__in=own_ids)
|
||||
return qs
|
||||
|
||||
|
||||
def staff_apply_order_filters(qs, data):
|
||||
leixing_id = pick_leixing_id(data)
|
||||
keyword = str(data.get('keyword', '')).strip()
|
||||
if leixing_id is not None:
|
||||
qs = qs.filter(Order__ProductTypeID=leixing_id)
|
||||
if keyword:
|
||||
qs = qs.filter(
|
||||
Q(Order__OrderID__exact=keyword)
|
||||
| Q(Order__Description__icontains=keyword)
|
||||
| Q(Order__Nickname__icontains=keyword)
|
||||
| Q(Order__PlayerID__exact=keyword)
|
||||
)
|
||||
return qs
|
||||
|
||||
|
||||
def staff_order_to_dict(ext):
|
||||
o = ext.Order
|
||||
ct = o.CreateTime.strftime('%Y-%m-%d %H:%M:%S') if o.CreateTime else ''
|
||||
return {
|
||||
'dingdan_id': o.OrderID,
|
||||
'zhuangtai': o.Status,
|
||||
'jine': float(o.Amount) if o.Amount else 0.0,
|
||||
'jieshao': o.Description or '',
|
||||
'beizhu': o.Remark or '',
|
||||
'nicheng': o.Nickname or '',
|
||||
'leixing_id': o.ProductTypeID,
|
||||
'tupian': o.ImageURL or '',
|
||||
'jiedan_dashou_id': o.PlayerID or '',
|
||||
'CreateTime': ct,
|
||||
'create_time': ct,
|
||||
}
|
||||
103
merchant_ops/services/template_query.py
Normal file
103
merchant_ops/services/template_query.py
Normal file
@@ -0,0 +1,103 @@
|
||||
"""子客服读取商家模板:按 merchant_id 查 ShangjiaMoban(与老板同一批数据)。"""
|
||||
from decimal import Decimal, InvalidOperation
|
||||
|
||||
from django.core.paginator import Paginator
|
||||
from django.db.models import Q
|
||||
|
||||
from config.models import Chenghao, ShangjiaMoban
|
||||
|
||||
|
||||
def _format_moban(moban):
|
||||
texiao_json = ''
|
||||
label_name = ''
|
||||
if moban.TitleID:
|
||||
try:
|
||||
ch = Chenghao.query.get(id=moban.TitleID)
|
||||
label_name = ch.mingcheng
|
||||
texiao_json = ch.texiao_miaoshu or ''
|
||||
except Chenghao.DoesNotExist:
|
||||
pass
|
||||
return {
|
||||
'mobanId': moban.id,
|
||||
'shangpinTypeId': moban.ProductTypeID,
|
||||
'jieshao': moban.TemplateDesc,
|
||||
'jiage': str(moban.Price),
|
||||
'fabushuliang': moban.PublishedCount,
|
||||
'commissionEnabled': moban.CommissionGrabEnabled,
|
||||
'commissionValue': str(moban.CommissionPrice) if moban.CommissionPrice is not None else None,
|
||||
'labelId': moban.TitleID,
|
||||
'labelName': label_name,
|
||||
'texiaoJson': texiao_json,
|
||||
'createTime': moban.CreateTime.strftime('%Y-%m-%d %H:%M:%S') if moban.CreateTime else '',
|
||||
}
|
||||
|
||||
|
||||
def list_merchant_templates(merchant_id, data):
|
||||
"""
|
||||
查询某商家全部模板(UserID=merchant_id)。
|
||||
返回 (payload_dict, http_status) 与 /peizhi/sjddmblb 一致,code=200。
|
||||
"""
|
||||
leixing_id = data.get('shangpinTypeId')
|
||||
if not leixing_id:
|
||||
return {'code': 400, 'msg': '商品类型ID不能为空', 'data': {}}, 400
|
||||
|
||||
get_type = int(data.get('getType', 2))
|
||||
page = int(data.get('page', 1))
|
||||
page_size = int(data.get('pageSize', 50))
|
||||
keyword = data.get('keyword', '')
|
||||
min_price = data.get('minPrice', '')
|
||||
label_id = data.get('labelId', None)
|
||||
if label_id is not None:
|
||||
try:
|
||||
label_id = int(label_id)
|
||||
except (ValueError, TypeError):
|
||||
label_id = None
|
||||
|
||||
query = Q(UserID=merchant_id, ProductTypeID=leixing_id)
|
||||
|
||||
if get_type == 1:
|
||||
if keyword:
|
||||
keyword = str(keyword).strip()
|
||||
try:
|
||||
mid = int(keyword)
|
||||
query &= Q(id=mid) | Q(TemplateDesc__icontains=keyword)
|
||||
except ValueError:
|
||||
query &= Q(TemplateDesc__icontains=keyword)
|
||||
if min_price:
|
||||
try:
|
||||
query &= Q(Price__gte=Decimal(str(min_price)))
|
||||
except (InvalidOperation, ValueError, TypeError):
|
||||
pass
|
||||
if label_id:
|
||||
query &= Q(TitleID=label_id)
|
||||
mobans = ShangjiaMoban.query.filter(query).order_by('-id')
|
||||
formatted = [_format_moban(m) for m in mobans]
|
||||
return {
|
||||
'code': 200,
|
||||
'msg': '搜索成功',
|
||||
'data': {'list': formatted, 'total': len(formatted), 'hasMore': False},
|
||||
}, 200
|
||||
|
||||
queryset = ShangjiaMoban.query.filter(query).order_by('-id')
|
||||
paginator = Paginator(queryset, page_size)
|
||||
if page < 1 or page > max(paginator.num_pages, 1):
|
||||
return {'code': 400, 'msg': '页码超出范围', 'data': {}}, 400
|
||||
|
||||
current_page = paginator.page(page)
|
||||
formatted = [_format_moban(m) for m in current_page.object_list]
|
||||
has_more = current_page.has_next()
|
||||
if len(formatted) < page_size:
|
||||
has_more = False
|
||||
|
||||
return {
|
||||
'code': 200,
|
||||
'msg': '获取成功',
|
||||
'data': {
|
||||
'list': formatted,
|
||||
'total': paginator.count,
|
||||
'hasMore': has_more,
|
||||
'currentPage': page,
|
||||
'pageSize': page_size,
|
||||
'totalPages': paginator.num_pages,
|
||||
},
|
||||
}, 200
|
||||
@@ -1,16 +1,20 @@
|
||||
"""子客服专用订单接口(不修改商家原接口)。"""
|
||||
import logging
|
||||
|
||||
from django.db.models import Q
|
||||
from rest_framework import status
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from backend.utils import pick_leixing_id, pick_order_id
|
||||
from merchant_ops.helpers import proxy_merchant_order_view, staff_can_access_order
|
||||
from merchant_ops.models import MerchantOrderDispatch
|
||||
from backend.utils import pick_order_id
|
||||
from merchant_ops.helpers import proxy_merchant_order_view
|
||||
from merchant_ops.services.authz import StaffAuthError, get_active_staff_member, member_has_perm
|
||||
from merchant_ops.services.order_query import (
|
||||
staff_apply_order_filters,
|
||||
staff_can_view_all_orders,
|
||||
staff_order_ext_qs,
|
||||
staff_order_to_dict,
|
||||
)
|
||||
from merchant_ops.services.audit import audit_staff
|
||||
from merchant_ops.services.dispatch import staff_dispatch_order
|
||||
from merchant_ops.services.stats import bump_cancel_count, bump_penalty_count, update_merchant_and_staff_stats
|
||||
@@ -40,7 +44,11 @@ def _err(e):
|
||||
|
||||
|
||||
class StaffOrderListView(APIView):
|
||||
"""POST /yonghu/merchant-staff/order/list — 对齐 sjdingdanhq"""
|
||||
"""
|
||||
POST /yonghu/merchant-staff/order/list
|
||||
- 有 order_view_all:该商家全部订单
|
||||
- 否则:仅 merchant_order_dispatch 中 staff_member_id=本人的订单
|
||||
"""
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def post(self, request):
|
||||
@@ -53,61 +61,33 @@ class StaffOrderListView(APIView):
|
||||
zhuangtai_list = data.get('zhuangtai_list', [])
|
||||
page = max(1, int(data.get('page', 1)))
|
||||
page_size = min(100, max(1, int(data.get('page_size', 10))))
|
||||
leixing_id = pick_leixing_id(data)
|
||||
keyword = str(data.get('keyword', '')).strip()
|
||||
|
||||
if not isinstance(zhuangtai_list, list) or not zhuangtai_list:
|
||||
return Response({'code': 3, 'msg': '状态列表不能为空', 'data': None})
|
||||
|
||||
base_qs = MerchantOrderExt.query.filter(
|
||||
MerchantID=member.merchant_id,
|
||||
).select_related('Order').filter(Order__Status__in=zhuangtai_list)
|
||||
base_qs = staff_apply_order_filters(
|
||||
staff_order_ext_qs(member, zhuangtai_list),
|
||||
data,
|
||||
)
|
||||
|
||||
if not member_has_perm(member, 'order_view_all'):
|
||||
own_ids = MerchantOrderDispatch.query.filter(
|
||||
staff_member_id=member.id,
|
||||
).values_list('order_id', flat=True)
|
||||
base_qs = base_qs.filter(Order__OrderID__in=list(own_ids))
|
||||
pending_qs = staff_order_ext_qs(member, [8])
|
||||
pending_count = pending_qs.count()
|
||||
|
||||
if leixing_id is not None:
|
||||
base_qs = base_qs.filter(Order__ProductTypeID=leixing_id)
|
||||
if keyword:
|
||||
base_qs = base_qs.filter(
|
||||
Q(Order__OrderID__exact=keyword)
|
||||
| Q(Order__Description__icontains=keyword)
|
||||
| Q(Order__Nickname__icontains=keyword)
|
||||
| Q(Order__PlayerID__exact=keyword)
|
||||
)
|
||||
|
||||
pending_count = MerchantOrderExt.query.filter(
|
||||
MerchantID=member.merchant_id, Order__Status=8,
|
||||
).count()
|
||||
total_count = base_qs.count()
|
||||
start = (page - 1) * page_size
|
||||
page_qs = base_qs.order_by('-Order__CreateTime')[start:start + page_size]
|
||||
|
||||
order_list = []
|
||||
for ext in page_qs:
|
||||
o = ext.Order
|
||||
order_list.append({
|
||||
'dingdan_id': o.OrderID,
|
||||
'zhuangtai': o.Status,
|
||||
'jine': float(o.Amount) if o.Amount else 0.0,
|
||||
'jieshao': o.Description or '',
|
||||
'beizhu': o.Remark or '',
|
||||
'nicheng': o.Nickname or '',
|
||||
'leixing_id': o.ProductTypeID,
|
||||
'tupian': o.ImageURL or '',
|
||||
'jiedan_dashou_id': o.PlayerID or '',
|
||||
'CreateTime': o.CreateTime.strftime('%Y-%m-%d %H:%M:%S') if o.CreateTime else '',
|
||||
})
|
||||
order_list = [staff_order_to_dict(ext) for ext in page_qs]
|
||||
|
||||
return Response({
|
||||
'code': 0, 'msg': '成功',
|
||||
'code': 0,
|
||||
'msg': '成功',
|
||||
'data': {
|
||||
'list': order_list,
|
||||
'has_more': len(page_qs) == page_size and start + page_size < total_count,
|
||||
'total': total_count,
|
||||
'pending_count': pending_count,
|
||||
'view_scope': 'all' if staff_can_view_all_orders(member) else 'self',
|
||||
},
|
||||
})
|
||||
except Exception as e:
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
"""子客服专用:派单模板 / 链接(代理商家 config 接口,校验权限,不修改原 /peizhi/*)。"""
|
||||
"""子客服专用:派单模板 / 链接(独立路径;读模板用 merchant_id,写模板需 template_manage)。"""
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from config.views import (
|
||||
ShangjiaMobanListView,
|
||||
ShangjiaTianjiaMobanView,
|
||||
ShangjiaGengxinMobanView,
|
||||
ShangjiaShanchuMobanView,
|
||||
@@ -13,6 +12,7 @@ from config.views import (
|
||||
)
|
||||
from merchant_ops.helpers import proxy_as_merchant_user
|
||||
from merchant_ops.services.authz import StaffAuthError, get_active_staff_member, member_has_perm
|
||||
from merchant_ops.services.template_query import list_merchant_templates
|
||||
from merchant_ops.views_manage import _err
|
||||
|
||||
|
||||
@@ -23,13 +23,23 @@ def _require_staff(request):
|
||||
return member
|
||||
|
||||
|
||||
def _can_read_templates(member):
|
||||
"""派单发常规单需读模板;改模板需 template_manage。"""
|
||||
return member_has_perm(member, 'order_dispatch') or member_has_perm(member, 'template_manage')
|
||||
|
||||
|
||||
class StaffTemplateListView(APIView):
|
||||
"""读商家全部模板(UserID=merchant_id),有 order_dispatch 即可。"""
|
||||
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def post(self, request):
|
||||
try:
|
||||
member = _require_staff(request)
|
||||
return proxy_as_merchant_user(request, member, ShangjiaMobanListView, 'template_manage')
|
||||
if not _can_read_templates(member):
|
||||
raise StaffAuthError(403, '无权限查看模板')
|
||||
payload, http_status = list_merchant_templates(member.merchant_id, request.data)
|
||||
return Response(payload, status=http_status)
|
||||
except Exception as e:
|
||||
return _err(e)
|
||||
|
||||
@@ -40,6 +50,8 @@ class StaffTemplateCreateView(APIView):
|
||||
def post(self, request):
|
||||
try:
|
||||
member = _require_staff(request)
|
||||
if not member_has_perm(member, 'template_manage'):
|
||||
raise StaffAuthError(403, '无权限添加模板')
|
||||
return proxy_as_merchant_user(request, member, ShangjiaTianjiaMobanView, 'template_manage')
|
||||
except Exception as e:
|
||||
return _err(e)
|
||||
@@ -51,6 +63,8 @@ class StaffTemplateUpdateView(APIView):
|
||||
def post(self, request):
|
||||
try:
|
||||
member = _require_staff(request)
|
||||
if not member_has_perm(member, 'template_manage'):
|
||||
raise StaffAuthError(403, '无权限修改模板')
|
||||
return proxy_as_merchant_user(request, member, ShangjiaGengxinMobanView, 'template_manage')
|
||||
except Exception as e:
|
||||
return _err(e)
|
||||
@@ -62,6 +76,8 @@ class StaffTemplateDeleteView(APIView):
|
||||
def post(self, request):
|
||||
try:
|
||||
member = _require_staff(request)
|
||||
if not member_has_perm(member, 'template_manage'):
|
||||
raise StaffAuthError(403, '无权限删除模板')
|
||||
return proxy_as_merchant_user(request, member, ShangjiaShanchuMobanView, 'template_manage')
|
||||
except Exception as e:
|
||||
return _err(e)
|
||||
|
||||
Reference in New Issue
Block a user