"""子客服专用订单接口(不修改商家原接口)。""" import logging 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_order_id from merchant_ops.helpers import proxy_merchant_order_view from merchant_ops.services.authz import ( StaffAuthError, require_active_staff_member, member_has_perm, staff_order_read_perm, ) from merchant_ops.services.order_query import ( staff_apply_order_filters, staff_can_view_all_orders, staff_order_ext_qs, ) 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 from merchant_ops.models import MerchantOrderDispatch from orders.models import MerchantOrderExt from orders.views import ( ShangjiaDingdanXiangqingView, ShangjiaJiesuanView, ShangjiaChexiaoView, ShangjiaTuikuanShenqingView, ShangjiaFakuanApplyView, ShangjiaFakuaiXiugaiView, ZxsjghdsView, ShangpinLeixingView, ) logger = logging.getLogger(__name__) def _require_staff(request): return require_active_staff_member(request.user) def _err(e): if isinstance(e, StaffAuthError): return Response({'code': e.code, 'msg': e.msg, 'data': None}) logger.exception(e) return Response({'code': 500, 'msg': '服务器错误', 'data': None}) class StaffOrderListView(APIView): """ POST /yonghu/merchant-staff/order/list - 有 order_view_all:该商家全部订单 - 否则:仅 merchant_order_dispatch 中 staff_member_id=本人的订单 """ permission_classes = [IsAuthenticated] def post(self, request): try: member = _require_staff(request) if not member_has_perm(member, 'order_view_all') and not member_has_perm(member, 'order_view_self'): raise StaffAuthError(403, '无订单查看权限') data = request.data 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)))) if not isinstance(zhuangtai_list, list) or not zhuangtai_list: return Response({'code': 3, 'msg': '状态列表不能为空', 'data': None}) base_qs = staff_apply_order_filters( staff_order_ext_qs(member, zhuangtai_list), data, ) pending_qs = staff_order_ext_qs(member, [8]) pending_count = pending_qs.count() from orders.services.merchant_order_stats import build_merchant_order_stats stats_qs = staff_order_ext_qs(member, None) stats_qs = staff_apply_order_filters(stats_qs, data) order_stats = build_merchant_order_stats(stats_qs) can_finance = member_has_perm(member, 'finance_view') if not can_finance: for k in list(order_stats.keys()): if k.endswith('_amount'): order_stats[k] = '0.00' total_count = base_qs.count() start = (page - 1) * page_size page_qs = list(base_qs.order_by('-Order__CreateTime')[start:start + page_size]) from jituan.services.club_context import resolve_club_id_from_request from orders.services.merchant_order_list_enrich import enrich_merchant_order_list_items club_id = resolve_club_id_from_request(request) order_list = enrich_merchant_order_list_items(page_qs, club_id=club_id) return Response({ 'code': 0, 'msg': '成功', 'data': { 'list': order_list, 'has_more': start + len(page_qs) < total_count, 'total': total_count, 'pending_count': order_stats['pending_count'], 'pending_amount': order_stats['pending_amount'] if can_finance else '0.00', 'order_stats': order_stats, 'can_view_finance': can_finance, 'view_scope': 'all' if staff_can_view_all_orders(member) else 'self', }, }) except Exception as e: return _err(e) class StaffOrderStatsView(APIView): """子客服/老板视角订单统计 POST /yonghu/merchant-staff/order/stats""" permission_classes = [IsAuthenticated] def post(self, request): try: member = _require_staff(request) if not member_has_perm(member, 'order_view_all') and not member_has_perm(member, 'order_view_self'): raise StaffAuthError(403, '无订单查看权限') data = request.data or {} from orders.services.merchant_order_stats import build_merchant_order_stats, filter_by_staff_member from orders.models import MerchantOrderExt filter_payload = dict(data) filter_payload['_merchant_id_filter'] = member.merchant_id qs = MerchantOrderExt.query.filter( MerchantID=member.merchant_id, ).select_related('Order') 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) elif data.get('staff_member_id'): qs = filter_by_staff_member(qs, member.merchant_id, data.get('staff_member_id')) qs = staff_apply_order_filters(qs, filter_payload) order_stats = build_merchant_order_stats(qs) can_finance = member_has_perm(member, 'finance_view') if not can_finance: for k in list(order_stats.keys()): if k.endswith('_amount'): order_stats[k] = '0.00' return Response({ 'code': 0, 'msg': '成功', 'data': { 'order': order_stats, 'can_view_finance': can_finance, }, }) except Exception as e: return _err(e) class StaffOrderDetailView(APIView): permission_classes = [IsAuthenticated] def post(self, request): try: member = _require_staff(request) if not member_has_perm(member, 'order_detail'): raise StaffAuthError(403, '无权限') resp = proxy_merchant_order_view( request, member, ShangjiaDingdanXiangqingView, 'order_detail', ) if resp.status_code == 200 and resp.data.get('code') == 0 and resp.data.get('data'): from merchant_ops.services.order_enrich import enrich_order_detail_data enrich_order_detail_data(resp.data['data'], pick_order_id(request.data)) return resp except Exception as e: return _err(e) class StaffDispatchView(APIView): permission_classes = [IsAuthenticated] def post(self, request): try: member = _require_staff(request) if not member_has_perm(member, 'order_dispatch'): raise StaffAuthError(403, '无派单权限') ok, payload = staff_dispatch_order(member, request.user, request.data) if ok: audit_staff(member, 'DISPATCH', request, resource_id=payload.get('data', {}).get('dingdan_id'), amount=request.data.get('jiage')) code = payload.get('code', 500) return Response(payload, status=status.HTTP_200_OK if code in (0, 200) else status.HTTP_400_BAD_REQUEST) except Exception as e: return _err(e) class StaffProductTypesView(APIView): """商品类型 — 代理 sjspleixing""" permission_classes = [IsAuthenticated] def post(self, request): try: member = _require_staff(request) perm = staff_order_read_perm(member) if not perm: raise StaffAuthError(403, '无权限查看商品类型') return proxy_merchant_order_view(request, member, ShangpinLeixingView, perm) except Exception as e: return _err(e) class StaffSettleView(APIView): permission_classes = [IsAuthenticated] def post(self, request): try: member = _require_staff(request) resp = proxy_merchant_order_view(request, member, ShangjiaJiesuanView, 'order_settle') if resp.data.get('code') in (0, 200): audit_staff(member, 'SETTLE', request, resource_id=pick_order_id(request.data)) return resp except Exception as e: return _err(e) class StaffCancelView(APIView): permission_classes = [IsAuthenticated] def post(self, request): try: member = _require_staff(request) resp = proxy_merchant_order_view(request, member, ShangjiaChexiaoView, 'order_cancel') if resp.data.get('code') in (0, 200): audit_staff(member, 'CANCEL', request, resource_id=pick_order_id(request.data)) bump_cancel_count(member.merchant_id, member) return resp except Exception as e: return _err(e) class StaffRefundView(APIView): permission_classes = [IsAuthenticated] def post(self, request): try: member = _require_staff(request) resp = proxy_merchant_order_view(request, member, ShangjiaTuikuanShenqingView, 'order_refund_apply') if resp.data.get('code') in (0, 200): audit_staff(member, 'REFUND_APPLY', request, resource_id=pick_order_id(request.data)) return resp except Exception as e: return _err(e) class StaffPenaltyApplyView(APIView): permission_classes = [IsAuthenticated] def post(self, request): try: member = _require_staff(request) resp = proxy_merchant_order_view(request, member, ShangjiaFakuanApplyView, 'penalty_apply') if resp.data.get('code') in (0, 200): audit_staff(member, 'PENALTY_APPLY', request, resource_id=pick_order_id(request.data)) bump_penalty_count(member.merchant_id, member) return resp except Exception as e: return _err(e) class StaffPenaltyManageView(APIView): permission_classes = [IsAuthenticated] def post(self, request): try: member = _require_staff(request) resp = proxy_merchant_order_view(request, member, ShangjiaFakuaiXiugaiView, 'penalty_manage') if resp.data.get('code') in (0, 200): audit_staff(member, 'PENALTY_MANAGE', request, resource_id=pick_order_id(request.data)) return resp except Exception as e: return _err(e) class StaffChangePlayerView(APIView): permission_classes = [IsAuthenticated] def post(self, request): try: member = _require_staff(request) resp = proxy_merchant_order_view(request, member, ZxsjghdsView, 'order_change_player') if resp.data.get('code') in (0, 200): audit_staff(member, 'CHANGE_PLAYER', request, resource_id=pick_order_id(request.data)) return resp except Exception as e: return _err(e)