feat(jituan): 集团多俱乐部改造 — club 隔离、财务/提现/分红/展示配置
This commit is contained in:
0
jituan/management/__init__.py
Normal file
0
jituan/management/__init__.py
Normal file
0
jituan/management/commands/__init__.py
Normal file
0
jituan/management/commands/__init__.py
Normal file
47
jituan/management/commands/backfill_display_club_id.py
Normal file
47
jituan/management/commands/backfill_display_club_id.py
Normal file
@@ -0,0 +1,47 @@
|
||||
"""回填 lunbo / gonggao / popup_page / tupianpeizhi 的 club_id 与 lunbo.page_key。"""
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db import transaction
|
||||
|
||||
from jituan.constants import CLUB_ID_DEFAULT
|
||||
from config.models import Gonggao, Lunbo, PopupPage, Tupianpeizhi
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = '回填展示配置表的 club_id,并为 lunbo 补 page_key'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
updated = {'lunbo_club': 0, 'lunbo_page': 0, 'gonggao': 0, 'popup': 0, 'tupian': 0}
|
||||
|
||||
with transaction.atomic():
|
||||
for row in Lunbo.query.all().only('id', 'club_id', 'page_key', 'ImageType'):
|
||||
fields = []
|
||||
if not row.club_id:
|
||||
row.club_id = CLUB_ID_DEFAULT
|
||||
fields.append('club_id')
|
||||
updated['lunbo_club'] += 1
|
||||
if not row.page_key:
|
||||
if row.ImageType == 2:
|
||||
row.page_key = 'dashou_center'
|
||||
else:
|
||||
row.page_key = 'order_pool'
|
||||
fields.append('page_key')
|
||||
updated['lunbo_page'] += 1
|
||||
if fields:
|
||||
row.save(update_fields=fields)
|
||||
|
||||
for row in Gonggao.query.filter(club_id='').only('id', 'club_id'):
|
||||
Gonggao.query.filter(id=row.id).update(club_id=CLUB_ID_DEFAULT)
|
||||
updated['gonggao'] += 1
|
||||
|
||||
for row in PopupPage.query.filter(club_id='').only('id', 'club_id'):
|
||||
PopupPage.query.filter(id=row.id).update(club_id=CLUB_ID_DEFAULT)
|
||||
updated['popup'] += 1
|
||||
|
||||
for row in Tupianpeizhi.query.filter(club_id='').only('id', 'club_id'):
|
||||
Tupianpeizhi.query.filter(id=row.id).update(club_id=CLUB_ID_DEFAULT)
|
||||
updated['tupian'] += 1
|
||||
|
||||
self.stdout.write(self.style.SUCCESS(
|
||||
f'回填完成: lunbo_club={updated["lunbo_club"]}, lunbo_page={updated["lunbo_page"]}, '
|
||||
f'gonggao={updated["gonggao"]}, popup={updated["popup"]}, tupian={updated["tupian"]}'
|
||||
))
|
||||
23
jituan/management/commands/backfill_gsfenhong_club_id.py
Normal file
23
jituan/management/commands/backfill_gsfenhong_club_id.py
Normal file
@@ -0,0 +1,23 @@
|
||||
"""按充值订单 / 订单 / 用户回填 gsfenhong.club_id。"""
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db import transaction
|
||||
|
||||
from jituan.constants import CLUB_ID_DEFAULT
|
||||
from jituan.services.club_penalty import resolve_gsfenhong_club_id
|
||||
from products.models import Gsfenhong
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = '回填 gsfenhong.club_id'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
updated = 0
|
||||
with transaction.atomic():
|
||||
for row in Gsfenhong.query.all().only('dingdan_id', 'dashouid', 'club_id'):
|
||||
cid = resolve_gsfenhong_club_id(dingdan_id=row.dingdan_id, dashouid=row.dashouid)
|
||||
if not cid:
|
||||
cid = CLUB_ID_DEFAULT
|
||||
if row.club_id != cid:
|
||||
Gsfenhong.query.filter(dingdan_id=row.dingdan_id).update(club_id=cid)
|
||||
updated += 1
|
||||
self.stdout.write(self.style.SUCCESS(f'gsfenhong club_id 更新 {updated} 条'))
|
||||
42
jituan/management/commands/backfill_penalty_club_id.py
Normal file
42
jituan/management/commands/backfill_penalty_club_id.py
Normal file
@@ -0,0 +1,42 @@
|
||||
"""回填罚单 club_id(从关联订单或被罚用户)。"""
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db import transaction
|
||||
|
||||
from jituan.constants import CLUB_ID_DEFAULT
|
||||
from jituan.services.club_penalty import resolve_penalty_club_id
|
||||
from orders.models import Order, Penalty
|
||||
from users.business_models import User
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = '按关联订单/被罚用户回填 fadan.club_id(默认仅处理仍为 xq 的记录)'
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument('--all', action='store_true', help='重算全部罚单(慎用)')
|
||||
parser.add_argument('--dry-run', action='store_true')
|
||||
|
||||
def handle(self, *args, **options):
|
||||
dry = options['dry_run']
|
||||
qs = Penalty.query.all()
|
||||
if not options['all']:
|
||||
qs = qs.filter(ClubID=CLUB_ID_DEFAULT)
|
||||
|
||||
updated = 0
|
||||
with transaction.atomic():
|
||||
for p in qs.iterator():
|
||||
order = None
|
||||
if p.RelatedOrderID:
|
||||
order = Order.query.filter(OrderID=p.RelatedOrderID).first()
|
||||
cid = resolve_penalty_club_id(
|
||||
order=order,
|
||||
penalized_user_id=p.PenalizedUserID,
|
||||
)
|
||||
if cid and cid != p.ClubID:
|
||||
if dry:
|
||||
self.stdout.write(f'would update penalty {p.id}: {p.ClubID} -> {cid}')
|
||||
else:
|
||||
p.ClubID = cid
|
||||
p.save(update_fields=['ClubID'])
|
||||
updated += 1
|
||||
|
||||
self.stdout.write(self.style.SUCCESS(f'罚单 club_id 更新 {updated} 条'))
|
||||
@@ -0,0 +1,35 @@
|
||||
"""回填 chufajilu / duoci_fenhong club_id。"""
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db import transaction
|
||||
|
||||
from jituan.constants import CLUB_ID_DEFAULT
|
||||
from jituan.services.club_penalty import resolve_gsfenhong_club_id, resolve_penalty_record_club_id
|
||||
from orders.models import PenaltyRecord
|
||||
from products.models import DuociFenhong
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = '回填 PenaltyRecord / DuociFenhong 的 club_id'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
pr_updated = 0
|
||||
df_updated = 0
|
||||
with transaction.atomic():
|
||||
for row in PenaltyRecord.query.all().only('id', 'OrderID', 'PlayerID', 'ClubID'):
|
||||
cid = resolve_penalty_record_club_id(order_id=row.OrderID, player_id=row.PlayerID)
|
||||
if row.ClubID != cid:
|
||||
PenaltyRecord.query.filter(id=row.id).update(ClubID=cid)
|
||||
pr_updated += 1
|
||||
for row in DuociFenhong.query.all().only('huiyuan', 'yonghuid', 'cishu', 'club_id'):
|
||||
cid = resolve_gsfenhong_club_id(dashouid=row.yonghuid) or CLUB_ID_DEFAULT
|
||||
if row.club_id != cid:
|
||||
DuociFenhong.query.filter(
|
||||
club_id=row.club_id,
|
||||
huiyuan=row.huiyuan,
|
||||
yonghuid=row.yonghuid,
|
||||
cishu=row.cishu,
|
||||
).update(club_id=cid)
|
||||
df_updated += 1
|
||||
self.stdout.write(self.style.SUCCESS(
|
||||
f'PenaltyRecord={pr_updated}, DuociFenhong={df_updated}'
|
||||
))
|
||||
36
jituan/management/commands/backfill_role_daily_club_id.py
Normal file
36
jituan/management/commands/backfill_role_daily_club_id.py
Normal file
@@ -0,0 +1,36 @@
|
||||
"""回填角色日统计 club_id(按用户归属俱乐部)。"""
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db import transaction
|
||||
|
||||
from backend.models import (
|
||||
LeaderDailyStats,
|
||||
ManagerDailyStats,
|
||||
ManagerRenewalDailyStats,
|
||||
MerchantDailyStats,
|
||||
PlayerDailyStats,
|
||||
)
|
||||
from backend.utils import _club_id_for_yonghuid
|
||||
|
||||
|
||||
MODELS = [
|
||||
(MerchantDailyStats, 'MerchantID'),
|
||||
(PlayerDailyStats, 'PlayerID'),
|
||||
(LeaderDailyStats, 'LeaderID'),
|
||||
(ManagerDailyStats, 'ManagerID'),
|
||||
(ManagerRenewalDailyStats, 'ManagerID'),
|
||||
]
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = '回填 5 张角色日统计表的 club_id'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
updated = 0
|
||||
with transaction.atomic():
|
||||
for model, uid_field in MODELS:
|
||||
for row in model.query.all().only('id', uid_field, 'club_id'):
|
||||
cid = _club_id_for_yonghuid(getattr(row, uid_field))
|
||||
if row.club_id != cid:
|
||||
model.query.filter(id=row.id).update(club_id=cid)
|
||||
updated += 1
|
||||
self.stdout.write(self.style.SUCCESS(f'角色日统计 club_id 更新 {updated} 条'))
|
||||
42
jituan/management/commands/backfill_tixian_club_id.py
Normal file
42
jituan/management/commands/backfill_tixian_club_id.py
Normal file
@@ -0,0 +1,42 @@
|
||||
"""按用户 ClubID 回填提现流水 club_id。"""
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db import transaction
|
||||
|
||||
from jituan.constants import CLUB_ID_DEFAULT
|
||||
from jituan.services.club_user import get_user_club_id
|
||||
from users.business_models import User
|
||||
from users.models import TixianAutoRecord, Tixianjilu, TixianShenheJilu
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = '回填 tixianjilu / tixian_shenhe_jilu / tixian_auto_record 的 club_id'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
uid_club = {}
|
||||
for u in User.query.all().only('UserUID', 'ClubID'):
|
||||
uid_club[u.UserUID] = get_user_club_id(u)
|
||||
|
||||
updated = {'jilu': 0, 'shenhe': 0, 'auto': 0}
|
||||
|
||||
with transaction.atomic():
|
||||
for row in Tixianjilu.query.all().only('id', 'yonghuid', 'club_id'):
|
||||
cid = uid_club.get(row.yonghuid) or CLUB_ID_DEFAULT
|
||||
if row.club_id != cid:
|
||||
Tixianjilu.query.filter(id=row.id).update(club_id=cid)
|
||||
updated['jilu'] += 1
|
||||
|
||||
for row in TixianShenheJilu.query.all().only('id', 'yonghuid', 'club_id'):
|
||||
cid = uid_club.get(row.yonghuid) or CLUB_ID_DEFAULT
|
||||
if row.club_id != cid:
|
||||
TixianShenheJilu.query.filter(id=row.id).update(club_id=cid)
|
||||
updated['shenhe'] += 1
|
||||
|
||||
for row in TixianAutoRecord.query.all().only('id', 'yonghuid', 'club_id'):
|
||||
cid = uid_club.get(row.yonghuid) or CLUB_ID_DEFAULT
|
||||
if row.club_id != cid:
|
||||
TixianAutoRecord.query.filter(id=row.id).update(club_id=cid)
|
||||
updated['auto'] += 1
|
||||
|
||||
self.stdout.write(self.style.SUCCESS(
|
||||
f'回填完成: jilu={updated["jilu"]}, shenhe={updated["shenhe"]}, auto={updated["auto"]}'
|
||||
))
|
||||
53
jituan/management/commands/backfill_user_club_id.py
Normal file
53
jituan/management/commands/backfill_user_club_id.py
Normal file
@@ -0,0 +1,53 @@
|
||||
"""回填用户 ClubID(缺省或空时设为 xq 或 user_wx_openid 绑定)。"""
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db import transaction
|
||||
|
||||
from jituan.constants import CLUB_ID_DEFAULT
|
||||
from jituan.models import UserWxOpenid
|
||||
from users.business_models import User
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = '回填 User.ClubID:OpenID 绑定 → user_wx_openid,否则默认 xq'
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
'--dry-run',
|
||||
action='store_true',
|
||||
help='仅统计不落库',
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
dry_run = options.get('dry_run', False)
|
||||
updated = 0
|
||||
skipped = 0
|
||||
|
||||
users = User.query.all()
|
||||
for user in users:
|
||||
current = getattr(user, 'ClubID', None) or ''
|
||||
if current and current != CLUB_ID_DEFAULT:
|
||||
skipped += 1
|
||||
continue
|
||||
|
||||
new_club = CLUB_ID_DEFAULT
|
||||
if user.OpenID:
|
||||
binding = UserWxOpenid.query.filter(openid=user.OpenID).order_by('id').first()
|
||||
if binding:
|
||||
new_club = binding.club_id
|
||||
|
||||
if current == new_club:
|
||||
skipped += 1
|
||||
continue
|
||||
|
||||
if dry_run:
|
||||
self.stdout.write(f'[dry-run] {user.UserUID} -> ClubID={new_club}')
|
||||
updated += 1
|
||||
continue
|
||||
|
||||
with transaction.atomic():
|
||||
user.ClubID = new_club
|
||||
user.save(update_fields=['ClubID'])
|
||||
updated += 1
|
||||
|
||||
suffix = '(dry-run)' if dry_run else ''
|
||||
self.stdout.write(self.style.SUCCESS(f'完成{suffix}:更新 {updated},跳过 {skipped}'))
|
||||
104
jituan/management/commands/create_club.py
Normal file
104
jituan/management/commands/create_club.py
Normal file
@@ -0,0 +1,104 @@
|
||||
"""从 xq 模板复制配置,创建新子公司俱乐部。"""
|
||||
from decimal import Decimal
|
||||
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.db import transaction
|
||||
|
||||
from jituan.constants import CLUB_ID_DEFAULT
|
||||
from jituan.models import Club, ClubHuiyuanPrice, ClubLilubiao, ClubTixianQuota, ClubWithdrawConfig
|
||||
from jituan.services.szjilu_accounting import normalize_szjilu_club_id
|
||||
from jituan.services.display_config import copy_display_config
|
||||
from config.models import Szjilu
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = '从 xq 复制支付/会员价/利率配置,创建新俱乐部'
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument('club_id', type=str, help='新俱乐部 ID,如 xy')
|
||||
parser.add_argument('--name', type=str, required=True, help='展示名称')
|
||||
parser.add_argument('--wx-appid', type=str, default='', help='小程序 appid')
|
||||
parser.add_argument('--from-club', type=str, default=CLUB_ID_DEFAULT, help='模板俱乐部')
|
||||
|
||||
def handle(self, *args, **options):
|
||||
new_id = (options['club_id'] or '').strip()
|
||||
name = (options['name'] or '').strip()
|
||||
template_id = normalize_szjilu_club_id(options.get('from_club'))
|
||||
|
||||
if not new_id or len(new_id) > 16:
|
||||
raise CommandError('club_id 无效')
|
||||
if new_id == template_id:
|
||||
raise CommandError('新 club_id 不能与模板相同')
|
||||
|
||||
try:
|
||||
template = Club.query.get(club_id=template_id)
|
||||
except Club.DoesNotExist:
|
||||
raise CommandError(f'模板俱乐部 {template_id} 不存在,请先 seed_club_xq')
|
||||
|
||||
with transaction.atomic():
|
||||
if Club.query.filter(club_id=new_id).exists():
|
||||
raise CommandError(f'俱乐部 {new_id} 已存在')
|
||||
|
||||
Club.query.create(
|
||||
club_id=new_id,
|
||||
name=name,
|
||||
status=1,
|
||||
wx_appid=options.get('wx_appid') or template.wx_appid,
|
||||
wx_secret=template.wx_secret,
|
||||
mch_id=template.mch_id,
|
||||
pay_app_id=template.pay_app_id or options.get('wx_appid') or template.wx_appid,
|
||||
api_v3_key=template.api_v3_key,
|
||||
cert_serial_no=template.cert_serial_no,
|
||||
private_key_path=template.private_key_path,
|
||||
platform_cert_dir=template.platform_cert_dir,
|
||||
official_appid=template.official_appid,
|
||||
official_secret=template.official_secret,
|
||||
official_token=template.official_token,
|
||||
encoding_aes_key=template.encoding_aes_key,
|
||||
template_id=template.template_id,
|
||||
template_max_per_minute=template.template_max_per_minute,
|
||||
h5_domain=template.h5_domain,
|
||||
oss_prefix=template.oss_prefix or new_id,
|
||||
goeasy_appkey=template.goeasy_appkey,
|
||||
goeasy_secret=template.goeasy_secret,
|
||||
config_json=dict(template.config_json or {}),
|
||||
sort_order=template.sort_order + 1,
|
||||
)
|
||||
|
||||
for row in ClubHuiyuanPrice.query.filter(club_id=template_id):
|
||||
ClubHuiyuanPrice.query.create(
|
||||
club_id=new_id,
|
||||
huiyuan_id=row.huiyuan_id,
|
||||
jiage=row.jiage or Decimal('0'),
|
||||
guanshifc=row.guanshifc or Decimal('0'),
|
||||
zuzhangfc=row.zuzhangfc or Decimal('0'),
|
||||
is_enabled=row.is_enabled,
|
||||
bankuai_id=row.bankuai_id,
|
||||
)
|
||||
|
||||
for row in ClubLilubiao.query.filter(club_id=template_id):
|
||||
ClubLilubiao.query.create(
|
||||
club_id=new_id,
|
||||
config_type=row.config_type,
|
||||
lilv=row.lilv or Decimal('0'),
|
||||
remark=row.remark or '',
|
||||
)
|
||||
|
||||
try:
|
||||
tpl_wd = ClubWithdrawConfig.query.get(club_id=template_id)
|
||||
ClubWithdrawConfig.query.create(club_id=new_id, mode=tpl_wd.mode)
|
||||
except ClubWithdrawConfig.DoesNotExist:
|
||||
ClubWithdrawConfig.query.create(club_id=new_id, mode=1)
|
||||
|
||||
for row in ClubTixianQuota.query.filter(club_id=template_id):
|
||||
ClubTixianQuota.query.create(
|
||||
club_id=new_id,
|
||||
leixing=row.leixing,
|
||||
daily_limit=row.daily_limit or Decimal('0'),
|
||||
)
|
||||
|
||||
Szjilu.objects.get_or_create(club_id=new_id)
|
||||
|
||||
copy_display_config(template_id, new_id)
|
||||
|
||||
self.stdout.write(self.style.SUCCESS(f'俱乐部 {new_id} ({name}) 已创建,配置自 {template_id} 复制'))
|
||||
65
jituan/management/commands/seed_admin_assignments.py
Normal file
65
jituan/management/commands/seed_admin_assignments.py
Normal file
@@ -0,0 +1,65 @@
|
||||
"""为后台客服账号初始化 admin_assignment(数据范围,非功能权限)。"""
|
||||
import logging
|
||||
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db import transaction
|
||||
|
||||
from jituan.constants import CLUB_ID_DEFAULT, DATA_SCOPE_SINGLE, ADMIN_ROLE_LABELS
|
||||
from jituan.models import AdminAssignment
|
||||
from users.business_models import User
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = '为 kefu 账号创建默认子公司任职(club=xq, CLUB_ADMIN);超管可不建 assignment'
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
'--club-id', default=CLUB_ID_DEFAULT, help='目标俱乐部 ID,默认 xq',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--role-code', default='CLUB_ADMIN', help='任职角色码',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--dry-run', action='store_true', help='只打印不写入',
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
club_id = options['club_id']
|
||||
role_code = options['role_code']
|
||||
dry_run = options['dry_run']
|
||||
|
||||
kefu_users = User.query.filter(UserType='kefu')
|
||||
created = 0
|
||||
skipped = 0
|
||||
|
||||
with transaction.atomic():
|
||||
for u in kefu_users:
|
||||
if u.IsSuperuser:
|
||||
skipped += 1
|
||||
continue
|
||||
exists = AdminAssignment.query.filter(
|
||||
yonghuid=u.UserUID, club_id=club_id, role_code=role_code,
|
||||
).exists()
|
||||
if exists:
|
||||
skipped += 1
|
||||
continue
|
||||
if dry_run:
|
||||
self.stdout.write(f'would assign {u.UserUID} -> {club_id} {role_code}')
|
||||
created += 1
|
||||
continue
|
||||
AdminAssignment.query.create(
|
||||
yonghuid=u.UserUID,
|
||||
club_id=club_id,
|
||||
role_code=role_code,
|
||||
data_scope=DATA_SCOPE_SINGLE,
|
||||
is_primary=True,
|
||||
status=1,
|
||||
)
|
||||
created += 1
|
||||
|
||||
label = ADMIN_ROLE_LABELS.get(role_code, role_code)
|
||||
self.stdout.write(self.style.SUCCESS(
|
||||
f'完成:新建 {created} 条,跳过 {skipped} 条(club={club_id}, role={label})'
|
||||
))
|
||||
183
jituan/management/commands/seed_club_xq.py
Normal file
183
jituan/management/commands/seed_club_xq.py
Normal file
@@ -0,0 +1,183 @@
|
||||
"""从现网配置初始化 xq 俱乐部及覆盖表。"""
|
||||
import logging
|
||||
from decimal import Decimal
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db import transaction
|
||||
|
||||
from jituan.constants import CLUB_ID_DEFAULT
|
||||
from jituan.models import (
|
||||
Club,
|
||||
ClubHuiyuanPrice,
|
||||
ClubLilubiao,
|
||||
ClubWithdrawConfig,
|
||||
UserWxOpenid,
|
||||
)
|
||||
from users.business_models import User
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = '初始化星阙(xq)俱乐部主数据,并从 huiyuan/lilubiao 复制覆盖配置'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
with transaction.atomic():
|
||||
club, created = self._ensure_club_xq()
|
||||
self.stdout.write(self.style.SUCCESS(
|
||||
f'club xq: {"新建" if created else "已存在"}'
|
||||
))
|
||||
self._copy_huiyuan_prices()
|
||||
self._copy_lilubiao()
|
||||
self._ensure_withdraw_config()
|
||||
migrated = self._migrate_openid_bindings()
|
||||
self.stdout.write(self.style.SUCCESS(f'user_wx_openid 迁移绑定: {migrated} 条'))
|
||||
|
||||
def _ensure_club_xq(self):
|
||||
wx_v3 = dict(getattr(settings, 'WECHAT_PAY_V3_CONFIG', {}) or {})
|
||||
defaults = {
|
||||
'name': '星阙电竞',
|
||||
'status': 1,
|
||||
'wx_appid': getattr(settings, 'WEIXIN_APPID', ''),
|
||||
'wx_secret': getattr(settings, 'WEIXIN_SECRET', ''),
|
||||
'mch_id': getattr(settings, 'WEIXIN_MCHID', '') or wx_v3.get('MCHID', ''),
|
||||
'pay_app_id': wx_v3.get('APPID', '') or getattr(settings, 'WEIXIN_APPID', ''),
|
||||
'api_v3_key': wx_v3.get('API_V3_KEY', ''),
|
||||
'cert_serial_no': wx_v3.get('CERT_SERIAL_NO', ''),
|
||||
'private_key_path': wx_v3.get('PRIVATE_KEY_PATH', ''),
|
||||
'platform_cert_dir': wx_v3.get('PLATFORM_CERT_DIR', ''),
|
||||
'config_json': {
|
||||
'mch_key': getattr(settings, 'WEIXIN_SHANGHUMIYAO', ''),
|
||||
'transfer_scene_id': wx_v3.get('TRANSFER_SCENE_ID', '1005'),
|
||||
},
|
||||
'official_appid': getattr(settings, 'WEIXIN_OFFICIAL_APPID', ''),
|
||||
'official_secret': getattr(settings, 'WEIXIN_OFFICIAL_SECRET', ''),
|
||||
'official_token': getattr(settings, 'WEIXIN_OFFICIAL_TOKEN', ''),
|
||||
'encoding_aes_key': getattr(settings, 'WEIXIN_OFFICIAL_ENCODING_AES_KEY', ''),
|
||||
'template_id': getattr(settings, 'WEIXIN_TEMPLATE_ID', ''),
|
||||
'template_max_per_minute': getattr(settings, 'WEIXIN_TEMPLATE_MAX_PER_MINUTE', 950),
|
||||
'h5_domain': getattr(settings, 'H5_DOMAIN', ''),
|
||||
'goeasy_appkey': getattr(settings, 'GOEASY_APPKEY', ''),
|
||||
'goeasy_secret': getattr(settings, 'GOEASY_SECRET', ''),
|
||||
'sort_order': 0,
|
||||
}
|
||||
try:
|
||||
club = Club.query.get(club_id=CLUB_ID_DEFAULT)
|
||||
for k, v in defaults.items():
|
||||
if k == 'config_json':
|
||||
merged = dict(club.config_json or {})
|
||||
for ck, cv in v.items():
|
||||
if cv and not merged.get(ck):
|
||||
merged[ck] = cv
|
||||
club.config_json = merged
|
||||
continue
|
||||
if v and not getattr(club, k, None):
|
||||
setattr(club, k, v)
|
||||
# V3 字段允许用 settings 补全(证书路径等)
|
||||
for field in ('api_v3_key', 'cert_serial_no', 'private_key_path', 'platform_cert_dir', 'pay_app_id'):
|
||||
val = defaults.get(field)
|
||||
if val and not getattr(club, field, None):
|
||||
setattr(club, field, val)
|
||||
club.save()
|
||||
return club, False
|
||||
except Club.DoesNotExist:
|
||||
club = Club.query.create(club_id=CLUB_ID_DEFAULT, **defaults)
|
||||
return club, True
|
||||
|
||||
def _copy_huiyuan_prices(self):
|
||||
from products.models import Huiyuan
|
||||
count = 0
|
||||
for h in Huiyuan.query.all():
|
||||
bankuai_id = getattr(h, 'bankuai_id', None)
|
||||
existing = ClubHuiyuanPrice.query.filter(
|
||||
club_id=CLUB_ID_DEFAULT, huiyuan_id=h.huiyuan_id
|
||||
).first()
|
||||
if existing:
|
||||
continue
|
||||
ClubHuiyuanPrice.query.create(
|
||||
club_id=CLUB_ID_DEFAULT,
|
||||
huiyuan_id=h.huiyuan_id,
|
||||
jiage=h.jiage or Decimal('0'),
|
||||
guanshifc=h.guanshifc or Decimal('0'),
|
||||
zuzhangfc=h.zuzhangfc or Decimal('0'),
|
||||
is_enabled=True,
|
||||
bankuai_id=bankuai_id,
|
||||
)
|
||||
count += 1
|
||||
self.stdout.write(f'club_huiyuan_price 新增 {count} 条')
|
||||
|
||||
def _copy_lilubiao(self):
|
||||
from orders.models import CommissionRate
|
||||
count = 0
|
||||
for row in CommissionRate.query.all():
|
||||
config_type = int(row.Platform or 0)
|
||||
existing = ClubLilubiao.query.filter(
|
||||
club_id=CLUB_ID_DEFAULT, config_type=config_type
|
||||
).first()
|
||||
if existing:
|
||||
continue
|
||||
ClubLilubiao.query.create(
|
||||
club_id=CLUB_ID_DEFAULT,
|
||||
config_type=config_type,
|
||||
lilv=row.Rate or Decimal('0'),
|
||||
remark='',
|
||||
)
|
||||
count += 1
|
||||
self.stdout.write(f'club_lilubiao 新增 {count} 条')
|
||||
|
||||
def _ensure_withdraw_config(self):
|
||||
from config.models import WithdrawConfig, TixianQuotaDefault
|
||||
mode = 1
|
||||
try:
|
||||
wc = WithdrawConfig.query.first()
|
||||
if wc:
|
||||
mode = wc.mode
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
cfg = ClubWithdrawConfig.query.get(club_id=CLUB_ID_DEFAULT)
|
||||
cfg.mode = mode
|
||||
cfg.save(update_fields=['mode'])
|
||||
except ClubWithdrawConfig.DoesNotExist:
|
||||
ClubWithdrawConfig.query.create(club_id=CLUB_ID_DEFAULT, mode=mode)
|
||||
self._copy_tixian_quota()
|
||||
|
||||
def _copy_tixian_quota(self):
|
||||
from config.models import TixianQuotaDefault
|
||||
from jituan.models import ClubTixianQuota
|
||||
count = 0
|
||||
for row in TixianQuotaDefault.query.all():
|
||||
existing = ClubTixianQuota.query.filter(
|
||||
club_id=CLUB_ID_DEFAULT, leixing=row.UserType,
|
||||
).first()
|
||||
if existing:
|
||||
continue
|
||||
ClubTixianQuota.query.create(
|
||||
club_id=CLUB_ID_DEFAULT,
|
||||
leixing=row.UserType,
|
||||
daily_limit=row.default_quota or Decimal('0'),
|
||||
)
|
||||
count += 1
|
||||
self.stdout.write(f'club_tixian_quota 新增 {count} 条')
|
||||
|
||||
def _migrate_openid_bindings(self):
|
||||
migrated = 0
|
||||
users = User.query.filter(OpenID__isnull=False).exclude(OpenID='')
|
||||
for u in users:
|
||||
exists = UserWxOpenid.query.filter(
|
||||
club_id=CLUB_ID_DEFAULT, openid=u.OpenID
|
||||
).exists()
|
||||
if exists:
|
||||
continue
|
||||
UserWxOpenid.query.create(
|
||||
club_id=CLUB_ID_DEFAULT,
|
||||
openid=u.OpenID,
|
||||
yonghuid=u.UserUID,
|
||||
unionid=u.UnionID,
|
||||
)
|
||||
if hasattr(u, 'ClubID') and (not u.ClubID or u.ClubID != CLUB_ID_DEFAULT):
|
||||
u.ClubID = CLUB_ID_DEFAULT
|
||||
u.save(update_fields=['ClubID'])
|
||||
migrated += 1
|
||||
return migrated
|
||||
40
jituan/management/commands/seed_szjilu_clubs.py
Normal file
40
jituan/management/commands/seed_szjilu_clubs.py
Normal file
@@ -0,0 +1,40 @@
|
||||
"""为每个启用俱乐部初始化 szjilu 收支流水行。"""
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db import transaction
|
||||
|
||||
from config.models import Szjilu
|
||||
from jituan.constants import CLUB_ID_DEFAULT
|
||||
from jituan.models import Club
|
||||
from jituan.services.szjilu_accounting import normalize_szjilu_club_id
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = '为每个俱乐部创建 szjilu 收支流水行(已有则跳过)'
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
'--club-id',
|
||||
type=str,
|
||||
default='',
|
||||
help='仅处理指定 club_id,默认处理全部启用俱乐部',
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
club_id = (options.get('club_id') or '').strip()
|
||||
if club_id:
|
||||
club_ids = [normalize_szjilu_club_id(club_id)]
|
||||
else:
|
||||
club_ids = list(
|
||||
Club.query.filter(status=1).values_list('club_id', flat=True)
|
||||
)
|
||||
if CLUB_ID_DEFAULT not in club_ids:
|
||||
club_ids.append(CLUB_ID_DEFAULT)
|
||||
|
||||
created = 0
|
||||
with transaction.atomic():
|
||||
for cid in club_ids:
|
||||
_, was_created = Szjilu.objects.get_or_create(club_id=cid)
|
||||
if was_created:
|
||||
created += 1
|
||||
self.stdout.write(f'创建 szjilu: club_id={cid}')
|
||||
self.stdout.write(self.style.SUCCESS(f'完成,新建 {created} 条 szjilu 记录'))
|
||||
Reference in New Issue
Block a user