108 lines
4.6 KiB
Python
108 lines
4.6 KiB
Python
"""子客服:绑定、个人信息。"""
|
|
import logging
|
|
|
|
from django.db import transaction
|
|
from django.utils import timezone
|
|
from rest_framework.permissions import IsAuthenticated
|
|
from rest_framework.response import Response
|
|
from rest_framework.views import APIView
|
|
|
|
from merchant_ops.constants import INVITE_STATUS_UNUSED, INVITE_STATUS_USED, MEMBER_STATUS_ACTIVE
|
|
from merchant_ops.models import MerchantStaffInvite, MerchantStaffMember
|
|
from merchant_ops.services.authz import (
|
|
StaffAuthError, assert_can_bind_staff, get_active_staff_member, resolve_staff_context,
|
|
)
|
|
from merchant_ops.services.audit import audit_staff
|
|
from merchant_ops.services.wallet import get_or_create_wallet
|
|
from users.business_models import User
|
|
from users.models import UserShangjia
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
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 StaffBindView(APIView):
|
|
"""POST /yonghu/merchant-staff/bind"""
|
|
permission_classes = [IsAuthenticated]
|
|
|
|
def post(self, request):
|
|
try:
|
|
assert_can_bind_staff(request.user)
|
|
invite_code = str(request.data.get('inviteCode') or request.data.get('invite_code') or '').strip()
|
|
if not invite_code or invite_code == 'XQKF2026':
|
|
return Response({'code': 400, 'msg': '请使用商家提供的一次性邀请码', 'data': None})
|
|
|
|
with transaction.atomic():
|
|
inv = MerchantStaffInvite.objects.select_for_update().get(
|
|
invite_code=invite_code, status=INVITE_STATUS_UNUSED,
|
|
)
|
|
if inv.expire_at and inv.expire_at < timezone.now():
|
|
inv.status = 3
|
|
inv.save(update_fields=['status'])
|
|
return Response({'code': 400, 'msg': '邀请码已过期', 'data': None})
|
|
|
|
if not inv.role_id:
|
|
return Response({'code': 400, 'msg': '邀请码未绑定角色', 'data': None})
|
|
|
|
display = getattr(request.user, 'Nickname', '') or request.user.UserUID
|
|
member, created = MerchantStaffMember.objects.get_or_create(
|
|
merchant_id=inv.merchant_id,
|
|
staff_user_id=request.user.UserUID,
|
|
defaults={
|
|
'role_id': inv.role_id,
|
|
'status': MEMBER_STATUS_ACTIVE,
|
|
'display_name': display[:64],
|
|
'invited_by_code': inv,
|
|
},
|
|
)
|
|
if not created:
|
|
if member.status == MEMBER_STATUS_ACTIVE:
|
|
return Response({'code': 400, 'msg': '您已是该商家客服', 'data': None})
|
|
member.status = MEMBER_STATUS_ACTIVE
|
|
member.role_id = inv.role_id
|
|
member.display_name = display[:64]
|
|
member.invited_by_code = inv
|
|
member.revoked_at = None
|
|
member.save()
|
|
|
|
inv.status = INVITE_STATUS_USED
|
|
inv.used_by = request.user.UserUID
|
|
inv.used_at = timezone.now()
|
|
inv.save(update_fields=['status', 'used_by', 'used_at'])
|
|
|
|
get_or_create_wallet(member)
|
|
|
|
ctx = resolve_staff_context(request.user)
|
|
shangjia = UserShangjia.query.filter(user__UserUID=inv.merchant_id).first()
|
|
if ctx and shangjia:
|
|
ctx['merchant_display'] = {'nicheng': shangjia.nicheng, 'merchant_id': inv.merchant_id}
|
|
audit_staff(member, 'STAFF_BIND', request, resource_id=invite_code)
|
|
return Response({'code': 0, 'msg': '绑定成功', 'data': {'staff_context': ctx}})
|
|
except MerchantStaffInvite.DoesNotExist:
|
|
return Response({'code': 404, 'msg': '邀请码无效或已使用', 'data': None})
|
|
except Exception as e:
|
|
return _err(e)
|
|
|
|
|
|
class StaffMeView(APIView):
|
|
"""GET/POST /yonghu/merchant-staff/me"""
|
|
permission_classes = [IsAuthenticated]
|
|
|
|
def post(self, request):
|
|
ctx = resolve_staff_context(request.user)
|
|
if not ctx:
|
|
return Response({'code': 404, 'msg': '非子客服身份', 'data': None})
|
|
member = get_active_staff_member(request.user)
|
|
shangjia = UserShangjia.query.filter(user__UserUID=member.merchant_id).first()
|
|
ctx['merchant_display'] = {
|
|
'nicheng': shangjia.nicheng if shangjia else '',
|
|
'sjyue': str(shangjia.yue) if shangjia else '0',
|
|
}
|
|
return Response({'code': 0, 'msg': '成功', 'data': ctx})
|