feat: 新增小汐电竞种子组长/管事命令 seed_xx_invite_data
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
223
jituan/management/commands/seed_xx_invite_data.py
Normal file
223
jituan/management/commands/seed_xx_invite_data.py
Normal file
@@ -0,0 +1,223 @@
|
||||
"""小汐电竞邀请链种子:插入组长+管事(含邀请码)。
|
||||
|
||||
默认 club_id=xx;找不到会列出全部俱乐部。
|
||||
可用:
|
||||
python manage.py seed_xx_invite_data
|
||||
python manage.py seed_xx_invite_data --club-id xx
|
||||
python manage.py seed_xx_invite_data --list-clubs
|
||||
"""
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.db import transaction
|
||||
|
||||
from jituan.models import Club, ClubHuiyuanPrice
|
||||
from users.business_models import User
|
||||
from users.models import UserBoss, UserGuanshi, UserZuzhang
|
||||
from utils.invitationcode_utils import CreateInvitationCode
|
||||
|
||||
DEFAULT_CLUB_ID = 'xx'
|
||||
WX_APPID = 'wx0d445b76f93774fa'
|
||||
NAME_HINTS = ('小汐', '小溪', '小西')
|
||||
|
||||
# 固定种子账号(可重复执行,幂等;UID/手机避开 xzj 990000x、lsx 991000x)
|
||||
SEED_ZUZHANG = {
|
||||
'UserUID': '9920001',
|
||||
'OpenID': 'xx_seed_openid_zuzhang_v1',
|
||||
'Phone': '19920000001',
|
||||
'UserName': 'xx_seed_zuzhang',
|
||||
'nickname': '小汐种子组长',
|
||||
}
|
||||
SEED_GUANSHI = {
|
||||
'UserUID': '9920002',
|
||||
'OpenID': 'xx_seed_openid_guanshi_v1',
|
||||
'Phone': '19920000002',
|
||||
'UserName': 'xx_seed_guanshi',
|
||||
'nickname': '小汐种子管事',
|
||||
}
|
||||
|
||||
|
||||
def _list_clubs(stdout, style):
|
||||
clubs = list(Club.query.order_by('sort_order', 'club_id'))
|
||||
stdout.write(style.SUCCESS('=' * 60))
|
||||
stdout.write(f'库里俱乐部共 {len(clubs)} 个:')
|
||||
for c in clubs:
|
||||
stdout.write('-' * 40)
|
||||
stdout.write(f' club_id={c.club_id!r} name={c.name!r} status={c.status}')
|
||||
stdout.write(f' wx_appid={c.wx_appid or "(空)"}')
|
||||
stdout.write(style.SUCCESS('=' * 60))
|
||||
return clubs
|
||||
|
||||
|
||||
def _resolve_club(club_id: str, stdout, style):
|
||||
"""优先精确 club_id;其次 wx_appid;再名称含小汐/小溪/小西。"""
|
||||
cid = (club_id or DEFAULT_CLUB_ID).strip()
|
||||
club = Club.query.filter(club_id=cid).first()
|
||||
if club:
|
||||
return club
|
||||
|
||||
stdout.write(style.WARNING(f'精确 club_id={cid!r} 不存在,尝试按 AppID/名称匹配…'))
|
||||
|
||||
by_app = Club.query.filter(wx_appid=WX_APPID).first()
|
||||
if by_app:
|
||||
stdout.write(style.WARNING(
|
||||
f'按 wx_appid={WX_APPID} 命中: club_id={by_app.club_id!r} name={by_app.name!r}'
|
||||
))
|
||||
return by_app
|
||||
|
||||
hits = []
|
||||
for hint in NAME_HINTS:
|
||||
hits.extend(list(Club.query.filter(name__icontains=hint)))
|
||||
# 去重
|
||||
seen = set()
|
||||
unique = []
|
||||
for c in hits:
|
||||
if c.club_id in seen:
|
||||
continue
|
||||
seen.add(c.club_id)
|
||||
unique.append(c)
|
||||
|
||||
if len(unique) == 1:
|
||||
c = unique[0]
|
||||
stdout.write(style.WARNING(
|
||||
f'按名称命中唯一: club_id={c.club_id!r} name={c.name!r}'
|
||||
))
|
||||
return c
|
||||
if len(unique) > 1:
|
||||
stdout.write(style.ERROR('名称匹配到多条,请用 --club-id 指定:'))
|
||||
for c in unique:
|
||||
stdout.write(f' - {c.club_id!r} / {c.name!r}')
|
||||
return None
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def _ensure_user(meta, club_id):
|
||||
user = User.query.filter(UserUID=meta['UserUID']).first()
|
||||
if not user:
|
||||
user = User.query.filter(OpenID=meta['OpenID']).first()
|
||||
if user:
|
||||
if (user.ClubID or '') != club_id:
|
||||
user.ClubID = club_id
|
||||
user.save(update_fields=['ClubID'])
|
||||
return user, False
|
||||
|
||||
user = User.query.create(
|
||||
UserUID=meta['UserUID'],
|
||||
UserName=meta['UserName'],
|
||||
OpenID=meta['OpenID'],
|
||||
Phone=meta['Phone'],
|
||||
ClubID=club_id,
|
||||
)
|
||||
UserBoss.query.create(user=user, nickname=meta['nickname'])
|
||||
return user, True
|
||||
|
||||
|
||||
def _ensure_zuzhang(user):
|
||||
try:
|
||||
return user.ZuzhangProfile, False
|
||||
except UserZuzhang.DoesNotExist:
|
||||
pass
|
||||
yaoqingma = CreateInvitationCode(str(user.UserUID))
|
||||
z = UserZuzhang.query.create(
|
||||
user=user,
|
||||
yaoqingma=yaoqingma,
|
||||
zhuangtai=1,
|
||||
)
|
||||
return z, True
|
||||
|
||||
|
||||
def _ensure_guanshi(user, zuzhang_uid):
|
||||
try:
|
||||
return user.GuanshiProfile, False
|
||||
except UserGuanshi.DoesNotExist:
|
||||
pass
|
||||
yaoqingma = CreateInvitationCode(str(user.UserUID))
|
||||
g = UserGuanshi.query.create(
|
||||
user=user,
|
||||
yaoqingma=yaoqingma,
|
||||
yaoqingren=zuzhang_uid,
|
||||
zhuangtai=1,
|
||||
)
|
||||
return g, True
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = '插入小汐电竞种子组长+管事(含邀请码);找不到俱乐部时会列出全部 club'
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
'--club-id',
|
||||
type=str,
|
||||
default=DEFAULT_CLUB_ID,
|
||||
help='目标俱乐部 ID(默认 xx)',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--list-clubs',
|
||||
action='store_true',
|
||||
help='只列出库里所有俱乐部,不写入种子',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--force-new-codes',
|
||||
action='store_true',
|
||||
help='已存在时重新生成邀请码(慎用)',
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
if options.get('list_clubs'):
|
||||
_list_clubs(self.stdout, self.style)
|
||||
return
|
||||
|
||||
want_id = (options.get('club_id') or DEFAULT_CLUB_ID).strip()
|
||||
club = _resolve_club(want_id, self.stdout, self.style)
|
||||
if club is None:
|
||||
self.stdout.write(self.style.ERROR(
|
||||
f'找不到可用俱乐部(请求 club_id={want_id!r})。'
|
||||
))
|
||||
self.stdout.write(self.style.WARNING(
|
||||
'请先在后台创建小汐俱乐部(club_id=xx),或:\n'
|
||||
' python manage.py seed_xx_invite_data --list-clubs\n'
|
||||
' python manage.py seed_xx_invite_data --club-id 真实id'
|
||||
))
|
||||
_list_clubs(self.stdout, self.style)
|
||||
raise CommandError('俱乐部不存在,已中止(未写入任何种子)')
|
||||
|
||||
club_id = club.club_id
|
||||
self.stdout.write(self.style.SUCCESS(
|
||||
f'将写入种子到俱乐部: club_id={club_id!r} name={club.name!r} '
|
||||
f'wx_appid={club.wx_appid or "(空)"}'
|
||||
))
|
||||
|
||||
with transaction.atomic():
|
||||
zz_user, zz_new = _ensure_user(SEED_ZUZHANG, club_id)
|
||||
zz_profile, zz_profile_new = _ensure_zuzhang(zz_user)
|
||||
if options.get('force_new_codes') and not zz_profile_new:
|
||||
zz_profile.yaoqingma = CreateInvitationCode(str(zz_user.UserUID))
|
||||
zz_profile.save(update_fields=['yaoqingma'])
|
||||
|
||||
gs_user, gs_new = _ensure_user(SEED_GUANSHI, club_id)
|
||||
gs_profile, gs_profile_new = _ensure_guanshi(gs_user, zz_user.UserUID)
|
||||
if options.get('force_new_codes') and not gs_profile_new:
|
||||
gs_profile.yaoqingma = CreateInvitationCode(str(gs_user.UserUID))
|
||||
gs_profile.save(update_fields=['yaoqingma'])
|
||||
|
||||
price_cnt = ClubHuiyuanPrice.query.filter(club_id=club_id).count()
|
||||
|
||||
self.stdout.write(self.style.SUCCESS('=' * 60))
|
||||
self.stdout.write(self.style.SUCCESS(f'小汐电竞邀请链种子已就绪(club_id={club_id})'))
|
||||
self.stdout.write(self.style.SUCCESS('=' * 60))
|
||||
self.stdout.write(f'club_huiyuan_price 条数: {price_cnt}')
|
||||
self.stdout.write('')
|
||||
self.stdout.write('【组长】管事注册用这个邀请码(guanshizhuce):')
|
||||
self.stdout.write(f' UserUID={zz_user.UserUID} Phone={SEED_ZUZHANG["Phone"]}')
|
||||
self.stdout.write(f' 组长邀请码 inviteCode = {zz_profile.yaoqingma}')
|
||||
self.stdout.write('')
|
||||
self.stdout.write('【管事】打手/接单员注册用这个邀请码(dashouzhuce):')
|
||||
self.stdout.write(f' UserUID={gs_user.UserUID} Phone={SEED_GUANSHI["Phone"]}')
|
||||
self.stdout.write(f' 管事邀请码 inviteCode = {gs_profile.yaoqingma}')
|
||||
self.stdout.write('')
|
||||
self.stdout.write('商家:后台「商家管理 → 添加商家」按用户UID开通')
|
||||
self.stdout.write('')
|
||||
self.stdout.write('新建: 组长=%s 管事=%s' % (
|
||||
'是' if zz_new or zz_profile_new else '否(已存在)',
|
||||
'是' if gs_new or gs_profile_new else '否(已存在)',
|
||||
))
|
||||
self.stdout.write(self.style.SUCCESS('=' * 60))
|
||||
Reference in New Issue
Block a user