避免 staff/订单统计异常导致整次 wechat-login 500;缺俱乐部配置时提示更清晰。 Co-authored-by: Cursor <cursoragent@cursor.com>
224 lines
7.4 KiB
Python
224 lines
7.4 KiB
Python
"""俱乐部微信登录(多 openid 绑定,不修改旧 wechatlogin 逻辑)。"""
|
||
import logging
|
||
import random
|
||
import time
|
||
import uuid
|
||
|
||
from django.db import transaction
|
||
from django.utils import timezone
|
||
from rest_framework_simplejwt.tokens import RefreshToken
|
||
|
||
from jituan.constants import CLUB_ID_DEFAULT
|
||
from jituan.models import UserWxOpenid
|
||
from jituan.services.club_resolver import jscode2session, resolve_club_by_appid
|
||
from jituan.services.club_user import (
|
||
ensure_user_club_id,
|
||
ensure_wx_openid_binding,
|
||
find_user_by_wx_openid,
|
||
resolve_or_create_wx_user,
|
||
)
|
||
from users.business_models import User
|
||
from users.models import UserBoss, UserDashou, UserGuanshi, UserShangjia, UserZuzhang, UserShenheguan
|
||
from gvsdsdk.models import Role
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
|
||
def _generate_user_uid():
|
||
for _ in range(10):
|
||
timestamp_part = str(int(time.time()))[-5:].zfill(5)
|
||
random_part = str(random.randint(0, 99)).zfill(2)
|
||
user_id = timestamp_part + random_part
|
||
if len(user_id) == 7 and user_id.isdigit():
|
||
if not User.query.filter(UserUID=user_id).exists():
|
||
return user_id
|
||
raise RuntimeError('生成用户ID失败')
|
||
|
||
|
||
def _ensure_boss_profile(user):
|
||
try:
|
||
UserBoss.query.get(user=user)
|
||
except UserBoss.DoesNotExist:
|
||
UserBoss.query.create(user=user, nickname='板板大人')
|
||
|
||
|
||
def _ensure_consumer_role(user):
|
||
from users.business_models import UserRole as BizUserRole
|
||
normal_role = Role.objects.filter(RoleName='消费者').first()
|
||
if not normal_role:
|
||
return
|
||
exists = BizUserRole.objects.filter(UserUUID=user.UserUUID, RoleUUID=normal_role.RoleUUID).exists()
|
||
if not exists:
|
||
BizUserRole.objects.create(
|
||
UserRoleUUID=uuid.uuid4().bytes,
|
||
UserUUID=user.UserUUID,
|
||
RoleUUID=normal_role.RoleUUID,
|
||
CompanyUUID=uuid.UUID('b0000000-0000-0000-0000-000000000001').bytes,
|
||
)
|
||
|
||
|
||
def _collect_role_status(user):
|
||
dashou_status = None
|
||
shangjia_status = None
|
||
guanshi_status = None
|
||
zuzhang_status = None
|
||
kaoheguan_status = 0
|
||
boss_nickname = '微信用户'
|
||
|
||
try:
|
||
boss = UserBoss.query.get(user=user)
|
||
boss_nickname = boss.nickname or '微信用户'
|
||
except UserBoss.DoesNotExist:
|
||
pass
|
||
|
||
try:
|
||
UserDashou.query.get(user=user)
|
||
dashou_status = 1
|
||
except UserDashou.DoesNotExist:
|
||
dashou_status = None
|
||
|
||
try:
|
||
UserShangjia.query.get(user=user)
|
||
shangjia_status = 1
|
||
except UserShangjia.DoesNotExist:
|
||
shangjia_status = None
|
||
|
||
try:
|
||
UserGuanshi.query.get(user=user)
|
||
guanshi_status = 1
|
||
except UserGuanshi.DoesNotExist:
|
||
guanshi_status = None
|
||
|
||
try:
|
||
UserZuzhang.query.get(user=user)
|
||
zuzhang_status = 1
|
||
except UserZuzhang.DoesNotExist:
|
||
zuzhang_status = None
|
||
|
||
try:
|
||
kg = UserShenheguan.query.get(user=user)
|
||
kaoheguan_status = 1 if kg.zhuangtai == 1 else 0
|
||
except UserShenheguan.DoesNotExist:
|
||
kaoheguan_status = 0
|
||
|
||
return {
|
||
'dashou_status': dashou_status,
|
||
'shangjia_status': shangjia_status,
|
||
'guanshi_status': guanshi_status,
|
||
'zuzhang_status': zuzhang_status,
|
||
'kaoheguan_status': kaoheguan_status,
|
||
'boss_nickname': boss_nickname,
|
||
}
|
||
|
||
|
||
def login_or_register_by_club(code, club_id=None, app_id=None, client_ip=''):
|
||
"""
|
||
俱乐部微信登录核心逻辑。
|
||
- 通过 user_wx_openid(club_id, openid) 定位用户
|
||
- xq 俱乐部兼容:若绑定不存在但 User.OpenID 已存在,则自动建绑定(不新建用户)
|
||
"""
|
||
wx_data = jscode2session(code, club_id=club_id, app_id=app_id)
|
||
if not wx_data or 'openid' not in wx_data:
|
||
return None, wx_data.get('errmsg', '微信授权失败')
|
||
|
||
openid = wx_data['openid']
|
||
unionid = wx_data.get('unionid', '')
|
||
resolved_club_id = wx_data.get('club_id') or club_id or CLUB_ID_DEFAULT
|
||
|
||
with transaction.atomic():
|
||
binding = UserWxOpenid.query.filter(
|
||
club_id=resolved_club_id, openid=openid
|
||
).first()
|
||
|
||
user = None
|
||
created = False
|
||
|
||
if binding:
|
||
user = User.query.filter(UserUID=binding.yonghuid).first()
|
||
if not user:
|
||
user = User.objects.filter(UserUID=binding.yonghuid).first()
|
||
|
||
if not user:
|
||
user, created = resolve_or_create_wx_user(
|
||
resolved_club_id, openid, _generate_user_uid, unionid=unionid,
|
||
)
|
||
if created:
|
||
_ensure_boss_profile(user)
|
||
_ensure_consumer_role(user)
|
||
else:
|
||
ensure_wx_openid_binding(resolved_club_id, openid, user, unionid)
|
||
|
||
if unionid and unionid != (user.UnionID or ''):
|
||
user.UnionID = unionid
|
||
if client_ip:
|
||
user.IP = client_ip
|
||
user.UserLastLoginDate = timezone.now()
|
||
user.save()
|
||
|
||
ensure_user_club_id(user, resolved_club_id)
|
||
|
||
roles = _collect_role_status(user)
|
||
refresh = RefreshToken.for_user(user)
|
||
token = str(refresh.access_token)
|
||
|
||
staff_fields = {}
|
||
order_counts = {}
|
||
group_info = {}
|
||
try:
|
||
from merchant_ops.services.authz import staff_fields_for_login
|
||
staff_fields = staff_fields_for_login(user) or {}
|
||
except Exception:
|
||
logger.exception('staff_fields_for_login 失败 uid=%s', getattr(user, 'UserUID', ''))
|
||
|
||
try:
|
||
from users.views import WechatMiniProgramLoginView
|
||
login_view = WechatMiniProgramLoginView()
|
||
order_counts = login_view.jisuanOrderShuliang(user.UserUID) or {}
|
||
group_info = login_view.huoquQunPeizhi() or {}
|
||
except Exception:
|
||
logger.exception('登录附属信息失败 uid=%s', getattr(user, 'UserUID', ''))
|
||
|
||
data = {
|
||
'token': token,
|
||
'nicheng': roles['boss_nickname'],
|
||
'uid': user.UserUID,
|
||
'touxiang': user.Avatar or '',
|
||
'shangjiastatus': roles['shangjia_status'],
|
||
'dashoustatus': roles['dashou_status'],
|
||
'guanshistatus': roles['guanshi_status'],
|
||
'zuzhangstatus': roles['zuzhang_status'],
|
||
'kaoheguanstatus': roles['kaoheguan_status'],
|
||
'dingdantiaoshu': order_counts,
|
||
'dashouqun': group_info.get('dashouqun', ''),
|
||
'dashouqunid': group_info.get('dashouqunid', ''),
|
||
'guanshiqun': group_info.get('guanshiqun', ''),
|
||
'guanshiqunid': group_info.get('guanshiqunid', ''),
|
||
'club_id': resolved_club_id,
|
||
'is_new_user': created,
|
||
**staff_fields,
|
||
}
|
||
return data, None
|
||
|
||
|
||
def refresh_wx_openid_binding(code, user, club_id=None, app_id=None):
|
||
"""已登录用户:用当前小程序 code 刷新 user_wx_openid(不换 JWT)。"""
|
||
wx_data = jscode2session(code, club_id=club_id, app_id=app_id)
|
||
if not wx_data or 'openid' not in wx_data:
|
||
return None, wx_data.get('errmsg', '微信授权失败')
|
||
|
||
openid = wx_data['openid']
|
||
unionid = wx_data.get('unionid', '')
|
||
resolved_club_id = wx_data.get('club_id') or club_id or CLUB_ID_DEFAULT
|
||
|
||
ensure_wx_openid_binding(resolved_club_id, openid, user, unionid)
|
||
ensure_user_club_id(user, resolved_club_id)
|
||
if unionid and unionid != (getattr(user, 'UnionID', None) or ''):
|
||
user.UnionID = unionid
|
||
user.save(update_fields=['UnionID'])
|
||
|
||
return {
|
||
'club_id': resolved_club_id,
|
||
'openid_preview': openid[:6] + '...' + openid[-4:] if len(openid) > 10 else openid,
|
||
'wx_appid': wx_data.get('wx_appid', ''),
|
||
}, None
|