Files
Django/jituan/models.py
T
XingQueandCursor 49ad57bbb2 feat: club 表独立 mch_key 字段,后台明确区分 APIv2 收款与 APIv3 提现
- 新增 club.mch_key 列并迁移 config_json 历史数据,api_v3_key 保持独立
- club-manage 读写 mch_key;支付读 club.mch_key 优先,兼容 config_json 回落
- 提现查单返回商户号改读俱乐部 V3 配置;不影响其他业务逻辑

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-10 21:34:32 +08:00

336 lines
16 KiB
Python

"""集团多俱乐部数据模型(新建表,不修改 gvsdsdk)。"""
import uuid
from decimal import Decimal
from django.db import models
from gvsdsdk.model_base import QModel
class Club(QModel):
"""子公司 / 俱乐部主表。"""
club_id = models.CharField(max_length=16, primary_key=True, verbose_name='俱乐部ID')
name = models.CharField(max_length=64, verbose_name='展示名')
status = models.IntegerField(default=1, verbose_name='1启用0停用')
wx_appid = models.CharField(max_length=32, blank=True, default='')
wx_secret = models.CharField(max_length=128, blank=True, default='')
mch_id = models.CharField(max_length=32, blank=True, default='')
pay_app_id = models.CharField(max_length=32, blank=True, default='')
mch_key = models.CharField(max_length=128, blank=True, default='', verbose_name='APIv2商户密钥')
api_v3_key = models.CharField(max_length=128, blank=True, default='', verbose_name='APIv3密钥')
cert_serial_no = models.CharField(max_length=64, blank=True, default='')
private_key_path = models.CharField(max_length=255, blank=True, default='')
platform_cert_dir = models.CharField(max_length=255, blank=True, default='')
official_appid = models.CharField(max_length=32, blank=True, default='')
official_secret = models.CharField(max_length=128, blank=True, default='')
official_token = models.CharField(max_length=64, blank=True, default='')
encoding_aes_key = models.CharField(max_length=64, blank=True, default='')
template_id = models.CharField(max_length=64, blank=True, default='')
template_max_per_minute = models.IntegerField(default=950)
h5_domain = models.CharField(max_length=128, blank=True, default='')
oss_prefix = models.CharField(max_length=128, blank=True, default='')
goeasy_appkey = models.CharField(max_length=64, blank=True, default='')
goeasy_secret = models.CharField(max_length=128, blank=True, default='')
config_json = models.JSONField(default=dict, blank=True)
company_uuid = models.BinaryField(max_length=16, null=True, blank=True)
sort_order = models.IntegerField(default=0)
CreateTime = models.DateTimeField(auto_now_add=True)
UpdateTime = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'club'
verbose_name = '俱乐部'
class UserWxOpenid(QModel):
"""微信 openid 与俱乐部用户绑定(club_id + openid 唯一)。"""
club_id = models.CharField(max_length=16, db_index=True)
openid = models.CharField(max_length=64, db_index=True)
yonghuid = models.CharField(max_length=7, db_index=True, verbose_name='用户ID')
unionid = models.CharField(max_length=64, null=True, blank=True)
CreateTime = models.DateTimeField(auto_now_add=True)
class Meta:
db_table = 'user_wx_openid'
unique_together = [['club_id', 'openid']]
class AdminAssignment(QModel):
"""管理任职:集团或子公司后台权限范围。"""
yonghuid = models.CharField(max_length=7, db_index=True)
club_id = models.CharField(max_length=16, null=True, blank=True, db_index=True,
verbose_name='NULL=集团任职')
role_code = models.CharField(max_length=50, default='CLUB_ADMIN')
data_scope = models.CharField(max_length=20, default='SINGLE_CLUB')
is_primary = models.BooleanField(default=False)
granted_by = models.CharField(max_length=7, blank=True, default='')
status = models.IntegerField(default=1, verbose_name='1有效0停用')
CreateTime = models.DateTimeField(auto_now_add=True)
UpdateTime = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'admin_assignment'
unique_together = [['yonghuid', 'club_id', 'role_code']]
class AdminAuditLog(QModel):
"""后台敏感操作审计(改余额等)。"""
club_id = models.CharField(max_length=16, null=True, blank=True, db_index=True)
operator_yonghuid = models.CharField(max_length=16, db_index=True)
operator_role_code = models.CharField(max_length=50, blank=True, default='')
target_yonghuid = models.CharField(max_length=7, null=True, blank=True)
action = models.CharField(max_length=64, db_index=True)
resource_type = models.CharField(max_length=32, blank=True, default='')
resource_id = models.CharField(max_length=64, blank=True, default='')
field_name = models.CharField(max_length=64, blank=True, default='')
value_before = models.TextField(null=True, blank=True)
value_after = models.TextField(null=True, blank=True)
request_ip = models.CharField(max_length=64, blank=True, default='')
remark = models.CharField(max_length=500, blank=True, default='')
CreateTime = models.DateTimeField(auto_now_add=True)
class Meta:
db_table = 'admin_audit_log'
indexes = [models.Index(fields=['club_id', '-CreateTime'])]
class ClubHuiyuanPrice(QModel):
"""各俱乐部会员售价/分成(全局 huiyuan_id 定义不变)。"""
club_id = models.CharField(max_length=16, db_index=True)
huiyuan_id = models.CharField(max_length=6, db_index=True)
jiage = models.DecimalField(max_digits=10, decimal_places=2, default=Decimal('0.00'))
guanshifc = models.DecimalField(max_digits=10, decimal_places=2, default=Decimal('0.00'))
zuzhangfc = models.DecimalField(max_digits=10, decimal_places=2, default=Decimal('0.00'))
formal_days = models.PositiveIntegerField(default=30, verbose_name='正式会员有效天数')
trial_enabled = models.BooleanField(default=False, verbose_name='是否开启体验会员')
trial_price = models.DecimalField(
max_digits=10, decimal_places=2, default=Decimal('0.00'), verbose_name='体验会员价格',
)
trial_days = models.PositiveIntegerField(default=0, verbose_name='体验会员有效天数')
trial_guanshifc = models.DecimalField(
max_digits=10, decimal_places=2, default=Decimal('0.00'), verbose_name='体验管事分成',
)
trial_zuzhangfc = models.DecimalField(
max_digits=10, decimal_places=2, default=Decimal('0.00'), verbose_name='体验组长分成',
)
card_image = models.CharField(
max_length=500, blank=True, default='', verbose_name='充值页会员卡片装饰图(相对URL)',
)
card_bg = models.CharField(
max_length=500, blank=True, default='', verbose_name='充值页会员卡片背景图(相对URL,可选)',
)
is_enabled = models.BooleanField(default=True)
bankuai_id = models.IntegerField(null=True, blank=True)
CreateTime = models.DateTimeField(auto_now_add=True)
UpdateTime = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'club_huiyuan_price'
unique_together = [['club_id', 'huiyuan_id']]
class ClubHuiyuanBundleInclude(QModel):
"""俱乐部总会员包含的子会员类型(仅 is_bundle 会员使用)。"""
club_id = models.CharField(max_length=16, db_index=True)
bundle_huiyuan_id = models.CharField(max_length=6, db_index=True, verbose_name='总会员ID')
included_huiyuan_id = models.CharField(max_length=6, db_index=True, verbose_name='包含的子会员ID')
CreateTime = models.DateTimeField(auto_now_add=True)
UpdateTime = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'club_huiyuan_bundle_include'
unique_together = [['club_id', 'bundle_huiyuan_id', 'included_huiyuan_id']]
class ClubShangpinLeixingConfig(QModel):
"""各俱乐部小程序商品类型上架与图标(全局 ShangpinLeixing 由集团定义)。"""
club_id = models.CharField(max_length=16, db_index=True)
leixing_id = models.IntegerField(db_index=True, verbose_name='全局商品类型ID')
is_enabled = models.BooleanField(default=True, verbose_name='是否上架')
tupian_url = models.CharField(max_length=500, blank=True, default='', verbose_name='俱乐部专属图标')
paixu = models.IntegerField(default=0, verbose_name='排序权重')
CreateTime = models.DateTimeField(auto_now_add=True)
UpdateTime = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'club_shangpin_leixing_config'
unique_together = [['club_id', 'leixing_id']]
class ClubKaoheChenghaoConfig(QModel):
"""各俱乐部抢单池标签筛选区上架配置(全局 Chenghao 由集团定义)。"""
club_id = models.CharField(max_length=16, db_index=True)
chenghao_id = models.IntegerField(db_index=True, verbose_name='全局称号ID')
is_enabled = models.BooleanField(default=True, verbose_name='是否在抢单池筛选区展示')
CreateTime = models.DateTimeField(auto_now_add=True)
UpdateTime = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'club_kaohe_chenghao_config'
unique_together = [['club_id', 'chenghao_id']]
class ClubLilubiao(QModel):
"""各俱乐部分红/手续费配置(对应 lilubiao.fadanpingtai)。"""
club_id = models.CharField(max_length=16, db_index=True)
config_type = models.IntegerField(db_index=True, verbose_name='同 lilubiao.fadanpingtai')
lilv = models.DecimalField(max_digits=10, decimal_places=4, default=Decimal('0.0000'))
remark = models.CharField(max_length=255, blank=True, default='')
CreateTime = models.DateTimeField(auto_now_add=True)
UpdateTime = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'club_lilubiao'
unique_together = [['club_id', 'config_type']]
class ClubWithdrawConfig(QModel):
club_id = models.CharField(max_length=16, primary_key=True)
mode = models.IntegerField(default=1, verbose_name='1自动2手动')
CreateTime = models.DateTimeField(auto_now_add=True)
UpdateTime = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'club_withdraw_config'
class ClubTixianQuota(QModel):
club_id = models.CharField(max_length=16, db_index=True)
leixing = models.IntegerField(db_index=True)
daily_limit = models.DecimalField(max_digits=12, decimal_places=2, default=Decimal('0.00'))
CreateTime = models.DateTimeField(auto_now_add=True)
UpdateTime = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'club_tixian_quota'
unique_together = [['club_id', 'leixing']]
class ClubFadanFenhongLilv(QModel):
club_id = models.CharField(max_length=16, db_index=True)
shenfen = models.IntegerField(db_index=True)
lilv = models.DecimalField(max_digits=10, decimal_places=4, default=Decimal('0.0000'))
CreateTime = models.DateTimeField(auto_now_add=True)
UpdateTime = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'club_fadan_fenhong_lilv'
unique_together = [['club_id', 'shenfen']]
class IdentityTag(QModel):
"""身份装饰标签定义(与考核称号、订单需求标签分离)。"""
club_id = models.CharField(max_length=16, db_index=True)
name = models.CharField(max_length=64, verbose_name='标签名')
color = models.CharField(max_length=32, default='#000000', verbose_name='主色')
flash_enabled = models.BooleanField(default=False, verbose_name='闪光特效')
texiao_json = models.TextField(blank=True, default='', verbose_name='特效JSON')
sort_order = models.IntegerField(default=0)
status = models.IntegerField(default=1, verbose_name='1启用0停用')
CreateTime = models.DateTimeField(auto_now_add=True)
UpdateTime = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'identity_tag'
ordering = ['sort_order', 'id']
class IdentityTagBind(QModel):
"""用户身份与装饰标签绑定。"""
club_id = models.CharField(max_length=16, db_index=True)
yonghuid = models.CharField(max_length=7, db_index=True)
shenfen = models.IntegerField(verbose_name='1打手2管事3商家4组长')
tag = models.ForeignKey(IdentityTag, on_delete=models.CASCADE, related_name='binds')
CreateTime = models.DateTimeField(auto_now_add=True)
class Meta:
db_table = 'identity_tag_bind'
unique_together = [['club_id', 'yonghuid', 'shenfen', 'tag']]
indexes = [
models.Index(fields=['club_id', 'yonghuid', 'shenfen']),
]
class ClubDashouExamConfig(QModel):
"""各俱乐部打手抢单前考试配置(互不影响)。"""
club_id = models.CharField(max_length=16, primary_key=True)
is_enabled = models.BooleanField(default=False, verbose_name='是否开启考试')
draw_count = models.PositiveIntegerField(default=10, verbose_name='每次抽题数量')
pass_count = models.PositiveIntegerField(default=10, verbose_name='至少答对题数')
require_member = models.BooleanField(default=True, verbose_name='须开通会员方可考试')
CreateTime = models.DateTimeField(auto_now_add=True)
UpdateTime = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'club_dashou_exam_config'
class ClubDashouExamQuestion(QModel):
"""俱乐部考试题库(题干+最多6选项)。"""
club_id = models.CharField(max_length=16, db_index=True)
stem = models.TextField(verbose_name='题干文字')
question_type = models.IntegerField(default=1, verbose_name='1单选2多选')
option_1 = models.CharField(max_length=500, blank=True, default='')
option_2 = models.CharField(max_length=500, blank=True, default='')
option_3 = models.CharField(max_length=500, blank=True, default='')
option_4 = models.CharField(max_length=500, blank=True, default='')
option_5 = models.CharField(max_length=500, blank=True, default='')
option_6 = models.CharField(max_length=500, blank=True, default='')
correct_1 = models.BooleanField(default=False)
correct_2 = models.BooleanField(default=False)
correct_3 = models.BooleanField(default=False)
correct_4 = models.BooleanField(default=False)
correct_5 = models.BooleanField(default=False)
correct_6 = models.BooleanField(default=False)
explanation = models.TextField(blank=True, default='', verbose_name='错题解析')
is_enabled = models.BooleanField(default=True, verbose_name='是否上架')
sort_order = models.IntegerField(default=0)
CreateTime = models.DateTimeField(auto_now_add=True)
UpdateTime = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'club_dashou_exam_question'
indexes = [models.Index(fields=['club_id', 'is_enabled'])]
class ClubDashouExamQuestionImage(QModel):
"""题目配图(题干下方,可多张)。"""
club_id = models.CharField(max_length=16, db_index=True)
question_id = models.IntegerField(db_index=True)
image_url = models.CharField(max_length=500)
sort_order = models.IntegerField(default=0)
CreateTime = models.DateTimeField(auto_now_add=True)
class Meta:
db_table = 'club_dashou_exam_question_image'
indexes = [models.Index(fields=['club_id', 'question_id'])]
class ClubDashouExamPass(QModel):
"""打手在本俱乐部是否已通过考试。"""
club_id = models.CharField(max_length=16, db_index=True)
yonghuid = models.CharField(max_length=7, db_index=True)
passed_at = models.DateTimeField(auto_now_add=True)
CreateTime = models.DateTimeField(auto_now_add=True)
class Meta:
db_table = 'club_dashou_exam_pass'
unique_together = [['club_id', 'yonghuid']]
class KefuMenuPage(QModel):
"""客服后台左侧菜单页(固定 page_id,与前端路由对应)。"""
page_id = models.CharField(max_length=64, primary_key=True, verbose_name='页面ID')
name = models.CharField(max_length=64, verbose_name='展示名')
path = models.CharField(max_length=128, blank=True, default='', verbose_name='路由路径,分组为空')
parent_id = models.CharField(max_length=64, blank=True, default='', db_index=True)
sort_order = models.IntegerField(default=0)
perm_codes = models.JSONField(default=list, blank=True, verbose_name='拥有任一权限即可见')
require_super = models.BooleanField(default=False, verbose_name='仅超级管理000001')
require_group_manage = models.BooleanField(default=False, verbose_name='仅集团超管任职')
CreateTime = models.DateTimeField(auto_now_add=True)
UpdateTime = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'kefu_menu_page'
ordering = ['sort_order', 'page_id']