diff --git a/jituan/management/commands/seed_lsx_invite_data.py b/jituan/management/commands/seed_lsx_invite_data.py index 35cea23..751af86 100644 --- a/jituan/management/commands/seed_lsx_invite_data.py +++ b/jituan/management/commands/seed_lsx_invite_data.py @@ -1,5 +1,12 @@ -"""龙先生电竞(lsx)邀请链种子:自动插入组长+管事(含邀请码),无需先登录小程序。""" -from django.core.management.base import BaseCommand +"""龙先生电竞邀请链种子:插入组长+管事(含邀请码)。 + +默认 club_id=lsx;若找不到会列出库里全部俱乐部,便于核对真实 club_id。 +可用: + python manage.py seed_lsx_invite_data + python manage.py seed_lsx_invite_data --club-id 你的真实id + python manage.py seed_lsx_invite_data --list-clubs +""" +from django.core.management.base import BaseCommand, CommandError from django.db import transaction from jituan.models import Club, ClubHuiyuanPrice @@ -7,7 +14,7 @@ from users.business_models import User from users.models import UserBoss, UserGuanshi, UserZuzhang from utils.invitationcode_utils import CreateInvitationCode -CLUB_ID = 'lsx' +DEFAULT_CLUB_ID = 'lsx' WX_APPID = 'wx7ff90e9d024fcdb8' # 固定种子账号(可重复执行,幂等;UID/手机避开 xzj 的 9900001/2) @@ -27,23 +34,62 @@ SEED_GUANSHI = { } -def _ensure_club(): - """仅检查俱乐部是否已由后台创建;不自动建空俱乐部。""" - if Club.query.filter(club_id=CLUB_ID).exists(): - return - raise SystemExit( - f'俱乐部 {CLUB_ID} 不存在。请先在后台创建龙先生俱乐部并上传证书,' - f'再执行 seed_lsx_invite_data(本命令不再自动 create_club)。' - ) +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(f' mch_id={c.mch_id or "(空)"} withdraw_mch_id={getattr(c, "withdraw_mch_id", "") or "(空)"}') + stdout.write( + f' pay_key_path={c.pay_key_path or "(空)"}' + ) + stdout.write(style.SUCCESS('=' * 60)) + return clubs -def _ensure_user(meta): +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 + + by_name = Club.query.filter(name__icontains='龙先生').order_by('club_id') + names = list(by_name) + if len(names) == 1: + c = names[0] + stdout.write(style.WARNING( + f'按名称「龙先生」命中唯一: club_id={c.club_id!r} name={c.name!r}' + )) + return c + if len(names) > 1: + stdout.write(style.ERROR('名称含「龙先生」的俱乐部有多条,请用 --club-id 指定:')) + for c in names: + 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 != CLUB_ID: - user.ClubID = CLUB_ID + if (user.ClubID or '') != club_id: + user.ClubID = club_id user.save(update_fields=['ClubID']) return user, False @@ -52,15 +98,17 @@ def _ensure_user(meta): UserName=meta['UserName'], OpenID=meta['OpenID'], Phone=meta['Phone'], - ClubID=CLUB_ID, + ClubID=club_id, ) UserBoss.query.create(user=user, nickname=meta['nickname']) return user, True def _ensure_zuzhang(user): - if hasattr(user, 'ZuzhangProfile'): + try: return user.ZuzhangProfile, False + except UserZuzhang.DoesNotExist: + pass yaoqingma = CreateInvitationCode(str(user.UserUID)) z = UserZuzhang.query.create( user=user, @@ -71,8 +119,10 @@ def _ensure_zuzhang(user): def _ensure_guanshi(user, zuzhang_uid): - if hasattr(user, 'GuanshiProfile'): + try: return user.GuanshiProfile, False + except UserGuanshi.DoesNotExist: + pass yaoqingma = CreateInvitationCode(str(user.UserUID)) g = UserGuanshi.query.create( user=user, @@ -84,9 +134,20 @@ def _ensure_guanshi(user, zuzhang_uid): class Command(BaseCommand): - help = '插入龙先生电竞种子组长+管事(含邀请码),一条命令即可邀请注册' + help = '插入龙先生电竞种子组长+管事(含邀请码);找不到俱乐部时会列出全部 club' def add_arguments(self, parser): + parser.add_argument( + '--club-id', + type=str, + default=DEFAULT_CLUB_ID, + help='目标俱乐部 ID(默认 lsx;若后台建的不是 lsx 请改这里)', + ) + parser.add_argument( + '--list-clubs', + action='store_true', + help='只列出库里所有俱乐部,不写入种子', + ) parser.add_argument( '--force-new-codes', action='store_true', @@ -94,25 +155,49 @@ class Command(BaseCommand): ) def handle(self, *args, **options): - with transaction.atomic(): - _ensure_club() + if options.get('list_clubs'): + _list_clubs(self.stdout, self.style) + return - zz_user, zz_new = _ensure_user(SEED_ZUZHANG) + 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( + '可能原因:\n' + ' 1) 后台创建时 club_id 不是 lsx(例如写成了别的拼音)\n' + ' 2) 之前执行过 delete_club_by_mch_id --apply,把 lsx 主表删掉了\n' + '请先看下面列表,用真实 club_id 再跑:\n' + ' python manage.py seed_lsx_invite_data --list-clubs\n' + ' python manage.py seed_lsx_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} 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) + 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() + price_cnt = ClubHuiyuanPrice.query.filter(club_id=club_id).count() self.stdout.write(self.style.SUCCESS('=' * 60)) - self.stdout.write(self.style.SUCCESS('龙先生电竞 lsx 邀请链种子数据已就绪')) + 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('') @@ -124,7 +209,7 @@ class Command(BaseCommand): 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('商家:后台「商家管理 → 添加商家」按用户UID开通') self.stdout.write('') self.stdout.write('新建: 组长=%s 管事=%s' % ( '是' if zz_new or zz_profile_new else '否(已存在)',