fix: 打手注册支持默认邀请码回退,修复扫码注册管事重复创建

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
XingQue
2026-07-02 13:59:11 +08:00
parent 243ab5b817
commit d22b265e58
3 changed files with 130 additions and 115 deletions

View File

@@ -275,6 +275,11 @@ WEIXIN_TEMPLATE_BATCH_SIZE = 100 # 每批发送数量
WEIXIN_BROADCAST_ENABLED = True # 服务号订单广播总开关
WEIXIN_BROADCAST_WORKERS = 30 # Celery 任务内并发推送线程数(勿过大,避免触发微信频控)
# 打手无邀请码一键注册(须与小程序 default-invite-code.js 保持一致)
DASHOU_DEFAULT_INVITE_CODE = '0000008U3Ck4267NmxuY'
# 默认邀请码在库中查不到时,回退到该管事 yonghuid请确保该账号在库中存在且为管事
DASHOU_DEFAULT_GUANSHI_YONGHUID = '0000008'
WEIXIN_MCHID = '1746784529' # 商户号,支付功能需要紧急
WEIXIN_SHANGHUMIYAO = 'thgnfbdyhd4536dbvgf7dgfhcvdgfh58'# 商户密钥,支付功能需要紧急

View File

@@ -0,0 +1,95 @@
"""
打手注册共用逻辑:邀请码解析、创建打手、管事邀请统计。
"""
import logging
from django.conf import settings
from django.db import transaction
from yonghu.models import UserDashou, UserGuanshi
logger = logging.getLogger('yonghu.dashouzhuce')
def get_default_dashou_invite_code():
return getattr(settings, 'DASHOU_DEFAULT_INVITE_CODE', '').strip()
def resolve_guanshi_for_dashou_register(invite_code):
"""
根据邀请码查找管事;无邀请码时使用默认码;默认码查不到时按平台管事 yonghuid 回退。
返回 (guanshi_profile, error_message)
"""
code = (invite_code or '').strip()
default_code = get_default_dashou_invite_code()
if not code:
code = default_code
if not code:
return None, '邀请码不能为空'
if len(code) > 100:
return None, '邀请码长度超过限制'
guanshi = UserGuanshi.objects.select_related('user').filter(yaoqingma=code).first()
if guanshi:
return guanshi, None
if default_code and code == default_code:
fallback_uid = getattr(settings, 'DASHOU_DEFAULT_GUANSHI_YONGHUID', '').strip()
if fallback_uid:
guanshi = UserGuanshi.objects.select_related('user').filter(
user__yonghuid=fallback_uid,
).first()
if guanshi:
if guanshi.yaoqingma != code:
UserGuanshi.objects.filter(pk=guanshi.pk).update(yaoqingma=code)
guanshi.refresh_from_db()
logger.info('默认邀请码回退到平台管事 yonghuid=%s', fallback_uid)
return guanshi, None
return None, '邀请码无效或不存在'
def create_dashou_for_user(user_main, guanshi_profile):
"""为已登录用户创建打手身份,并更新管事邀请统计。返回 dashou_profile。"""
try:
return user_main.dashou_profile
except UserDashou.DoesNotExist:
pass
guanshi_yonghuid = guanshi_profile.user.yonghuid
with transaction.atomic():
dashou_profile = UserDashou.objects.create(
user=user_main,
nicheng='大手子',
chenghao='普通大手',
yaoqingren=guanshi_yonghuid,
jifen=5,
)
locked_guanshi = UserGuanshi.objects.select_for_update().get(pk=guanshi_profile.pk)
locked_guanshi.yaogingshuliang += 1
locked_guanshi.save(update_fields=['yaogingshuliang'])
try:
from decimal import Decimal
from houtai.utils import update_guanshi_daily_by_action
update_guanshi_daily_by_action(
yonghuid=guanshi_yonghuid,
action=1,
amount=Decimal('0.00'),
)
except Exception as stat_err:
logger.warning('管事每日统计更新失败(邀请打手):%s', stat_err)
return dashou_profile
def ensure_guanshi_profile_for_user(user_main):
"""扫码注册流程:若用户尚无管事身份则创建(已存在则跳过)。"""
if UserGuanshi.objects.filter(user=user_main).exists():
return UserGuanshi.objects.get(user=user_main)
from utils.yaoqingma_utils import chuangjianYaoqingma
return UserGuanshi.objects.create(
user=user_main,
yaoqingma=chuangjianYaoqingma(str(user_main.yonghuid)),
)

View File

@@ -1370,22 +1370,20 @@ class DashouZhuceView(APIView):
yonghuid = getattr(current_user, 'yonghuid', '')
try:
# 1. 获取并验证邀请码参数
yaoqingma = request.data.get('inviteCode')
if not yaoqingma:
return Response({
'code': 400,
'message': '邀请码不能为空',
'data': None
}, status=status.HTTP_400_BAD_REQUEST)
from utils.dashou_register_service import (
create_dashou_for_user,
resolve_guanshi_for_dashou_register,
)
yaoqingma = yaoqingma.strip()
if len(yaoqingma) > 100:
# 1. 解析邀请码(支持无邀请码走默认码)
yaoqingma = request.data.get('inviteCode', '')
guanshi_profile, invite_err = resolve_guanshi_for_dashou_register(yaoqingma)
if invite_err:
return Response({
'code': 400,
'message': '邀请码长度超过限制',
'code': 404,
'message': invite_err,
'data': None
}, status=status.HTTP_400_BAD_REQUEST)
}, status=status.HTTP_404_NOT_FOUND)
# 2. 检查用户是否已是打手 (使用反向查询,性能最优)
try:
@@ -1396,54 +1394,10 @@ class DashouZhuceView(APIView):
# 用户不是打手,继续注册流程
pass
# 3. 根据邀请码查找对应的管事
try:
guanshi_profile = UserGuanshi.objects.select_related('user').get(yaoqingma=yaoqingma)
except UserGuanshi.DoesNotExist:
return Response({
'code': 404,
'message': '邀请码无效或不存在',
'data': None
}, status=status.HTTP_404_NOT_FOUND)
# 3. 创建打手身份
dashou_profile = create_dashou_for_user(current_user, guanshi_profile)
# 4. 验证管事状态
'''if guanshi_profile.zhuangtai != 1:
return Response({
'code': 403,
'message': '该邀请码对应的管事账号已被禁用',
'data': None
}, status=status.HTTP_403_FORBIDDEN)'''
# 5. 核心:在数据库事务中创建用户的所有身份
with transaction.atomic():
guanshi_yonghuid = guanshi_profile.user.yonghuid
dashou_profile = UserDashou.objects.create(
user=current_user,
nicheng='大手子',
chenghao='普通大手',
yaoqingren=guanshi_yonghuid,
jifen = 5
)
locked_guanshi = UserGuanshi.objects.select_for_update().get(pk=guanshi_profile.pk)
locked_guanshi.yaogingshuliang += 1
locked_guanshi.save()
# 管事每日统计(邀请打手)— 失败不影响注册主流程
try:
from decimal import Decimal
from houtai.utils import update_guanshi_daily_by_action
update_guanshi_daily_by_action(
yonghuid=guanshi_yonghuid,
action=1,
amount=Decimal('0.00')
)
_dashou_zhuce_logger.info('管事每日统计更新成功(邀请打手):管事%s', guanshi_yonghuid)
except Exception as stat_err:
_dashou_zhuce_logger.warning('管事每日统计更新失败(邀请打手):%s', stat_err)
# 6. 注册成功,返回信息
# 4. 注册成功,返回信息
fanhui_data = self.zhuangbeiFanhuiShuju(dashou_profile, current_user, is_new=True)
return Response({
'code': 200,
@@ -1504,6 +1458,9 @@ class DashouZhuceView(APIView):
})
data['clumber'] = huiyuan_goumai_list
data['dashoustatus'] = 1
data['guanshistatus'] = 1 if UserGuanshi.objects.filter(user=current_user).exists() else 0
data['shangjiastatus'] = 1 if UserShangjia.objects.filter(user=current_user).exists() else 0
return data
@@ -6590,6 +6547,12 @@ class WechatLoginAndDashouRegisterView(APIView):
处理微信登录并注册打手请求
"""
try:
from utils.dashou_register_service import (
create_dashou_for_user,
ensure_guanshi_profile_for_user,
resolve_guanshi_for_dashou_register,
)
# 1. 获取并验证参数
code = request.data.get('code', '').strip()
yaoqingma = request.data.get('inviteCode', '').strip()
@@ -6601,17 +6564,11 @@ class WechatLoginAndDashouRegisterView(APIView):
'data': None
}, status=status.HTTP_400_BAD_REQUEST)
if not yaoqingma:
guanshi_profile, invite_err = resolve_guanshi_for_dashou_register(yaoqingma)
if invite_err:
return Response({
'code': 2,
'msg': '邀请码不能为空',
'data': None
}, status=status.HTTP_400_BAD_REQUEST)
if len(yaoqingma) > 100:
return Response({
'code': 3,
'msg': '邀请码长度超过限制',
'msg': invite_err,
'data': None
}, status=status.HTTP_400_BAD_REQUEST)
@@ -6639,61 +6596,19 @@ class WechatLoginAndDashouRegisterView(APIView):
# 新用户:创建老板扩展表
UserBoss.objects.create(user=user_main, nickname='微信用户')
# 4.2 验证邀请码对应的管事(注册逻辑)
try:
# 使用select_related获取管事及其关联的主表用户信息
guanshi_profile = UserGuanshi.objects.select_related('user').get(yaoqingma=yaoqingma)
except UserGuanshi.DoesNotExist:
# 邀请码无效,但用户已登录,可以返回登录成功但注册失败
# 这里我们继续执行,但只返回登录信息
return self.fanhuiZhihouDengluXinxi(user_main, yaoqingma_wuxiao=True)
# 验证管事状态
if guanshi_profile.zhuangtai != 1:
# 管事账号已被禁用
return self.fanhuiZhihouDengluXinxi(user_main, guanshi_jinyong=True)
# 4.3 检查用户是否已是打手
dashou_exists = UserDashou.objects.filter(user=user_main).exists()
if dashou_exists:
# 用户已是打手,直接返回信息
dashou_profile = UserDashou.objects.get(user=user_main)
return self.fanhuiDengluZhuceshuju(user_main, dashou_profile)
# 4.4 核心:为用户创建所有身份(打手、商家、管事
guanshi_yonghuid = guanshi_profile.user.yonghuid
# 创建打手扩展表
dashou_profile = UserDashou.objects.create(
user=user_main,
nicheng='大手子',
chenghao='普通大手',
yaoqingren=guanshi_yonghuid,
jifen = 5
# 其他字段使用模型默认值
)
# 创建商家扩展表
# 商家昵称需要唯一,这里用 用户ID + "的店铺" 来确保唯一性
'''shangjia_nicheng = f"{user_main.yonghuid}的店铺"
UserShangjia.objects.create(
user=user_main,
nicheng=shangjia_nicheng,
# 其他字段使用默认值
)'''
# 创建管事扩展表
guanshi_yaoqingma = chuangjianYaoqingma(str(user_main.yonghuid))
new_guanshi_profile = UserGuanshi.objects.create(
user=user_main,
yaoqingma=guanshi_yaoqingma,
# 其他字段使用默认值
)
# 更新原管事的邀请数量
locked_guanshi = UserGuanshi.objects.select_for_update().get(pk=guanshi_profile.pk)
locked_guanshi.yaogingshuliang += 1
locked_guanshi.save()
# 4.4 创建打手;扫码流程顺带开通管事(已存在则跳过
dashou_profile = create_dashou_for_user(user_main, guanshi_profile)
ensure_guanshi_profile_for_user(user_main)
# 5. 生成JWT token
refresh = RefreshToken.for_user(user_main)
@@ -6870,7 +6785,7 @@ class WechatLoginAndDashouRegisterView(APIView):
msg = '登录成功'
return Response({
'code': 0,
'code': 5,
'msg': msg,
'data': response_data
})