第一次提交:阿龙电竞 Django 后端最新版本

This commit is contained in:
XingQue
2026-06-14 02:23:24 +08:00
commit 4f7bf00224
9654 changed files with 5417000 additions and 0 deletions

0
yonghu/__init__.py Normal file
View File

3
yonghu/admin.py Normal file
View File

@@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

5
yonghu/apps.py Normal file
View File

@@ -0,0 +1,5 @@
from django.apps import AppConfig
class YonghuConfig(AppConfig):
name = "yonghu"

View File

@@ -0,0 +1,168 @@
# yonghu/fadan_fenhong_utils.py
# 罚款缴纳分红处理公共方法(支持更新罚单中的申请人分红金额)
import decimal
import logging
from decimal import Decimal
from django.db import transaction
from django.core.exceptions import ObjectDoesNotExist
from dingdan.models import Fadan, FadanFenhong, FadanFenhongLilv
from yonghu.models import UserShangjia
logger = logging.getLogger(__name__)
# 身份映射字典
IDENTITY_MAP = {
1: {'fenhong': 2, 'lilv': 1}, # 客服
2: {'fenhong': 5, 'lilv': 2}, # 售后
3: {'fenhong': 3, 'lilv': 3}, # 管理员
4: {'fenhong': 4, 'lilv': 4}, # 店铺
5: {'fenhong': 1, 'lilv': 5}, # 商家
}
def process_fadan_fenhong(fadan_id):
"""
罚款缴纳后的分红处理(在回调中调用)
参数:
fadan_id: 罚单 ID
返回:
(success, message)
"""
try:
# 1. 获取罚单对象(必须是已缴纳状态)
try:
fadan = Fadan.objects.get(id=fadan_id, zhuangtai=2)
except Fadan.DoesNotExist:
logger.error(f"罚单 {fadan_id} 不存在或状态不是已缴纳")
return False, "罚单不存在或状态异常"
# 2. 获取申请处罚者ID和身份源身份数字
shenqing_chufa = fadan.shenqing_chufa
src_shenfen = fadan.shenqingren_shenfen
if not shenqing_chufa:
logger.info(f"罚单 {fadan_id} 无申请处罚者,不进行分红")
# 即使无申请者也可将分红金额字段设为0默认已是0
return True, "无申请处罚者,无需分红"
# 3. 映射身份数字
if src_shenfen not in IDENTITY_MAP:
logger.error(f"未知的申请处罚者身份: {src_shenfen},罚单 {fadan_id}")
return False, f"未知身份 {src_shenfen}"
mapped = IDENTITY_MAP[src_shenfen]
fenhong_shenfen = mapped['fenhong'] # 用于 FadanFenhong.shenfen
lilv_shenfen = mapped['lilv'] # 用于 FadanFenhongLilv.shenfen
# 4. 获取罚款金额
fakuan_jine = fadan.fakuanjine
if fakuan_jine <= 0:
logger.info(f"罚单 {fadan_id} 罚款金额为0不产生分红")
fadan.shenqingren_fenhong_jine = Decimal('0.00')
fadan.save(update_fields=['shenqingren_fenhong_jine'])
return True, "罚款金额为0无分红"
# 5. 确定分红利率
rate = _get_fenhong_rate(shenqing_chufa, fenhong_shenfen, lilv_shenfen)
if rate is None:
logger.warning(f"未找到身份 {src_shenfen} (映射后 fenhong_shenfen={fenhong_shenfen}, lilv_shenfen={lilv_shenfen}) 的分红利率,罚单 {fadan_id} 不进行分红")
fadan.shenqingren_fenhong_jine = Decimal('0.00')
fadan.save(update_fields=['shenqingren_fenhong_jine'])
return True, "未配置分红利率,无分红"
# 6. 计算分红金额
fenhong_jine = (Decimal(str(fakuan_jine)) * Decimal(str(rate))).quantize(Decimal('0.01'))
if fenhong_jine <= 0:
logger.info(f"罚单 {fadan_id} 计算分红金额为0无需处理")
fadan.shenqingren_fenhong_jine = Decimal('0.00')
fadan.save(update_fields=['shenqingren_fenhong_jine'])
return True, "分红金额为0"
# 7. 根据申请处罚者身份执行不同的分红逻辑
# src_shenfen == 5 代表商家(源身份)
if src_shenfen == 5:
# 商家特殊处理只记录总额可提现分红永远为0直接加到商家余额
with transaction.atomic():
fenhong_record, created = FadanFenhong.objects.get_or_create(
fenhongzhe_id=shenqing_chufa,
shenfen=fenhong_shenfen,
defaults={
'zonge': Decimal('0.00'),
'ketixian_fenhong': Decimal('0.00'),
'fenhong_cishu': 0,
'yingde_lilv': rate,
'is_individual_rate': False
}
)
fenhong_record.zonge += fenhong_jine
# 可提现分红不累加保持0
fenhong_record.fenhong_cishu += 1
fenhong_record.save()
# 直接增加商家余额UserShangjia.yue
try:
shangjia = UserShangjia.objects.get(user__yonghuid=shenqing_chufa)
shangjia.yue += fenhong_jine
shangjia.save(update_fields=['yue'])
logger.info(f"商家 {shenqing_chufa} 余额增加 {fenhong_jine}")
except UserShangjia.DoesNotExist:
logger.error(f"商家 {shenqing_chufa} 扩展表不存在,无法增加余额")
raise Exception(f"商家 {shenqing_chufa} 扩展表不存在,无法增加余额")
# 更新罚单中的申请人分红金额
fadan.shenqingren_fenhong_jine = fenhong_jine
fadan.save(update_fields=['shenqingren_fenhong_jine'])
else:
# 其他身份(客服、售后、管理员、店铺):同时增加总额和可提现分红
with transaction.atomic():
fenhong_record, created = FadanFenhong.objects.get_or_create(
fenhongzhe_id=shenqing_chufa,
shenfen=fenhong_shenfen,
defaults={
'zonge': Decimal('0.00'),
'ketixian_fenhong': Decimal('0.00'),
'fenhong_cishu': 0,
'yingde_lilv': rate,
'is_individual_rate': False
}
)
fenhong_record.zonge += fenhong_jine
fenhong_record.ketixian_fenhong += fenhong_jine
fenhong_record.fenhong_cishu += 1
fenhong_record.save()
# 更新罚单中的申请人分红金额
fadan.shenqingren_fenhong_jine = fenhong_jine
fadan.save(update_fields=['shenqingren_fenhong_jine'])
logger.info(f"罚单 {fadan_id} 分红处理成功: 申请者 {shenqing_chufa}, 分红金额 {fenhong_jine} 元, 源身份 {src_shenfen}, 映射后分红身份 {fenhong_shenfen}")
return True, "分红处理成功"
except Exception as e:
logger.error(f"罚单 {fadan_id} 分红处理异常: {str(e)}", exc_info=True)
return False, f"分红处理异常: {str(e)}"
def _get_fenhong_rate(fenhongzhe_id, fenhong_shenfen, lilv_shenfen):
"""
获取分红利率(优先使用个人单独配置,否则使用全局身份配置)
"""
try:
individual = FadanFenhong.objects.get(
fenhongzhe_id=fenhongzhe_id,
shenfen=fenhong_shenfen,
is_individual_rate=True
)
return individual.yingde_lilv
except FadanFenhong.DoesNotExist:
pass
try:
global_rate = FadanFenhongLilv.objects.get(shenfen=lilv_shenfen)
return global_rate.lilv
except FadanFenhongLilv.DoesNotExist:
return None

View File

@@ -0,0 +1,833 @@
# Generated by Django 4.2.27 on 2026-01-23 19:32
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = []
operations = [
migrations.CreateModel(
name="UserMain",
fields=[
(
"last_login",
models.DateTimeField(
blank=True, null=True, verbose_name="last login"
),
),
(
"id",
models.AutoField(
primary_key=True, serialize=False, verbose_name="主键ID"
),
),
(
"yonghuid",
models.CharField(
db_index=True, max_length=7, unique=True, verbose_name="用户ID"
),
),
(
"openid",
models.CharField(
db_index=True,
max_length=64,
unique=True,
verbose_name="微信OpenID",
),
),
(
"avatar",
models.CharField(
blank=True, max_length=500, null=True, verbose_name="头像"
),
),
(
"phone",
models.CharField(
blank=True, max_length=11, null=True, verbose_name="手机号"
),
),
(
"password",
models.CharField(
blank=True, max_length=200, null=True, verbose_name="密码"
),
),
(
"zhifu",
models.CharField(
blank=True, max_length=500, null=True, verbose_name="收款码图片"
),
),
(
"skzhanghao",
models.CharField(
blank=True, max_length=11, null=True, verbose_name="收款账号"
),
),
(
"ip",
models.CharField(
blank=True, max_length=50, null=True, verbose_name="来访用户ip"
),
),
(
"last_login_time",
models.DateTimeField(
blank=True, null=True, verbose_name="最后登录时间"
),
),
(
"user_type",
models.CharField(
choices=[
("normal", "普通用户"),
("dashou", "打手"),
("shop", "商家"),
("guanshi", "管事"),
("admin", "管理员"),
],
default="normal",
max_length=10,
verbose_name="用户类型",
),
),
(
"create_time",
models.DateTimeField(auto_now_add=True, verbose_name="创建时间"),
),
(
"update_time",
models.DateTimeField(auto_now=True, verbose_name="更新时间"),
),
],
options={
"verbose_name": "用户主表",
"verbose_name_plural": "用户主表",
"db_table": "user_main",
},
),
migrations.CreateModel(
name="Xiugaijilu",
fields=[
(
"id",
models.AutoField(
primary_key=True, serialize=False, verbose_name="记录ID"
),
),
(
"yonghuid",
models.CharField(max_length=7, verbose_name="被修改用户ID"),
),
(
"xiugaiid",
models.CharField(max_length=30, verbose_name="修改人账号ID"),
),
("leixing", models.IntegerField(verbose_name="被修改用户类型")),
(
"xiugaitijiao",
models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=12,
verbose_name="修改后的打手提现金额",
),
),
(
"xiugaitijiaoq",
models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=12,
verbose_name="修改前的打手提现金额",
),
),
(
"jifen",
models.IntegerField(default=0, verbose_name="修改后的打手积分"),
),
(
"yjifen",
models.IntegerField(default=0, verbose_name="修改前的打手积分"),
),
(
"yajin",
models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=12,
verbose_name="修改后的打手押金",
),
),
(
"yyajin",
models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=12,
verbose_name="修改前的打手押金",
),
),
(
"shangjiayue",
models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=12,
verbose_name="修改后的商家余额",
),
),
(
"shangjiayueq",
models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=12,
verbose_name="修改前的商家余额",
),
),
(
"guanshiyue",
models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=12,
verbose_name="修改后的管事余额",
),
),
(
"guanshiyueq",
models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=12,
verbose_name="修改前的管事余额",
),
),
(
"huiyuants",
models.IntegerField(default=0, verbose_name="添加会员天数"),
),
(
"huiyuan_id",
models.CharField(
blank=True, max_length=6, null=True, verbose_name="会员ID"
),
),
(
"qitashuoming",
models.TextField(blank=True, null=True, verbose_name="其他说明"),
),
(
"create_time",
models.DateTimeField(auto_now_add=True, verbose_name="创建时间"),
),
(
"update_time",
models.DateTimeField(auto_now=True, verbose_name="更新时间"),
),
],
options={
"verbose_name": "修改记录表",
"verbose_name_plural": "修改记录表",
"db_table": "xiugaijilu",
},
),
migrations.CreateModel(
name="UserShangjia",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"nicheng",
models.CharField(
db_index=True,
max_length=50,
unique=True,
verbose_name="商家昵称",
),
),
(
"zhuangtai",
models.IntegerField(
choices=[(0, "待审核"), (1, "正常"), (2, "禁用")],
default=1,
verbose_name="商家状态",
),
),
(
"dianhua",
models.CharField(max_length=20, null=True, verbose_name="商家电话"),
),
(
"wechat",
models.CharField(
max_length=50, null=True, verbose_name="商家微信号"
),
),
("fabu", models.IntegerField(default=0, verbose_name="发布订单总数量")),
(
"tuikuan",
models.IntegerField(default=0, verbose_name="退款订单总量"),
),
(
"yue",
models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=12,
verbose_name="商家余额",
),
),
(
"chengjiao",
models.IntegerField(default=0, verbose_name="商家成交订单总量"),
),
(
"jinridingdan",
models.IntegerField(default=0, verbose_name="商家今日订单总量"),
),
(
"jinriliushui",
models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=12,
verbose_name="商家今日流水",
),
),
(
"jinyuedingdan",
models.IntegerField(default=0, verbose_name="商家今月订单总量"),
),
(
"jinyueliushui",
models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=12,
verbose_name="商家今月流水",
),
),
(
"create_time",
models.DateTimeField(auto_now_add=True, verbose_name="创建时间"),
),
(
"user",
models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE,
related_name="shop_profile",
to=settings.AUTH_USER_MODEL,
verbose_name="关联用户",
),
),
],
options={
"verbose_name": "商家扩展表",
"verbose_name_plural": "商家扩展表",
"db_table": "user_shangjia",
},
),
migrations.CreateModel(
name="UserGuanshi",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"yaoqingma",
models.CharField(
db_index=True, max_length=20, null=True, verbose_name="邀请码"
),
),
(
"dianhua",
models.CharField(max_length=20, null=True, verbose_name="管事电话"),
),
(
"wechat",
models.CharField(
max_length=50, null=True, verbose_name="管事微信号"
),
),
(
"yaogingshuliang",
models.IntegerField(default=0, verbose_name="邀请打手总数"),
),
(
"zhuangtai",
models.IntegerField(
choices=[(0, "禁用"), (1, "正常")],
default=1,
verbose_name="管事状态",
),
),
(
"jinrichongzhi",
models.IntegerField(default=0, verbose_name="今日充值打手数量"),
),
(
"jinyuechongzhi",
models.IntegerField(default=0, verbose_name="今月充值打手数量"),
),
(
"chongzhifenrun",
models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=12,
verbose_name="充值分佣总额",
),
),
(
"yue",
models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=12,
verbose_name="可提现余额",
),
),
(
"create_time",
models.DateTimeField(auto_now_add=True, verbose_name="创建时间"),
),
(
"user",
models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE,
related_name="guanshi_profile",
to=settings.AUTH_USER_MODEL,
verbose_name="关联用户",
),
),
],
options={
"verbose_name": "管事扩展表",
"verbose_name_plural": "管事扩展表",
"db_table": "user_guanshi",
},
),
migrations.CreateModel(
name="UserDashou",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"nicheng",
models.CharField(max_length=50, null=True, verbose_name="打手昵称"),
),
(
"chenghao",
models.CharField(max_length=50, null=True, verbose_name="打手称号"),
),
("zhuangtai", models.IntegerField(default=1, verbose_name="打手状态")),
(
"zaixianzhuangtai",
models.IntegerField(default=1, verbose_name="打手在线状态"),
),
(
"zhanghaozhuangtai",
models.IntegerField(default=1, verbose_name="打手账号状态"),
),
("jieshao", models.TextField(null=True, verbose_name="打手介绍")),
(
"jiedanzongliang",
models.IntegerField(default=0, verbose_name="接单总量"),
),
(
"chengjiaozongliang",
models.IntegerField(default=0, verbose_name="成交单总量"),
),
(
"tuikuanliang",
models.IntegerField(default=0, verbose_name="退款订单总量"),
),
(
"yue",
models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=12,
verbose_name="可提现余额",
),
),
(
"zonge",
models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=12,
verbose_name="打单赚取总额",
),
),
(
"dianhua",
models.CharField(max_length=20, null=True, verbose_name="打手电话"),
),
(
"wechat",
models.CharField(
max_length=50, null=True, verbose_name="打手微信号"
),
),
(
"yaoqingren",
models.CharField(
db_index=True, max_length=7, null=True, verbose_name="邀请人ID"
),
),
(
"jinrijiedan",
models.IntegerField(default=0, verbose_name="今日接单数量"),
),
(
"jinrishouyi",
models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=10,
verbose_name="今日收益金额",
),
),
(
"jinyuejiedan",
models.IntegerField(default=0, verbose_name="今月接单数量"),
),
(
"jinyueshouyi",
models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=10,
verbose_name="今月收益金额",
),
),
("jifen", models.IntegerField(default=0, verbose_name="打手积分")),
(
"yajin",
models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=12,
verbose_name="打手押金",
),
),
(
"create_time",
models.DateTimeField(auto_now_add=True, verbose_name="创建时间"),
),
(
"user",
models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE,
related_name="dashou_profile",
to=settings.AUTH_USER_MODEL,
verbose_name="关联用户",
),
),
],
options={
"verbose_name": "打手扩展表",
"verbose_name_plural": "打手扩展表",
"db_table": "user_dashou",
},
),
migrations.CreateModel(
name="UserBoss",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("nickname", models.CharField(max_length=50, verbose_name="老板昵称")),
(
"zonge",
models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=12,
verbose_name="消费总额",
),
),
("alldingdan", models.IntegerField(default=0, verbose_name="订单总数")),
("alltui", models.IntegerField(default=0, verbose_name="退款总数")),
(
"create_time",
models.DateTimeField(auto_now_add=True, verbose_name="创建时间"),
),
(
"user",
models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE,
related_name="boss_profile",
to=settings.AUTH_USER_MODEL,
verbose_name="关联用户",
),
),
],
options={
"verbose_name": "老板扩展表",
"verbose_name_plural": "老板扩展表",
"db_table": "user_boss",
},
),
migrations.CreateModel(
name="Tixianjilu",
fields=[
(
"id",
models.AutoField(
primary_key=True, serialize=False, verbose_name="提现记录ID"
),
),
(
"yonghuid",
models.CharField(
db_index=True, max_length=7, verbose_name="提现用户ID"
),
),
(
"avatar",
models.CharField(
blank=True, max_length=500, null=True, verbose_name="头像"
),
),
(
"phone",
models.CharField(
blank=True, max_length=11, null=True, verbose_name="手机号"
),
),
(
"nicheng",
models.CharField(max_length=50, null=True, verbose_name="打手昵称"),
),
(
"leixing",
models.PositiveIntegerField(
blank=True,
null=True,
verbose_name="提现类型1:打手佣金2管事分红",
),
),
(
"zhifu",
models.CharField(
blank=True, max_length=500, null=True, verbose_name="收款码图片"
),
),
(
"skzhanghao",
models.CharField(
blank=True, max_length=11, null=True, verbose_name="收款账号"
),
),
(
"jine",
models.DecimalField(
blank=True,
decimal_places=2,
max_digits=10,
null=True,
verbose_name="提现金额",
),
),
(
"zhuangtai",
models.IntegerField(
blank=True,
db_index=True,
default=1,
null=True,
verbose_name="提现状态1:审核2成功3失败",
),
),
(
"fangshi",
models.IntegerField(
blank=True,
db_index=True,
null=True,
verbose_name="收款方式1:微信2支付宝",
),
),
(
"shenheid",
models.CharField(
db_index=True,
max_length=7,
null=True,
verbose_name="审核用户ID",
),
),
(
"bhliyou",
models.TextField(blank=True, null=True, verbose_name="驳回理由"),
),
(
"create_time",
models.DateTimeField(auto_now_add=True, verbose_name="创建时间"),
),
(
"update_time",
models.DateTimeField(auto_now=True, verbose_name="更新时间"),
),
],
options={
"verbose_name": "提现记录表",
"verbose_name_plural": "提现记录表",
"db_table": "tixianjilu",
"indexes": [
models.Index(
fields=["yonghuid"], name="tixianjilu_yonghui_8083bb_idx"
),
models.Index(
fields=["zhuangtai"], name="tixianjilu_zhuangt_839d8e_idx"
),
models.Index(
fields=["shenheid"], name="tixianjilu_shenhei_470e0c_idx"
),
models.Index(
fields=["fangshi"], name="tixianjilu_fangshi_a1e0bc_idx"
),
],
},
),
migrations.CreateModel(
name="AdminProfile",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("password", models.CharField(max_length=255, verbose_name="密码")),
(
"wechat",
models.CharField(
blank=True, max_length=50, verbose_name="管理员微信"
),
),
(
"yaoqingma",
models.CharField(
db_index=True,
max_length=20,
null=True,
verbose_name="管理员邀请码",
),
),
(
"create_time",
models.DateTimeField(auto_now_add=True, verbose_name="创建时间"),
),
(
"user",
models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE,
related_name="admin_profile",
to=settings.AUTH_USER_MODEL,
verbose_name="关联用户",
),
),
],
options={
"verbose_name": "管理员扩展表",
"verbose_name_plural": "管理员扩展表",
"db_table": "admin_profile",
},
),
migrations.AddIndex(
model_name="usermain",
index=models.Index(
fields=["yonghuid"], name="user_main_yonghui_b8b2fe_idx"
),
),
migrations.AddIndex(
model_name="usermain",
index=models.Index(fields=["openid"], name="user_main_openid_c9edbe_idx"),
),
migrations.AddIndex(
model_name="usermain",
index=models.Index(
fields=["user_type"], name="user_main_user_ty_8515fd_idx"
),
),
migrations.AddIndex(
model_name="usershangjia",
index=models.Index(fields=["user"], name="user_shangj_user_id_823c5c_idx"),
),
migrations.AddIndex(
model_name="usershangjia",
index=models.Index(
fields=["nicheng"], name="user_shangj_nicheng_6967bc_idx"
),
),
migrations.AddIndex(
model_name="userguanshi",
index=models.Index(fields=["user"], name="user_guansh_user_id_cbadac_idx"),
),
migrations.AddIndex(
model_name="userguanshi",
index=models.Index(
fields=["yaoqingma"], name="user_guansh_yaoqing_21d1d4_idx"
),
),
migrations.AddIndex(
model_name="userdashou",
index=models.Index(fields=["user"], name="user_dashou_user_id_cf0410_idx"),
),
migrations.AddIndex(
model_name="userdashou",
index=models.Index(
fields=["yaoqingren"], name="user_dashou_yaoqing_894658_idx"
),
),
migrations.AddIndex(
model_name="userboss",
index=models.Index(fields=["user"], name="user_boss_user_id_4e81a4_idx"),
),
migrations.AddIndex(
model_name="adminprofile",
index=models.Index(fields=["user"], name="admin_profi_user_id_7d067d_idx"),
),
]

View File

@@ -0,0 +1,90 @@
# Generated by Django 4.2.27 on 2026-01-24 22:53
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("yonghu", "0001_initial"),
]
operations = [
migrations.CreateModel(
name="RankingRecord",
fields=[
(
"id",
models.AutoField(
primary_key=True, serialize=False, verbose_name="ID"
),
),
(
"zhouqi",
models.IntegerField(
choices=[(1, "日榜"), (2, "月榜")], verbose_name="周期类型"
),
),
(
"tongji_date",
models.DateField(db_index=True, verbose_name="统计日期"),
),
(
"shenfen",
models.IntegerField(
choices=[(2, "打手"), (3, "管事"), (4, "商家")],
verbose_name="用户身份",
),
),
(
"yonghuid",
models.CharField(
db_index=True, max_length=7, verbose_name="用户ID"
),
),
("paiming", models.IntegerField(verbose_name="排名")),
(
"zhizhi",
models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=12,
verbose_name="指标值",
),
),
(
"nicheng",
models.CharField(max_length=50, null=True, verbose_name="用户昵称"),
),
(
"avatar",
models.CharField(
blank=True, max_length=500, null=True, verbose_name="头像"
),
),
(
"chuangjian_time",
models.DateTimeField(auto_now_add=True, verbose_name="创建时间"),
),
],
options={
"verbose_name": "排行榜记录",
"verbose_name_plural": "排行榜记录",
"db_table": "ranking_record",
"indexes": [
models.Index(
fields=["zhouqi", "tongji_date", "shenfen", "paiming"],
name="ranking_rec_zhouqi_fc9f4d_idx",
),
models.Index(
fields=["yonghuid", "zhouqi"],
name="ranking_rec_yonghui_e5be77_idx",
),
models.Index(
fields=["tongji_date"], name="ranking_rec_tongji__820158_idx"
),
],
"unique_together": {("zhouqi", "tongji_date", "shenfen", "paiming")},
},
),
]

View File

@@ -0,0 +1,24 @@
# Generated by Django 4.2.27 on 2026-01-24 23:49
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("yonghu", "0002_rankingrecord"),
]
operations = [
migrations.AlterField(
model_name="usermain",
name="avatar",
field=models.CharField(
blank=True,
default="a_long/morentouxiang.jpg",
max_length=500,
null=True,
verbose_name="头像",
),
),
]

View File

@@ -0,0 +1,63 @@
# Generated by Django 4.2.27 on 2026-02-09 18:09
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("yonghu", "0003_alter_usermain_avatar"),
]
operations = [
migrations.CreateModel(
name="OfficialAccountUser",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"unionid",
models.CharField(
db_index=True, max_length=64, verbose_name="UnionID"
),
),
(
"official_openid",
models.CharField(
db_index=True,
max_length=64,
unique=True,
verbose_name="服务号OpenID",
),
),
(
"subscribe_time",
models.DateTimeField(auto_now_add=True, verbose_name="关注时间"),
),
(
"is_subscribed",
models.BooleanField(default=True, verbose_name="是否关注"),
),
(
"created_at",
models.DateTimeField(auto_now_add=True, verbose_name="创建时间"),
),
(
"updated_at",
models.DateTimeField(auto_now=True, verbose_name="更新时间"),
),
],
options={
"verbose_name": "服务号用户",
"verbose_name_plural": "服务号用户",
"db_table": "official_account_user",
},
),
]

View File

@@ -0,0 +1,24 @@
# Generated by Django 4.2.27 on 2026-02-09 19:17
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("yonghu", "0004_officialaccountuser"),
]
operations = [
migrations.AddField(
model_name="usermain",
name="unionid",
field=models.CharField(
blank=True,
db_index=True,
max_length=64,
null=True,
verbose_name="微信UnionID",
),
),
]

View File

@@ -0,0 +1,20 @@
# Generated by Django 4.2.27 on 2026-02-09 19:21
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("yonghu", "0005_usermain_unionid"),
]
operations = [
migrations.AlterField(
model_name="officialaccountuser",
name="unionid",
field=models.CharField(
db_index=True, max_length=64, null=True, verbose_name="UnionID"
),
),
]

View File

@@ -0,0 +1,79 @@
# Generated by Django 4.2.27 on 2026-02-22 01:00
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
("yonghu", "0006_alter_officialaccountuser_unionid"),
]
operations = [
migrations.CreateModel(
name="UserKefu",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("nicheng", models.CharField(max_length=50, verbose_name="客服昵称")),
("erjimima", models.CharField(max_length=128, verbose_name="二级密码")),
(
"zhuangtai",
models.IntegerField(
choices=[(0, "禁用"), (1, "正常")],
default=1,
verbose_name="客服状态",
),
),
(
"jinrichuli",
models.IntegerField(default=0, verbose_name="今日处理订单数"),
),
(
"jinyuechuli",
models.IntegerField(default=0, verbose_name="本月处理订单数"),
),
(
"zongchuli",
models.IntegerField(default=0, verbose_name="累计处理订单数"),
),
(
"create_time",
models.DateTimeField(auto_now_add=True, verbose_name="创建时间"),
),
(
"update_time",
models.DateTimeField(auto_now=True, verbose_name="更新时间"),
),
(
"user",
models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE,
related_name="kefu_profile",
to=settings.AUTH_USER_MODEL,
verbose_name="关联用户",
),
),
],
options={
"verbose_name": "客服扩展表",
"verbose_name_plural": "客服扩展表",
"db_table": "user_kefu",
"indexes": [
models.Index(fields=["user"], name="user_kefu_user_id_5fe3a1_idx"),
models.Index(
fields=["zhuangtai"], name="user_kefu_zhuangt_317491_idx"
),
],
},
),
]

View File

@@ -0,0 +1,176 @@
# Generated by Django 4.2.27 on 2026-03-04 23:27
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("yonghu", "0007_userkefu"),
]
operations = [
migrations.AddField(
model_name="userdashou",
name="ewai_xiane",
field=models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=10,
verbose_name="额外提现限额(元)",
),
),
migrations.AddField(
model_name="userdashou",
name="jinritixian_jine",
field=models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=10,
verbose_name="今日已提现金额",
),
),
migrations.AddField(
model_name="userdashou",
name="kaioi_ewai_xiane",
field=models.BooleanField(
default=False, verbose_name="是否开启额外提现限额"
),
),
migrations.AddField(
model_name="userdashou",
name="last_tixian_date",
field=models.DateField(blank=True, null=True, verbose_name="最近提现日期"),
),
migrations.AddField(
model_name="usershangjia",
name="ewai_xiane",
field=models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=10,
verbose_name="额外提现限额(元)",
),
),
migrations.AddField(
model_name="usershangjia",
name="jinritixian_jine",
field=models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=10,
verbose_name="今日已提现金额",
),
),
migrations.AddField(
model_name="usershangjia",
name="kaioi_ewai_xiane",
field=models.BooleanField(
default=False, verbose_name="是否开启额外提现限额"
),
),
migrations.AddField(
model_name="usershangjia",
name="last_tixian_date",
field=models.DateField(blank=True, null=True, verbose_name="最近提现日期"),
),
migrations.CreateModel(
name="TixianAutoRecord",
fields=[
("id", models.BigAutoField(primary_key=True, serialize=False)),
(
"tixian_id",
models.CharField(
db_index=True,
max_length=32,
unique=True,
verbose_name="提现订单号(自定义)",
),
),
(
"yonghuid",
models.CharField(
db_index=True, max_length=7, verbose_name="用户ID"
),
),
("leixing", models.IntegerField(verbose_name="提现类型 1打手 2管事")),
(
"jine",
models.DecimalField(
decimal_places=2, max_digits=10, verbose_name="申请提现金额"
),
),
(
"shouxufei",
models.DecimalField(
decimal_places=2, max_digits=10, verbose_name="手续费"
),
),
(
"shijidaozhang",
models.DecimalField(
decimal_places=2, max_digits=10, verbose_name="实际到账金额"
),
),
(
"feilv",
models.DecimalField(
decimal_places=4, max_digits=5, verbose_name="费率"
),
),
(
"zhuangtai",
models.IntegerField(
choices=[(0, "处理中"), (1, "成功"), (2, "失败")],
default=0,
verbose_name="状态",
),
),
(
"wechat_transfer_no",
models.CharField(
blank=True,
max_length=64,
null=True,
verbose_name="微信转账单号",
),
),
(
"wechat_package",
models.TextField(
blank=True,
null=True,
verbose_name="微信返回的package_info(JSON)",
),
),
(
"fail_reason",
models.TextField(blank=True, null=True, verbose_name="失败原因"),
),
(
"create_time",
models.DateTimeField(auto_now_add=True, verbose_name="创建时间"),
),
(
"update_time",
models.DateTimeField(auto_now=True, verbose_name="更新时间"),
),
],
options={
"verbose_name": "自动提现记录",
"verbose_name_plural": "自动提现记录",
"db_table": "tixian_auto_record",
"indexes": [
models.Index(
fields=["tixian_id"], name="tixian_auto_tixian__273dac_idx"
),
models.Index(
fields=["yonghuid"], name="tixian_auto_yonghui_61c5b6_idx"
),
models.Index(
fields=["zhuangtai"], name="tixian_auto_zhuangt_24d9fa_idx"
),
],
},
),
]

View File

@@ -0,0 +1,61 @@
# Generated by Django 4.2.27 on 2026-03-05 16:11
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("yonghu", "0008_userdashou_ewai_xiane_userdashou_jinritixian_jine_and_more"),
]
operations = [
migrations.RemoveField(
model_name="usershangjia",
name="ewai_xiane",
),
migrations.RemoveField(
model_name="usershangjia",
name="jinritixian_jine",
),
migrations.RemoveField(
model_name="usershangjia",
name="kaioi_ewai_xiane",
),
migrations.RemoveField(
model_name="usershangjia",
name="last_tixian_date",
),
migrations.AddField(
model_name="userguanshi",
name="ewai_xiane",
field=models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=10,
verbose_name="额外提现限额(元)",
),
),
migrations.AddField(
model_name="userguanshi",
name="jinritixian_jine",
field=models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=10,
verbose_name="今日已提现金额",
),
),
migrations.AddField(
model_name="userguanshi",
name="kaioi_ewai_xiane",
field=models.BooleanField(
default=False, verbose_name="是否开启额外提现限额"
),
),
migrations.AddField(
model_name="userguanshi",
name="last_tixian_date",
field=models.DateField(blank=True, null=True, verbose_name="最近提现日期"),
),
]

View File

@@ -0,0 +1,20 @@
# Generated by Django 4.2.27 on 2026-03-06 21:46
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("yonghu", "0009_remove_usershangjia_ewai_xiane_and_more"),
]
operations = [
migrations.AlterField(
model_name="tixianjilu",
name="shenheid",
field=models.CharField(
db_index=True, max_length=11, null=True, verbose_name="审核用户ID"
),
),
]

View File

@@ -0,0 +1,23 @@
# Generated by Django 4.2.27 on 2026-03-10 21:32
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("yonghu", "0010_alter_tixianjilu_shenheid"),
]
operations = [
migrations.AddField(
model_name="userguanshi",
name="invite_qrcode_url",
field=models.CharField(
blank=True,
max_length=500,
null=True,
verbose_name="邀请码二维码图片URL",
),
),
]

View File

@@ -0,0 +1,181 @@
# Generated by Django 4.2.27 on 2026-03-19 15:28
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
("yonghu", "0011_userguanshi_invite_qrcode_url"),
]
operations = [
migrations.AddField(
model_name="userguanshi",
name="fenghong_erci",
field=models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=10,
verbose_name="二次分红金额",
),
),
migrations.AddField(
model_name="userguanshi",
name="fenghong_erci_enabled",
field=models.BooleanField(default=False, verbose_name="开启二次分红"),
),
migrations.CreateModel(
name="UserZuzhang",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"yaoqingma",
models.CharField(
db_index=True,
max_length=20,
unique=True,
verbose_name="组长邀请码",
),
),
(
"fenyong_zonge",
models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=12,
verbose_name="分佣总额(元)",
),
),
(
"ketixian_jine",
models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=12,
verbose_name="可提现金额(元)",
),
),
(
"yaoqing_zongshu",
models.IntegerField(default=0, verbose_name="邀请总数"),
),
(
"jinri_fenyong",
models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=10,
verbose_name="今日分佣(元)",
),
),
(
"jinyue_fenyong",
models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=10,
verbose_name="今月分佣(元)",
),
),
(
"zhuangtai",
models.IntegerField(
choices=[(0, "禁用"), (1, "正常")],
default=1,
verbose_name="账号状态",
),
),
(
"haibao_url",
models.CharField(
blank=True,
max_length=500,
null=True,
verbose_name="推广海报相对URL",
),
),
(
"jinri_tixian",
models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=10,
verbose_name="今日提现金额(元)",
),
),
(
"last_tixian_time",
models.DateTimeField(
blank=True, null=True, verbose_name="最后提现时间"
),
),
(
"ewai_tixian_xiane",
models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=10,
verbose_name="额外提现限额(元)",
),
),
(
"kaioi_ewai_tixian",
models.BooleanField(default=False, verbose_name="开启额外提现"),
),
(
"kaioi_ewai_fenhong",
models.BooleanField(default=False, verbose_name="开启额外分红"),
),
(
"ewai_fenhong_jine",
models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=10,
verbose_name="额外分红金额(元)",
),
),
(
"create_time",
models.DateTimeField(auto_now_add=True, verbose_name="创建时间"),
),
(
"update_time",
models.DateTimeField(auto_now=True, verbose_name="更新时间"),
),
(
"user",
models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE,
related_name="zuzhang_profile",
to=settings.AUTH_USER_MODEL,
verbose_name="关联用户",
),
),
],
options={
"verbose_name": "组长扩展表",
"verbose_name_plural": "组长扩展表",
"db_table": "user_zuzhang",
"indexes": [
models.Index(
fields=["user"], name="user_zuzhan_user_id_8064f2_idx"
),
models.Index(
fields=["yaoqingma"], name="user_zuzhan_yaoqing_cba91d_idx"
),
],
},
),
]

View File

@@ -0,0 +1,20 @@
# Generated by Django 4.2.27 on 2026-03-19 16:07
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("yonghu", "0012_userguanshi_fenghong_erci_and_more"),
]
operations = [
migrations.AddField(
model_name="userguanshi",
name="yaoqingren",
field=models.CharField(
db_index=True, max_length=7, null=True, verbose_name="邀请人ID"
),
),
]

View File

@@ -0,0 +1,20 @@
# Generated by Django 4.2.27 on 2026-05-03 12:28
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("yonghu", "0013_userguanshi_yaoqingren"),
]
operations = [
migrations.AddField(
model_name="usermain",
name="session_key",
field=models.CharField(
blank=True, max_length=100, null=True, verbose_name="微信虚拟支付"
),
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 4.2.27 on 2026-05-13 08:51
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("yonghu", "0014_usermain_session_key"),
]
operations = [
migrations.AddField(
model_name="usermain",
name="shoujihao_renzheng",
field=models.BooleanField(default=False, verbose_name="手机号是否已认证"),
),
]

View File

@@ -0,0 +1,100 @@
# Generated by Django 4.2.27 on 2026-05-19 17:30
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
("yonghu", "0015_usermain_shoujihao_renzheng"),
]
operations = [
migrations.CreateModel(
name="UserShenheguan",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"zhuangtai",
models.IntegerField(
choices=[(0, "禁用"), (1, "正常")],
default=1,
verbose_name="账号状态",
),
),
(
"is_renzheng",
models.BooleanField(default=False, verbose_name="是否认证"),
),
(
"shenhe_zhuangtai",
models.IntegerField(
choices=[(0, "空闲"), (1, "审核中")],
default=0,
verbose_name="审核官状态",
),
),
(
"shenhe_zongshu",
models.IntegerField(default=0, verbose_name="审核总数"),
),
(
"tongguo_zongshu",
models.IntegerField(default=0, verbose_name="通过总数"),
),
(
"yue",
models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=12,
verbose_name="可提现余额",
),
),
(
"zonge",
models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=12,
verbose_name="赚取总额",
),
),
(
"create_time",
models.DateTimeField(auto_now_add=True, verbose_name="创建时间"),
),
(
"update_time",
models.DateTimeField(auto_now=True, verbose_name="更新时间"),
),
(
"user",
models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE,
related_name="shenheguan_profile",
to=settings.AUTH_USER_MODEL,
verbose_name="关联用户",
),
),
],
options={
"verbose_name": "审核官扩展表",
"verbose_name_plural": "审核官扩展表",
"db_table": "user_shenheguan",
"indexes": [
models.Index(fields=["user"], name="user_shenhe_user_id_624f19_idx")
],
},
),
]

View File

@@ -0,0 +1,197 @@
# Generated by Django 4.2.27 on 2026-06-08 17:30
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("yonghu", "0016_usershenheguan"),
]
operations = [
migrations.AddField(
model_name="tixianautorecord",
name="shenhe_danhao",
field=models.CharField(
blank=True,
db_index=True,
max_length=32,
null=True,
verbose_name="关联审核单号",
),
),
migrations.AddField(
model_name="tixianjilu",
name="shenhe_danhao",
field=models.CharField(
blank=True,
db_index=True,
max_length=32,
null=True,
verbose_name="关联提现审核单号",
),
),
migrations.AddField(
model_name="tixianjilu",
name="shenhe_jilu_id",
field=models.IntegerField(
blank=True,
db_index=True,
null=True,
verbose_name="关联提现审核记录ID(TixianShenheJilu.id)",
),
),
migrations.CreateModel(
name="TixianShenheJilu",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"shenhe_danhao",
models.CharField(
db_index=True,
max_length=32,
unique=True,
verbose_name="审核单号",
),
),
(
"yonghuid",
models.CharField(
db_index=True, max_length=7, verbose_name="用户ID"
),
),
(
"leixing",
models.PositiveSmallIntegerField(
db_index=True, verbose_name="提现类型"
),
),
(
"zhuangtai",
models.IntegerField(
db_index=True,
default=1,
verbose_name="审核状态(1审核中2提现成功3提现失败4审核成功5审核失败6待收款)",
),
),
(
"shenqing_jine",
models.DecimalField(
decimal_places=2,
max_digits=10,
verbose_name="申请提现金额(扣款额)",
),
),
(
"shouxufei",
models.DecimalField(
decimal_places=2,
default=0,
max_digits=10,
verbose_name="手续费",
),
),
(
"shijidaozhang",
models.DecimalField(
decimal_places=2, max_digits=10, verbose_name="实际到账金额"
),
),
(
"feilv",
models.DecimalField(
decimal_places=4,
default=0,
max_digits=5,
verbose_name="手续费率",
),
),
(
"bhliyou",
models.TextField(
blank=True, null=True, verbose_name="驳回/失败原因"
),
),
(
"bo_hui_ren_id",
models.CharField(
blank=True,
db_index=True,
max_length=11,
null=True,
verbose_name="驳回人用户ID",
),
),
(
"shenhe_ren_id",
models.CharField(
blank=True,
db_index=True,
max_length=11,
null=True,
verbose_name="审核通过操作人ID",
),
),
(
"tixianjilu_id",
models.IntegerField(
blank=True,
db_index=True,
null=True,
verbose_name="关联Tixianjilu.id",
),
),
(
"tixian_auto_id",
models.CharField(
blank=True,
db_index=True,
max_length=32,
null=True,
verbose_name="最近一次打款单号(非唯一,重试收款会更新)",
),
),
(
"fail_reason",
models.TextField(
blank=True, null=True, verbose_name="微信打款失败原因"
),
),
(
"create_time",
models.DateTimeField(auto_now_add=True, verbose_name="创建时间"),
),
(
"update_time",
models.DateTimeField(auto_now=True, verbose_name="更新时间"),
),
],
options={
"verbose_name": "提现审核记录",
"verbose_name_plural": "提现审核记录",
"db_table": "tixian_shenhe_jilu",
"indexes": [
models.Index(
fields=["yonghuid", "zhuangtai"],
name="tixian_shen_yonghui_a782e9_idx",
),
models.Index(
fields=["yonghuid", "leixing"],
name="tixian_shen_yonghui_bb44eb_idx",
),
models.Index(
fields=["shenhe_danhao"], name="tixian_shen_shenhe__4a1ca7_idx"
),
],
},
),
]

View File

@@ -0,0 +1,20 @@
# Generated by Django 4.2.27 on 2026-06-08 18:23
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("yonghu", "0017_tixianautorecord_shenhe_danhao_and_more"),
]
operations = [
migrations.AddField(
model_name="tixianjilu",
name="dakuan_mode",
field=models.PositiveSmallIntegerField(
db_index=True, default=1, verbose_name="打款方式(1手动2自动)"
),
),
]

View File

596
yonghu/models.py Normal file
View File

@@ -0,0 +1,596 @@
# models.py
from django.db import models
import random
import string
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
# ==================== 用户主表 ====================
class UserMain(AbstractBaseUser):
# ID字段
id = models.AutoField(primary_key=True, verbose_name='主键ID')
yonghuid = models.CharField(max_length=7, unique=True, db_index=True, verbose_name='用户ID')
# 微信相关字段
openid = models.CharField(max_length=64, unique=True, db_index=True, verbose_name='微信OpenID')
unionid = models.CharField(max_length=64, null=True, blank=True, db_index=True, verbose_name='微信UnionID')
session_key = models.CharField(max_length=100, blank=True, null=True,verbose_name='微信虚拟支付')
# 基础信息字段
#tupian_url = models.CharField(max_length=500, null=True, blank=True, verbose_name='商品图片URL') # 用CharField
avatar = models.CharField(max_length=500, null=True, blank=True, default='a_long/morentouxiang.jpg', verbose_name='头像') # 用CharField
phone = models.CharField(max_length=11, blank=True, null=True, verbose_name='手机号')
shoujihao_renzheng = models.BooleanField(default=False, verbose_name='手机号是否已认证')
password = models.CharField(max_length=200, null=True, blank=True, verbose_name='密码')
zhifu = models.CharField(max_length=500, null=True, blank=True, verbose_name='收款码图片') # 用CharField
skzhanghao = models.CharField(max_length=11, blank=True, null=True, verbose_name='收款账号')
ip = models.CharField(max_length=50, blank=True, null=True, verbose_name='来访用户ip')
last_login_time = models.DateTimeField(null=True, blank=True, verbose_name='最后登录时间')
# 用户类型字段
user_type = models.CharField(
max_length=10,
choices=[
('normal', '普通用户'),
('dashou', '打手'),
('shop', '商家'),
('guanshi', '管事'),
('admin', '管理员')
],
default='normal',
verbose_name='用户类型'
)
# 状态和时间字段
#is_active = models.BooleanField(default=True, verbose_name='是否激活')
#last_login = models.DateTimeField(blank=True, null=True, verbose_name='最后登录时间')
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')
# 邀请码字段
#yaoqingma = models.CharField(max_length=20, blank=True, null=True, verbose_name='邀请码')
# 只需要添加这3行
USERNAME_FIELD = 'openid' # 用openid作为用户名
REQUIRED_FIELDS = ['yonghuid'] # 必填字段
class Meta:
db_table = 'user_main'
verbose_name = '用户主表'
verbose_name_plural = verbose_name
indexes = [
models.Index(fields=['yonghuid']),
models.Index(fields=['openid']),
#models.Index(fields=['phone']),
models.Index(fields=['user_type']),
#models.Index(fields=['create_time']),
]
def __str__(self):
return f'{self.yonghuid}'
# 新增服务号用户表
class OfficialAccountUser(models.Model):
unionid = models.CharField(max_length=64, null =True,db_index=True, verbose_name='UnionID')
official_openid = models.CharField(max_length=64, db_index=True, unique=True, verbose_name='服务号OpenID')
subscribe_time = models.DateTimeField(auto_now_add=True, verbose_name='关注时间')
is_subscribed = models.BooleanField(default=True, verbose_name='是否关注')
created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
class Meta:
db_table = 'official_account_user'
verbose_name = '服务号用户'
verbose_name_plural = verbose_name
def __str__(self):
return f"{self.unionid[:8]}... (关注: {self.is_subscribed})"
# ==================== 老板扩展表 ====================
class UserBoss(models.Model):
user = models.OneToOneField(UserMain, on_delete=models.CASCADE, related_name='boss_profile',
verbose_name='关联用户')
nickname = models.CharField(max_length=50, verbose_name='老板昵称')
zonge = models.DecimalField(max_digits=12, decimal_places=2, default=0.00, verbose_name='消费总额')
alldingdan = models.IntegerField(default=0, verbose_name='订单总数')
alltui = models.IntegerField(default=0, verbose_name='退款总数')
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
class Meta:
db_table = 'user_boss'
verbose_name = '老板扩展表'
verbose_name_plural = verbose_name
indexes = [models.Index(fields=['user']), ]
# ==================== 打手扩展表 ====================
class UserDashou(models.Model):
user = models.OneToOneField(UserMain, on_delete=models.CASCADE, related_name='dashou_profile',
verbose_name='关联用户')
nicheng = models.CharField(max_length=50, null=True, verbose_name='打手昵称')
chenghao = models.CharField(max_length=50, null=True,verbose_name='打手称号')
zhuangtai = models.IntegerField(default=1, verbose_name='打手状态')
zaixianzhuangtai = models.IntegerField(default=1, verbose_name='打手在线状态')
zhanghaozhuangtai = models.IntegerField(default=1, verbose_name='打手账号状态')
jieshao = models.TextField(null=True, verbose_name='打手介绍')
jiedanzongliang = models.IntegerField(default=0, verbose_name='接单总量')
chengjiaozongliang = models.IntegerField(default=0, verbose_name='成交单总量')
tuikuanliang = models.IntegerField(default=0, verbose_name='退款订单总量')
yue = models.DecimalField(max_digits=12, decimal_places=2, default=0.00, verbose_name='可提现余额')
zonge = models.DecimalField(max_digits=12, decimal_places=2, default=0.00, verbose_name='打单赚取总额')
dianhua = models.CharField(max_length=20, null=True, verbose_name='打手电话')
wechat = models.CharField(max_length=50,null=True, verbose_name='打手微信号')
yaoqingren = models.CharField(max_length=7,null=True, db_index=True, verbose_name='邀请人ID')
jinrijiedan = models.IntegerField(default=0, verbose_name='今日接单数量')
jinrishouyi = models.DecimalField(max_digits=10, decimal_places=2, default=0.00, verbose_name='今日收益金额')
jinyuejiedan = models.IntegerField(default=0, verbose_name='今月接单数量')
jinyueshouyi = models.DecimalField(max_digits=10, decimal_places=2, default=0.00, verbose_name='今月收益金额')
jifen = models.IntegerField(default=0, verbose_name='打手积分')
yajin= models.DecimalField(max_digits=12, decimal_places=2, default=0.00, verbose_name='打手押金')
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
last_tixian_date = models.DateField(null=True, blank=True, verbose_name='最近提现日期') # 用于重置今日提现金额
jinritixian_jine = models.DecimalField(max_digits=10, decimal_places=2, default=0.00, verbose_name='今日已提现金额')
kaioi_ewai_xiane = models.BooleanField(default=False, verbose_name='是否开启额外提现限额') # True=开启额外限额
ewai_xiane = models.DecimalField(max_digits=10, decimal_places=2, default=0.00, verbose_name='额外提现限额(元)')
class Meta:
db_table = 'user_dashou'
verbose_name = '打手扩展表'
verbose_name_plural = verbose_name
indexes = [
models.Index(fields=['user']),
#models.Index(fields=['zhuangtai']),
models.Index(fields=['yaoqingren']),
#models.Index(fields=['nicheng']),
]
# ==================== 商家扩展表 ====================
class UserShangjia(models.Model):
user = models.OneToOneField(UserMain, on_delete=models.CASCADE, related_name='shop_profile',
verbose_name='关联用户')
nicheng = models.CharField(max_length=50, unique=True, db_index=True, verbose_name='商家昵称')
zhuangtai = models.IntegerField(choices=[(0, '待审核'), (1, '正常'), (2, '禁用')], default=1,
verbose_name='商家状态')
dianhua = models.CharField(max_length=20,null=True,verbose_name='商家电话')
wechat = models.CharField(max_length=50, null=True, verbose_name='商家微信号')
fabu = models.IntegerField(default=0, verbose_name='发布订单总数量')
tuikuan = models.IntegerField(default=0, verbose_name='退款订单总量')
yue = models.DecimalField(max_digits=12, decimal_places=2, default=0.00, verbose_name='商家余额')
chengjiao = models.IntegerField(default=0, verbose_name='商家成交订单总量')
jinridingdan = models.IntegerField(default=0, verbose_name='商家今日订单总量')
jinriliushui = models.DecimalField(max_digits=12, decimal_places=2, default=0.00, verbose_name='商家今日流水')
jinyuedingdan = models.IntegerField(default=0, verbose_name='商家今月订单总量')
jinyueliushui = models.DecimalField(max_digits=12, decimal_places=2, default=0.00, verbose_name='商家今月流水')
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
class Meta:
db_table = 'user_shangjia'
verbose_name = '商家扩展表'
verbose_name_plural = verbose_name
indexes = [
models.Index(fields=['user']),
models.Index(fields=['nicheng']),
]
# ==================== 管事扩展表 ====================
class UserGuanshi(models.Model):
user = models.OneToOneField(UserMain, on_delete=models.CASCADE, related_name='guanshi_profile',
verbose_name='关联用户')
yaoqingren = models.CharField(max_length=7, null=True, db_index=True, verbose_name='邀请人ID')
yaoqingma = models.CharField(max_length=20,null=True,db_index=True, verbose_name='邀请码')
invite_qrcode_url = models.CharField(max_length=500, null=True, blank=True, verbose_name='邀请码二维码图片URL')
dianhua = models.CharField(max_length=20,null=True, verbose_name='管事电话')
wechat = models.CharField(max_length=50,null=True, verbose_name='管事微信号')
yaogingshuliang = models.IntegerField(default=0, verbose_name='邀请打手总数')
zhuangtai = models.IntegerField(choices=[(0, '禁用'), (1, '正常')], default=1, verbose_name='管事状态')
jinrichongzhi = models.IntegerField(default=0, verbose_name='今日充值打手数量')
jinyuechongzhi = models.IntegerField(default=0, verbose_name='今月充值打手数量')
chongzhifenrun = models.DecimalField(max_digits=12, decimal_places=2, default=0.00, verbose_name='充值分佣总额')
yue = models.DecimalField(max_digits=12, decimal_places=2, default=0.00, verbose_name='可提现余额')
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
# 新增:二次分红开关
fenghong_erci_enabled = models.BooleanField(default=False,verbose_name='开启二次分红')
# 新增:二次分红金额
fenghong_erci = models.DecimalField(max_digits=10,decimal_places=2,default=0.00,verbose_name='二次分红金额')
last_tixian_date = models.DateField(null=True, blank=True, verbose_name='最近提现日期')
jinritixian_jine = models.DecimalField(max_digits=10, decimal_places=2, default=0.00, verbose_name='今日已提现金额')
kaioi_ewai_xiane = models.BooleanField(default=False, verbose_name='是否开启额外提现限额')
ewai_xiane = models.DecimalField(max_digits=10, decimal_places=2, default=0.00, verbose_name='额外提现限额(元)')
class Meta:
db_table = 'user_guanshi'
verbose_name = '管事扩展表'
verbose_name_plural = verbose_name
indexes = [models.Index(fields=['user']),
models.Index(fields=['yaoqingma']),
]
class UserZuzhang(models.Model):
"""组长扩展表与UserMain一对一关联"""
user = models.OneToOneField(
UserMain,
on_delete=models.CASCADE,
related_name='zuzhang_profile',
verbose_name='关联用户',
db_index=True
)
# 组长邀请码
yaoqingma = models.CharField(max_length=20, unique=True, db_index=True, verbose_name='组长邀请码')
# 分佣总额
fenyong_zonge = models.DecimalField(max_digits=12, decimal_places=2, default=0.00, verbose_name='分佣总额(元)')
# 可提现金额
ketixian_jine = models.DecimalField(max_digits=12, decimal_places=2, default=0.00, verbose_name='可提现金额(元)')
# 邀请总数
yaoqing_zongshu = models.IntegerField(default=0, verbose_name='邀请总数')
# 今日分佣
jinri_fenyong = models.DecimalField(max_digits=10, decimal_places=2, default=0.00, verbose_name='今日分佣(元)')
# 今月分佣
jinyue_fenyong = models.DecimalField(max_digits=10, decimal_places=2, default=0.00, verbose_name='今月分佣(元)')
# 账号状态
zhuangtai = models.IntegerField(choices=[(0, '禁用'), (1, '正常')], default=1, verbose_name='账号状态')
# 推广海报相对URL
haibao_url = models.CharField(max_length=500, null=True, blank=True, verbose_name='推广海报相对URL')
# 今日提现
jinri_tixian = models.DecimalField(max_digits=10, decimal_places=2, default=0.00, verbose_name='今日提现金额(元)')
# 最后提现时间
last_tixian_time = models.DateTimeField(null=True, blank=True, verbose_name='最后提现时间')
# 额外提现限额
ewai_tixian_xiane = models.DecimalField(max_digits=10, decimal_places=2, default=0.00, verbose_name='额外提现限额(元)')
# 是否开启额外提现
kaioi_ewai_tixian = models.BooleanField(default=False, verbose_name='开启额外提现')
# 是否开启额外分红
kaioi_ewai_fenhong = models.BooleanField(default=False, verbose_name='开启额外分红')
# 额外分红金额
ewai_fenhong_jine = models.DecimalField(max_digits=10, decimal_places=2, default=0.00, verbose_name='额外分红金额(元)')
# 创建时间
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
# 更新时间
update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')
class Meta:
db_table = 'user_zuzhang'
verbose_name = '组长扩展表'
verbose_name_plural = verbose_name
indexes = [
models.Index(fields=['user']),
models.Index(fields=['yaoqingma']),
]
def __str__(self):
return f"组长 {self.user.yonghuid}"
# ==================== 管理员扩展表 ====================
class AdminProfile(models.Model):
user = models.OneToOneField(UserMain, on_delete=models.CASCADE, related_name='admin_profile',
verbose_name='关联用户')
password = models.CharField(max_length=255, verbose_name='密码')
wechat = models.CharField(max_length=50, blank=True, verbose_name='管理员微信')
yaoqingma = models.CharField(max_length=20, null=True, db_index=True,verbose_name='管理员邀请码') # 🟢 新增字段
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
class Meta:
db_table = 'admin_profile'
verbose_name = '管理员扩展表'
verbose_name_plural = verbose_name
indexes = [models.Index(fields=['user']), ]
class UserKefu(models.Model):
user = models.OneToOneField(UserMain, on_delete=models.CASCADE, related_name='kefu_profile', verbose_name='关联用户')
nicheng = models.CharField(max_length=50, verbose_name='客服昵称')
erjimima = models.CharField(max_length=128, verbose_name='二级密码')
zhuangtai = models.IntegerField(choices=[(0, '禁用'), (1, '正常')], default=1, verbose_name='客服状态')
jinrichuli = models.IntegerField(default=0, verbose_name='今日处理订单数')
jinyuechuli = models.IntegerField(default=0, verbose_name='本月处理订单数')
zongchuli = models.IntegerField(default=0, verbose_name='累计处理订单数')
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')
class Meta:
db_table = 'user_kefu'
verbose_name = '客服扩展表'
verbose_name_plural = verbose_name
indexes = [
models.Index(fields=['user']),
models.Index(fields=['zhuangtai']),
]
def __str__(self):
return f"{self.nicheng} ({self.user.yonghuid})"
class UserShenheguan(models.Model):
"""审核官扩展表与UserMain一对一关联"""
user = models.OneToOneField(UserMain, on_delete=models.CASCADE, related_name='shenheguan_profile', verbose_name='关联用户', db_index=True)
zhuangtai = models.IntegerField(choices=[(0, '禁用'), (1, '正常')], default=1, verbose_name='账号状态')
is_renzheng = models.BooleanField(default=False, verbose_name='是否认证')
shenhe_zhuangtai = models.IntegerField(choices=[(0, '空闲'), (1, '审核中')], default=0, verbose_name='审核官状态')
shenhe_zongshu = models.IntegerField(default=0, verbose_name='审核总数')
tongguo_zongshu = models.IntegerField(default=0, verbose_name='通过总数')
yue = models.DecimalField(max_digits=12, decimal_places=2, default=0.00, verbose_name='可提现余额')
zonge = models.DecimalField(max_digits=12, decimal_places=2, default=0.00, verbose_name='赚取总额')
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')
class Meta:
db_table = 'user_shenheguan'
verbose_name = '审核官扩展表'
verbose_name_plural = verbose_name
indexes = [models.Index(fields=['user'])]
class Tixianjilu(models.Model):
id = models.AutoField(primary_key=True, verbose_name='提现记录ID')
yonghuid = models.CharField(max_length=7, db_index=True, verbose_name='提现用户ID')
avatar = models.CharField(max_length=500, null=True, blank=True, verbose_name='头像') # 用CharField
phone = models.CharField(max_length=11, blank=True, null=True, verbose_name='手机号')
nicheng = models.CharField(max_length=50, null=True, verbose_name='打手昵称')
leixing = models.PositiveIntegerField(null=True, blank=True, verbose_name='提现类型1:打手佣金2管事分红')
zhifu = models.CharField(max_length=500, null=True, blank=True, verbose_name='收款码图片') # 用CharField
skzhanghao = models.CharField(max_length=11, blank=True, null=True, verbose_name='收款账号')
jine = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True, verbose_name='提现金额')
# 状态与平台:用整数表示,具体含义由业务逻辑定义
zhuangtai = models.IntegerField(default=1, null=True, blank=True, db_index=True, verbose_name='提现状态1:审核2成功3失败')
fangshi = models.IntegerField(null=True, blank=True,db_index=True, verbose_name='收款方式1:微信2支付宝')
dakuan_mode = models.PositiveSmallIntegerField(
default=1, db_index=True, verbose_name='打款方式(1手动2自动)'
)
shenheid = models.CharField(max_length=11, null=True, db_index=True, verbose_name='审核用户ID')
bhliyou = models.TextField(null=True, blank=True, verbose_name='驳回理由')
# ---------- 自动提现审核新流程关联字段(旧数据为空,兼容历史记录) ----------
shenhe_jilu_id = models.IntegerField(
null=True, blank=True, db_index=True,
verbose_name='关联提现审核记录ID(TixianShenheJilu.id)'
)
shenhe_danhao = models.CharField(
max_length=32, null=True, blank=True, db_index=True,
verbose_name='关联提现审核单号'
)
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')
class Meta:
db_table = 'tixianjilu'
verbose_name = '提现记录表'
verbose_name_plural = verbose_name
indexes = [models.Index(fields=['yonghuid']),
models.Index(fields=['zhuangtai']),
models.Index(fields=['shenheid']),
models.Index(fields=['fangshi']),
]
class TixianShenheJilu(models.Model):
"""
提现审核记录表(自动打款新流程)
状态码与前端 TX_STATUS / Tixianjilu.zhuangtai 完全对标:
1=审核中 2=提现成功(已收款) 3=提现失败 4=审核成功 5=审核失败 6=待收款
"""
# 审核单号(唯一,前端字段 shenhe_danhao
shenhe_danhao = models.CharField(
max_length=32, unique=True, db_index=True, verbose_name='审核单号'
)
yonghuid = models.CharField(max_length=7, db_index=True, verbose_name='用户ID')
# 提现类型1打手佣金 2管事分红 3组长分红 4考核官分佣 5打手押金 6商家余额
leixing = models.PositiveSmallIntegerField(db_index=True, verbose_name='提现类型')
zhuangtai = models.IntegerField(
default=1, db_index=True,
verbose_name='审核状态(1审核中2提现成功3提现失败4审核成功5审核失败6待收款)'
)
# 金额shenqing_jine=申请扣款金额shijidaozhang=实际打款到账金额
shenqing_jine = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='申请提现金额(扣款额)')
shouxufei = models.DecimalField(max_digits=10, decimal_places=2, default=0, verbose_name='手续费')
shijidaozhang = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='实际到账金额')
feilv = models.DecimalField(max_digits=5, decimal_places=4, default=0, verbose_name='手续费率')
# 审核/驳回
bhliyou = models.TextField(null=True, blank=True, verbose_name='驳回/失败原因')
bo_hui_ren_id = models.CharField(
max_length=11, null=True, blank=True, db_index=True, verbose_name='驳回人用户ID'
)
shenhe_ren_id = models.CharField(
max_length=11, null=True, blank=True, db_index=True, verbose_name='审核通过操作人ID'
)
# 关联提现记录表主键
tixianjilu_id = models.IntegerField(null=True, blank=True, db_index=True, verbose_name='关联Tixianjilu.id')
# 最近一次打款单号(仅作记录,不唯一;同一审核单可多次收款产生多条打款记录)
tixian_auto_id = models.CharField(
max_length=32, null=True, blank=True, db_index=True,
verbose_name='最近一次打款单号(非唯一,重试收款会更新)'
)
fail_reason = models.TextField(null=True, blank=True, verbose_name='微信打款失败原因')
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')
class Meta:
db_table = 'tixian_shenhe_jilu'
verbose_name = '提现审核记录'
verbose_name_plural = verbose_name
indexes = [
models.Index(fields=['yonghuid', 'zhuangtai']),
models.Index(fields=['yonghuid', 'leixing']),
models.Index(fields=['shenhe_danhao']),
]
def __str__(self):
return f'{self.shenhe_danhao}({self.yonghuid})'
class TixianAutoRecord(models.Model):
"""
自动提现记录表(微信自动打款)
"""
id = models.BigAutoField(primary_key=True)
tixian_id = models.CharField(
max_length=32,
unique=True,
db_index=True,
verbose_name='提现订单号(自定义)'
)
yonghuid = models.CharField(max_length=7, db_index=True, verbose_name='用户ID')
leixing = models.IntegerField(verbose_name='提现类型 1打手 2管事')
jine = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='申请提现金额')
shouxufei = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='手续费')
shijidaozhang = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='实际到账金额')
feilv = models.DecimalField(max_digits=5, decimal_places=4, verbose_name='费率')
zhuangtai = models.IntegerField(
default=0,
choices=[(0, '处理中'), (1, '成功'), (2, '失败')],
verbose_name='状态'
)
wechat_transfer_no = models.CharField(
max_length=64,
null=True,
blank=True,
verbose_name='微信转账单号'
)
wechat_package = models.TextField(
null=True,
blank=True,
verbose_name='微信返回的package_info(JSON)'
)
fail_reason = models.TextField(null=True, blank=True, verbose_name='失败原因')
# 关联提现审核单号(新流程必填,旧数据为空)
shenhe_danhao = models.CharField(
max_length=32, null=True, blank=True, db_index=True, verbose_name='关联审核单号'
)
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')
class Meta:
db_table = 'tixian_auto_record'
verbose_name = '自动提现记录'
verbose_name_plural = verbose_name
indexes = [
models.Index(fields=['tixian_id']),
models.Index(fields=['yonghuid']),
models.Index(fields=['zhuangtai']),
]
def __str__(self):
return f"{self.tixian_id} - {self.get_zhuangtai_display()}"
# yonghu/models.py
class Xiugaijilu(models.Model):
id = models.AutoField(primary_key=True, verbose_name='记录ID')
yonghuid = models.CharField(max_length=7, verbose_name='被修改用户ID')
xiugaiid = models.CharField(max_length=30, verbose_name='修改人账号ID')
leixing = models.IntegerField(verbose_name='被修改用户类型')
# 打手相关金钱字段
xiugaitijiao = models.DecimalField(max_digits=12, decimal_places=2, default=0.00,
verbose_name='修改后的打手提现金额')
xiugaitijiaoq = models.DecimalField(max_digits=12, decimal_places=2, default=0.00,
verbose_name='修改前的打手提现金额')
# 打手积分
jifen = models.IntegerField(default=0, verbose_name='修改后的打手积分')
yjifen = models.IntegerField(default=0, verbose_name='修改前的打手积分')
# 打手押金
yajin = models.DecimalField(max_digits=12, decimal_places=2, default=0.00, verbose_name='修改后的打手押金')
yyajin = models.DecimalField(max_digits=12, decimal_places=2, default=0.00, verbose_name='修改前的打手押金')
# 商家余额
shangjiayue = models.DecimalField(max_digits=12, decimal_places=2, default=0.00, verbose_name='修改后的商家余额')
shangjiayueq = models.DecimalField(max_digits=12, decimal_places=2, default=0.00, verbose_name='修改前的商家余额')
# 管事余额
guanshiyue = models.DecimalField(max_digits=12, decimal_places=2, default=0.00, verbose_name='修改后的管事余额')
guanshiyueq = models.DecimalField(max_digits=12, decimal_places=2, default=0.00, verbose_name='修改前的管事余额')
# 会员相关
huiyuants = models.IntegerField(default=0, verbose_name='添加会员天数')
huiyuan_id = models.CharField(max_length=6, null=True, blank=True, verbose_name='会员ID')
# 其他字段
qitashuoming = models.TextField(null=True, blank=True, verbose_name='其他说明')
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')
class Meta:
db_table = 'xiugaijilu'
verbose_name = '修改记录表'
verbose_name_plural = verbose_name
def __str__(self):
return f"修改记录-用户{self.yonghuid}"
# yonghu/models.py - 新增排行榜模型
class RankingRecord(models.Model):
# id: 主键ID
id = models.AutoField(primary_key=True, verbose_name='ID')
# zhouqi: 周期类型1=日榜2=月榜
zhouqi = models.IntegerField(choices=[(1, '日榜'), (2, '月榜')], verbose_name='周期类型')
# tongji_date: 统计日期(日榜存具体日期,月榜存月份第一天)
tongji_date = models.DateField(db_index=True, verbose_name='统计日期')
# shenfen: 用户身份2=打手3=管事4=商家1=普通用户不统计)
shenfen = models.IntegerField(choices=[(2, '打手'), (3, '管事'), (4, '商家')], verbose_name='用户身份')
# yonghuid: 用户ID冗余存储避免连表查询
yonghuid = models.CharField(max_length=7, db_index=True, verbose_name='用户ID')
# paiming: 排名从1开始
paiming = models.IntegerField(verbose_name='排名')
# zhizhi: 指标数值(打手:收益金额,管事:充值人数,商家:流水金额)
zhizhi = models.DecimalField(max_digits=12, decimal_places=2, default=0.00, verbose_name='指标值')
# nicheng: 用户昵称
nicheng = models.CharField(max_length=50, null=True,verbose_name='用户昵称')
# avatar: 用户头像URL
avatar = models.CharField(max_length=500, blank=True, null=True, verbose_name='头像')
# chuangjian_time: 记录创建时间
chuangjian_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
class Meta:
db_table = 'ranking_record'
verbose_name = '排行榜记录'
verbose_name_plural = verbose_name
indexes = [
models.Index(fields=['zhouqi', 'tongji_date', 'shenfen', 'paiming']),
models.Index(fields=['yonghuid', 'zhouqi']),
models.Index(fields=['tongji_date']),
]
unique_together = [['zhouqi', 'tongji_date', 'shenfen', 'paiming']]
def __str__(self):
zhouqi_str = '' if self.zhouqi == 1 else ''
shenfen_map = {2: '打手', 3: '管事', 4: '商家'}
return f"{self.tongji_date} {zhouqi_str}{shenfen_map.get(self.shenfen)}{self.paiming}"

280
yonghu/ranking_tasks.py Normal file
View File

@@ -0,0 +1,280 @@
# yonghu/ranking_tasks.py
"""
排行榜数据转移任务 - 生产环境专用
在清空前将数据转移到排行榜表
"""
from celery import shared_task
from django.db import transaction
from django.utils import timezone
from datetime import datetime, timedelta
import logging
from decimal import Decimal
from yonghu.models import (
UserMain, UserDashou, UserShangjia, UserGuanshi, UserBoss,
RankingRecord
)
logger = logging.getLogger(__name__)
def get_user_nicheng(user, shenfen):
"""
获取用户昵称
规则打手用打手nicheng其他用老板nickname
"""
try:
if shenfen == 2: # 打手
dashou_profile = getattr(user, 'dashou_profile', None)
if dashou_profile and dashou_profile.nicheng:
return dashou_profile.nicheng
else: # 管事或商家
boss_profile = getattr(user, 'boss_profile', None)
if boss_profile and boss_profile.nickname:
return boss_profile.nickname
# 默认返回用户ID
return f"用户{user.yonghuid}"
except Exception:
return f"用户{user.yonghuid}"
@shared_task
def zhuanyi_ribang():
"""
转移日榜数据 - 每天23:55执行
在清零前将今日数据转移到排行榜表
"""
try:
# 统计日期(今天)
today = timezone.now().date()
logger.info(f"开始转移日榜数据,日期: {today}")
records_to_create = []
# 1. 转移打手日榜(今日收益 > 0
dashou_list = UserDashou.objects.filter(
jinrishouyi__gt=0 # 只转移收益大于0的
).select_related('user').order_by('-jinrishouyi')
for i, dashou in enumerate(dashou_list, start=1):
if i > 100: # 最多100条
break
user = dashou.user
record = RankingRecord(
zhouqi=1, # 日榜
tongji_date=today,
shenfen=2, # 打手
yonghuid=user.yonghuid,
paiming=i,
zhizhi=dashou.jinrishouyi,
nicheng=get_user_nicheng(user, 2),
avatar=user.avatar or ''
)
records_to_create.append(record)
# 2. 转移商家日榜(今日流水 > 0
shangjia_list = UserShangjia.objects.filter(
jinriliushui__gt=0 # 只转移流水大于0的
).select_related('user').order_by('-jinriliushui')
for i, shangjia in enumerate(shangjia_list, start=1):
if i > 100: # 最多100条
break
user = shangjia.user
record = RankingRecord(
zhouqi=1,
tongji_date=today,
shenfen=4, # 商家
yonghuid=user.yonghuid,
paiming=i,
zhizhi=shangjia.jinriliushui,
nicheng=get_user_nicheng(user, 4),
avatar=user.avatar or ''
)
records_to_create.append(record)
# 3. 转移管事日榜(今日充值人数 > 0
guanshi_list = UserGuanshi.objects.filter(
jinrichongzhi__gt=0 # 只转移充值人数大于0的
).select_related('user').order_by('-jinrichongzhi')
for i, guanshi in enumerate(guanshi_list, start=1):
if i > 100: # 最多100条
break
user = guanshi.user
record = RankingRecord(
zhouqi=1,
tongji_date=today,
shenfen=3, # 管事
yonghuid=user.yonghuid,
paiming=i,
zhizhi=Decimal(guanshi.jinrichongzhi),
nicheng=get_user_nicheng(user, 3),
avatar=user.avatar or ''
)
records_to_create.append(record)
# 批量保存
if records_to_create:
with transaction.atomic():
RankingRecord.objects.bulk_create(records_to_create)
logger.info(f"日榜数据转移完成,保存{len(records_to_create)}条记录")
result = {
'success': True,
'date': today.strftime('%Y-%m-%d'),
'total_count': len(records_to_create),
}
return result
except Exception as e:
logger.error(f"日榜数据转移失败: {str(e)}", exc_info=True)
raise
@shared_task
def zhuanyi_yuebang():
"""
转移月榜数据 - 每月最后一天23:50执行
在清零前将本月数据转移到排行榜表
"""
try:
# 🔥 获取当前时间
now = timezone.now()
today = now.date()
# 🔥 判断今天是否是当月的最后一天
# 方法:计算明天的日期,如果明天的月份和今天不同,那么今天就是最后一天
tomorrow = today + timedelta(days=1)
if tomorrow.month == today.month:
# 今天不是最后一天,直接返回
logger.info(f"今天不是当月最后一天({today}),跳过月榜转移")
return {
'success': True,
'message': f'今天不是当月最后一天,跳过执行',
'is_last_day': False,
'today': today.strftime('%Y-%m-%d'),
}
logger.info(f"今天是当月最后一天({today}),开始转移月榜数据")
# 🔥 统计日期为当月第一天如2024-01-01
tongji_date = datetime(today.year, today.month, 1).date()
records_to_create = []
# 1. 转移打手月榜(今月收益 > 0
dashou_list = UserDashou.objects.filter(
jinyueshouyi__gt=0 # 只转移收益大于0的
).select_related('user').order_by('-jinyueshouyi')
for i, dashou in enumerate(dashou_list, start=1):
if i > 100: # 最多100条
break
user = dashou.user
record = RankingRecord(
zhouqi=2, # 月榜
tongji_date=tongji_date,
shenfen=2, # 打手
yonghuid=user.yonghuid,
paiming=i,
zhizhi=dashou.jinyueshouyi,
nicheng=get_user_nicheng(user, 2),
avatar=user.avatar or ''
)
records_to_create.append(record)
# 2. 转移商家月榜(今月流水 > 0
shangjia_list = UserShangjia.objects.filter(
jinyueliushui__gt=0 # 只转移流水大于0的
).select_related('user').order_by('-jinyueliushui')
for i, shangjia in enumerate(shangjia_list, start=1):
if i > 100: # 最多100条
break
user = shangjia.user
record = RankingRecord(
zhouqi=2,
tongji_date=tongji_date,
shenfen=4, # 商家
yonghuid=user.yonghuid,
paiming=i,
zhizhi=shangjia.jinyueliushui,
nicheng=get_user_nicheng(user, 4),
avatar=user.avatar or ''
)
records_to_create.append(record)
# 3. 转移管事月榜(今月充值人数 > 0
guanshi_list = UserGuanshi.objects.filter(
jinyuechongzhi__gt=0 # 只转移充值人数大于0的
).select_related('user').order_by('-jinyuechongzhi')
for i, guanshi in enumerate(guanshi_list, start=1):
if i > 100: # 最多100条
break
user = guanshi.user
record = RankingRecord(
zhouqi=2,
tongji_date=tongji_date,
shenfen=3, # 管事
yonghuid=user.yonghuid,
paiming=i,
zhizhi=Decimal(guanshi.jinyuechongzhi),
nicheng=get_user_nicheng(user, 3),
avatar=user.avatar or ''
)
records_to_create.append(record)
# 批量保存
if records_to_create:
with transaction.atomic():
RankingRecord.objects.bulk_create(records_to_create)
logger.info(f"月榜数据转移完成,保存{len(records_to_create)}条记录")
result = {
'success': True,
'month': tongji_date.strftime('%Y-%m'),
'total_count': len(records_to_create),
'is_last_day': True,
'today': today.strftime('%Y-%m-%d'),
}
return result
except Exception as e:
logger.error(f"月榜数据转移失败: {str(e)}", exc_info=True)
raise
@shared_task
def qingli_jiulishuju():
"""
清理旧历史数据 - 每月1号凌晨1点执行
清理3个月前的排行榜数据保留最近3个月的数据
"""
try:
# 计算3个月前的日期
three_months_ago = timezone.now().date() - timedelta(days=90)
# 删除旧数据
deleted_count, _ = RankingRecord.objects.filter(
tongji_date__lt=three_months_ago
).delete()
logger.info(f"清理旧历史数据完成,删除{deleted_count}条记录")
return {
'success': True,
'deleted_count': deleted_count,
'before_date': three_months_ago.strftime('%Y-%m-%d')
}
except Exception as e:
logger.error(f"清理旧历史数据失败: {str(e)}")
raise

176
yonghu/tasks.py Normal file
View File

@@ -0,0 +1,176 @@
"""
阿龙电竞 - 用户定时任务
处理每日/每月清零等用户相关定时任务
完整版本,包含所有异常处理
"""
from celery import shared_task
from django.db import transaction
from django.db.models import F, Q
from django.utils import timezone
from datetime import datetime
import logging
# 导入模型
from yonghu.models import UserDashou, UserShangjia, UserGuanshi
from utils.celery_utils import log_task_execution, rollback_on_failure
logger = logging.getLogger(__name__)
@shared_task
@rollback_on_failure("每日清零任务")
def daily_reset_task():
"""
每日清零任务 - 每天凌晨0点执行
清零打手、商家、管事的今日相关字段
"""
try:
with transaction.atomic():
start_time = timezone.now()
today = datetime.now().strftime('%Y-%m-%d')
logger.info(f"开始执行每日清零任务,日期: {today}")
# 1. 清零打手今日数据
dashou_updated = UserDashou.objects.filter(
Q(jinrijiedan__gt=0) | Q(jinrishouyi__gt=0)
).update(
jinrijiedan=0,
jinrishouyi=0
)
logger.info(f"打手今日数据清零完成,影响记录: {dashou_updated}")
# 2. 清零商家今日数据
shangjia_updated = UserShangjia.objects.filter(
Q(jinridingdan__gt=0) | Q(jinriliushui__gt=0)
).update(
jinridingdan=0,
jinriliushui=0
)
logger.info(f"商家今日数据清零完成,影响记录: {shangjia_updated}")
# 3. 清零管事今日数据
guanshi_updated = UserGuanshi.objects.filter(
jinrichongzhi__gt=0
).update(
jinrichongzhi=0
)
logger.info(f"管事今日数据清零完成,影响记录: {guanshi_updated}")
end_time = timezone.now()
duration = (end_time - start_time).total_seconds()
# 记录执行结果
result_msg = (
f"每日清零完成 - 日期: {today}, "
f"打手: {dashou_updated}条, "
f"商家: {shangjia_updated}条, "
f"管事: {guanshi_updated}条, "
f"耗时: {duration:.2f}"
)
log_task_execution("每日清零任务", True, result_msg)
return {
"success": True,
"date": today,
"updated_dashou": dashou_updated,
"updated_shangjia": shangjia_updated,
"updated_guanshi": guanshi_updated,
"duration_seconds": duration,
"message": result_msg
}
except Exception as e:
error_msg = f"每日清零任务失败: {str(e)}"
logger.error(error_msg)
log_task_execution("每日清零任务", False, error_msg)
return {
"success": False,
"error": str(e),
"date": datetime.now().strftime('%Y-%m-%d'),
"message": error_msg
}
@shared_task
@rollback_on_failure("每月清零任务")
def monthly_reset_task():
"""
每月清零任务 - 每月1日凌晨0点执行
清零打手、商家、管事的本月相关字段
"""
try:
with transaction.atomic():
start_time = timezone.now()
current_month = datetime.now().strftime('%Y-%m')
logger.info(f"开始执行每月清零任务,月份: {current_month}")
# 1. 清零打手本月数据
dashou_updated = UserDashou.objects.filter(
Q(jinyuejiedan__gt=0) | Q(jinyueshouyi__gt=0)
).update(
jinyuejiedan=0,
jinyueshouyi=0
)
logger.info(f"打手本月数据清零完成,影响记录: {dashou_updated}")
# 2. 清零商家本月数据
shangjia_updated = UserShangjia.objects.filter(
Q(jinyuedingdan__gt=0) | Q(jinyueliushui__gt=0)
).update(
jinyuedingdan=0,
jinyueliushui=0
)
logger.info(f"商家本月数据清零完成,影响记录: {shangjia_updated}")
# 3. 清零管事本月数据
guanshi_updated = UserGuanshi.objects.filter(
jinyuechongzhi__gt=0
).update(
jinyuechongzhi=0
)
logger.info(f"管事本月数据清零完成,影响记录: {guanshi_updated}")
end_time = timezone.now()
duration = (end_time - start_time).total_seconds()
# 记录执行结果
result_msg = (
f"每月清零完成 - 月份: {current_month}, "
f"打手: {dashou_updated}条, "
f"商家: {shangjia_updated}条, "
f"管事: {guanshi_updated}条, "
f"耗时: {duration:.2f}"
)
log_task_execution("每月清零任务", True, result_msg)
return {
"success": True,
"month": current_month,
"updated_dashou": dashou_updated,
"updated_shangjia": shangjia_updated,
"updated_guanshi": guanshi_updated,
"duration_seconds": duration,
"message": result_msg
}
except Exception as e:
error_msg = f"每月清零任务失败: {str(e)}"
logger.error(error_msg)
log_task_execution("每月清零任务", False, error_msg)
return {
"success": False,
"error": str(e),
"month": datetime.now().strftime('%Y-%m'),
"message": error_msg
}

3
yonghu/tests.py Normal file
View File

@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,383 @@
# yonghu/tixian_shenhe_collect_b.py
"""
自动提现审核 — 用户侧接口:
① TixianZddkshApplyView → POST /yonghu/zddksh 提交审核(扣款)
② process_audit_collect → POST /yonghu/tixiansq 收款P0一单到底先查微信再决定是否新建
"""
import decimal
import json
import logging
import random
import string
import time
import requests
from django.conf import settings
from django.db import transaction
from django.utils import timezone
from rest_framework import permissions
from rest_framework.response import Response
from rest_framework.views import APIView
from .models import TixianAutoRecord, TixianShenheJilu
from .tixian_shenhe_services import (
RECONCILE_ALLOW_NEW,
RECONCILE_COMPLETED,
RECONCILE_PENDING,
RECONCILE_WAIT_CONFIRM,
check_collect_quota_limits,
create_audit_application,
get_audit_for_collect,
handle_post_transfer_failure,
reconcile_shenhe_wechat_bills,
release_collect_quota_for_record,
reserve_collect_quota_limits,
resolve_collect_context,
validate_collect_eligibility,
)
logger = logging.getLogger('yonghu.tixian_shenhe')
def generate_tixian_id():
"""生成唯一微信商户打款单号TX + 时间戳(13位) + 4位随机数"""
timestamp = str(int(time.time() * 1000))
rand = ''.join(random.choices(string.digits, k=4))
return f'TX{timestamp}{rand}'
def _build_collect_success_response(payload):
return Response({
'code': 0,
'msg': '请确认收款',
'data': payload,
})
def _is_wx_balance_insufficient(err_code='', err_msg=''):
blob = f'{err_code} {err_msg}'.upper()
return any(k in blob for k in ('NOT_ENOUGH', 'INSUFFICIENT', '余额不足', '资金不足'))
def _verify_collect_quota_or_response(user_main, audit, shenhe_danhao):
"""收款限额校验;不通过时直接返回 Response"""
ok, msg, limit_kind = check_collect_quota_limits(
user_main,
audit.leixing,
audit.shenqing_jine,
audit.shijidaozhang,
shenhe_danhao,
)
if not ok:
limit_code = 33 if limit_kind == 'platform' else 400
logger.warning(
'收款限额校验未通过 yonghuid=%s shenhe_danhao=%s leixing=%s kind=%s msg=%s',
user_main.yonghuid, shenhe_danhao, audit.leixing, limit_kind, msg,
)
return Response({'code': limit_code, 'msg': msg})
return None
def _mark_auto_record_failed(tixian_id, fail_reason):
"""微信明确失败时标记打款记录终态,避免后续一直被当成「处理中」"""
TixianAutoRecord.objects.filter(tixian_id=tixian_id, zhuangtai=0).update(
zhuangtai=2,
fail_reason=(fail_reason or '打款失败')[:500],
update_time=timezone.now(),
)
def _build_wx_transfer_body(wx_cfg, tixian_id, openid, yonghuid, leixing, shijidaozhang):
transfer_scene_id = wx_cfg['TRANSFER_SCENE_ID']
role_map = {1: '打手', 2: '管事', 3: '组长', 4: '考核官', 5: '打手', 6: '商家'}
desc_map = {1: '佣金提现', 2: '分红提现', 3: '分红提现', 4: '分佣提现', 5: '押金提现', 6: '余额提现'}
transfer_scene_report_infos = []
if transfer_scene_id == '1005':
transfer_scene_report_infos = [
{'info_type': '岗位类型', 'info_content': role_map.get(leixing, '用户')},
{'info_type': '报酬说明', 'info_content': desc_map.get(leixing, '提现')},
]
elif transfer_scene_id == '1009':
transfer_scene_report_infos = [
{'info_type': '采购商品名称', 'info_content': '平台服务'},
]
return {
'appid': wx_cfg['APPID'],
'out_bill_no': tixian_id,
'transfer_scene_id': transfer_scene_id,
'openid': openid,
'transfer_amount': int(shijidaozhang * 100),
'transfer_remark': f'兄弟们 收款前记得录屏发快手',
'transfer_scene_report_infos': transfer_scene_report_infos,
}
def _call_wechat_transfer(body, wx_cfg):
from utils.wechat_v3 import build_authorization
url = 'https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills'
body_json = json.dumps(body, separators=(',', ':'))
auth = build_authorization('POST', url, body_json)
headers = {
'Authorization': auth,
'Content-Type': 'application/json',
'Accept': 'application/json',
'User-Agent': 'Mozilla/5.0',
}
resp = requests.post(url, data=body_json, headers=headers, timeout=15)
try:
wx_result = resp.json()
except ValueError:
wx_result = {}
return resp, wx_result
class TixianZddkshApplyView(APIView):
"""POST /yonghu/zddksh 提交审核申请(扣款,不创建 TixianAutoRecord"""
permission_classes = [permissions.IsAuthenticated]
def post(self, request):
from utils.redis_lock import acquire_lock, release_lock
user_main = request.user
lock_key = f'tixian_audit_apply:{user_main.yonghuid}'
if not acquire_lock(lock_key, timeout=10):
return Response({'code': 429, 'msg': '操作频繁,请稍后重试'})
try:
leixing = request.data.get('leixing')
jine_str = request.data.get('jine')
if leixing is None or jine_str is None:
return Response({'code': 1, 'msg': '缺少参数: leixing 或 jine'})
try:
leixing = int(leixing)
jine = decimal.Decimal(str(jine_str))
except (ValueError, decimal.InvalidOperation):
return Response({'code': 2, 'msg': '参数格式错误'})
if leixing not in [1, 2, 3, 4, 5, 6]:
return Response({'code': 3, 'msg': '提现类型无效'})
if jine <= decimal.Decimal('0.1'):
return Response({'code': 4, 'msg': '提现金额必须大于0.1'})
try:
data = create_audit_application(user_main, leixing, jine)
except ValueError as e:
return Response({'code': 400, 'msg': str(e)})
except Exception as e:
logger.error(f'提现审核申请异常: {e}', exc_info=True)
return Response({'code': 99, 'msg': '提现申请失败,请稍后重试'})
return Response({'code': 0, 'msg': '提现申请已提交,请等待审核', 'data': data})
finally:
release_lock(lock_key)
def process_audit_collect(request):
"""
POST /yonghu/tixiansq 用户收款P0 防多提)
主路径tixianjilu_id → Tixianjilu → TixianShenheJilu(状态6)
若 TixianAutoRecord 已有 tixian_id → 只问微信,非终态绝不新建
仅微信 FAIL/CANCELLED 终态后才允许新建打款记录
"""
from utils.redis_lock import acquire_lock, release_lock
user_main = request.user
yonghuid = user_main.yonghuid
tixianjilu_id = request.data.get('tixianjilu_id') or request.data.get('id')
shenhe_danhao = (request.data.get('shenhe_danhao') or '').strip()
shenhe_jilu_id = request.data.get('shenhe_jilu_id')
logger.info(
'收款请求 yonghuid=%s tixianjilu_id=%s shenhe_jilu_id=%s shenhe_danhao=%s',
yonghuid, tixianjilu_id, shenhe_jilu_id, shenhe_danhao,
)
try:
if not user_main.openid:
return Response({'code': 10, 'msg': '用户未绑定微信,无法收款'})
wx_cfg = settings.WECHAT_PAY_V3_CONFIG
if not wx_cfg.get('APPID') or not wx_cfg.get('MCHID') or not wx_cfg.get('TRANSFER_SCENE_ID'):
logger.error('微信打款配置不完整 APPID=%s MCHID=%s', wx_cfg.get('APPID'), wx_cfg.get('MCHID'))
return Response({'code': 11, 'msg': '系统配置异常,请联系客服'})
ctx, err = resolve_collect_context(
yonghuid,
tixianjilu_id=tixianjilu_id,
shenhe_danhao=shenhe_danhao,
shenhe_jilu_id=shenhe_jilu_id,
)
if not ctx:
return Response({'code': 400, 'msg': err})
audit = ctx['audit']
shenhe_danhao = ctx['shenhe_danhao']
tixianjilu_id_val = ctx['jilu'].id if ctx.get('jilu') else audit.tixianjilu_id
leixing = audit.leixing
# 二次资格校验:不通过仅返回错误,审核单保持待收款(6),不退款,用户补齐资质后可再点收款
collect_ok, collect_msg = validate_collect_eligibility(user_main, leixing)
if not collect_ok:
logger.warning(
'收款校验未通过 yonghuid=%s shenhe_danhao=%s leixing=%s msg=%s',
yonghuid, shenhe_danhao, leixing, collect_msg,
)
return Response({'code': 400, 'msg': collect_msg})
quota_resp = _verify_collect_quota_or_response(user_main, audit, shenhe_danhao)
if quota_resp:
return quota_resp
lock_key = f'tixian_collect:{shenhe_danhao}'
if not acquire_lock(lock_key, timeout=15):
return Response({'code': 429, 'msg': '操作频繁,请稍后重试'})
tixian_id = None
quota_reserved = False
try:
action, payload = reconcile_shenhe_wechat_bills(shenhe_danhao)
if action == RECONCILE_COMPLETED:
return Response({'code': 8, 'msg': payload.get('msg', '该提现已完成,请勿重复操作')})
if action == RECONCILE_WAIT_CONFIRM:
quota_resp = _verify_collect_quota_or_response(user_main, audit, shenhe_danhao)
if quota_resp:
return quota_resp
return _build_collect_success_response(payload)
if action == RECONCILE_PENDING:
msg = payload.get('msg') if isinstance(payload, dict) else payload
return Response({'code': 12, 'msg': msg or '有收款处理中,请稍后再试'})
if action != RECONCILE_ALLOW_NEW:
return Response({'code': 12, 'msg': '收款处理中,请稍后再试'})
with transaction.atomic():
audit, err = get_audit_for_collect(
shenhe_danhao, yonghuid, audit.id,
)
if not audit:
return Response({'code': 400, 'msg': err})
# 金额一律用审核表已落库数据(申请时扣款+算费),收款不再重算
jine = audit.shenqing_jine
shouxufei = audit.shouxufei
shijidaozhang = audit.shijidaozhang
feilv = audit.feilv
ok, msg, limit_kind = reserve_collect_quota_limits(
user_main, leixing, jine, shijidaozhang, shenhe_danhao,
)
if not ok:
limit_code = 33 if limit_kind == 'platform' else 400
return Response({'code': limit_code, 'msg': msg})
quota_reserved = True
tixian_id = generate_tixian_id()
TixianAutoRecord.objects.create(
tixian_id=tixian_id,
yonghuid=yonghuid,
leixing=leixing,
jine=jine,
shouxufei=shouxufei,
shijidaozhang=shijidaozhang,
feilv=feilv,
zhuangtai=0,
shenhe_danhao=shenhe_danhao,
)
audit.tixian_auto_id = tixian_id
audit.save(update_fields=['tixian_auto_id', 'update_time'])
body = _build_wx_transfer_body(
wx_cfg, tixian_id, user_main.openid, yonghuid, leixing, shijidaozhang,
)
try:
resp, wx_result = _call_wechat_transfer(body, wx_cfg)
if resp.status_code == 200 and wx_result.get('state') == 'WAIT_USER_CONFIRM':
package_info = wx_result.get('package_info')
auto_record = TixianAutoRecord.objects.get(tixian_id=tixian_id)
auto_record.wechat_package = json.dumps(package_info, ensure_ascii=False)
auto_record.save(update_fields=['wechat_package'])
return _build_collect_success_response({
'tixian_id': tixian_id,
'package_info': package_info,
'shouxufei': str(shouxufei),
'shijidaozhang': str(shijidaozhang),
'current_rate': str(feilv),
'mch_id': wx_cfg['MCHID'],
'shenhe_danhao': shenhe_danhao,
'tixianjilu_id': tixianjilu_id_val,
})
err_code = wx_result.get('code', '')
err_msg = wx_result.get('message', wx_result.get('detail', '微信接口调用失败'))
logger.error(
'微信发起转账未进入待确认: bill=%s code=%s msg=%s HTTP%s',
tixian_id, err_code, err_msg, resp.status_code,
)
is_balance_issue = _is_wx_balance_insufficient(err_code, err_msg)
if is_balance_issue:
_mark_auto_record_failed(tixian_id, err_msg)
if quota_reserved:
release_collect_quota_for_record(
TixianAutoRecord.objects.get(tixian_id=tixian_id),
)
quota_reserved = False
return Response({
'code': 99,
'msg': '运营账户资金不足,需等管理员充值后才能提现',
})
post_action, post_payload = handle_post_transfer_failure(
tixian_id, shenhe_danhao, err_code, err_msg,
)
if post_action == RECONCILE_WAIT_CONFIRM:
quota_resp = _verify_collect_quota_or_response(user_main, audit, shenhe_danhao)
if quota_resp:
return quota_resp
return _build_collect_success_response(post_payload)
if post_action == RECONCILE_COMPLETED:
return Response({'code': 8, 'msg': '该提现已完成,请勿重复操作'})
if post_action == RECONCILE_PENDING:
pending_msg = (
post_payload.get('msg', post_payload)
if isinstance(post_payload, dict) else post_payload
)
return Response({'code': 12, 'msg': pending_msg or '有收款处理中,请稍后再试'})
user_msg = err_msg or '微信收款发起失败,请稍后重试'
_mark_auto_record_failed(tixian_id, user_msg)
if quota_reserved:
release_collect_quota_for_record(
TixianAutoRecord.objects.get(tixian_id=tixian_id),
)
quota_reserved = False
return Response({'code': 99, 'msg': user_msg})
except requests.RequestException as e:
logger.error(
'微信打款网络异常(保持待查单): bill=%s err=%s',
tixian_id, e, exc_info=True,
)
return Response({
'code': 12,
'msg': '收款请求已提交,系统正在核对状态,请稍后再试,切勿重复点击',
})
finally:
release_lock(lock_key)
except Exception as e:
logger.error(
'收款接口未捕获异常 yonghuid=%s tixianjilu_id=%s shenhe_danhao=%s err=%s',
yonghuid, tixianjilu_id, shenhe_danhao, e,
exc_info=True,
)
return Response({'code': 99, 'msg': '系统繁忙,请稍后重试'})

157
yonghu/urls.py Normal file
View File

@@ -0,0 +1,157 @@
from django.urls import path
from django.views.decorators.csrf import csrf_exempt
from .views import WechatMiniProgramLoginView, UserInfoUpdateView, DashouXinxiAPIView, \
ZaixianZhuangtaiAPIView, GuanshiXinxiView, ShangJiaXinXiView, BossBiaoshiView, YaoqingmaView, \
DashouZhuceView, GuanshiYaoqingDashouListView, TixianXinxiHuoquView, ShoukuanXinxiShangchuanView, \
TixianShenqingView, TixianJiluHuoquViewV2, AdminLoginView, AdminFinancialDataView, AdGetDingdanList, \
AdGetOrderTypes, AdGuanLiYongHu, AdYaoQingDaShou, CfGuanLi, AdTongYiChuFa, AdckyhxqView, AdcjxgView, AddtxshView, \
AdtixianqkView, DashouZiliaoHuoquView, DashouGengxinView, \
ShangjiaZhuceView,PaihangbangGuanliQueryView,PaihangbangRiqiliebiaoView,WechatLoginAndDashouRegisterView, \
YonghuTixianShenheXiugaiView, ChufaJiluHuoquView, DashouShensuView, ShangjiaChufaJiluHuoquView,\
WeixinOfficialCallbackView,KefuLoginView, KefuStatsView, KefuGetOrderTypesView, KefuGetOrderListView, \
KefuGetShangjiaOrderListView, KefuGetOrderDetailView, KefuChangeDashouView, KefuRecoverOrderView, \
KefuPlatformRefundView, KefuRejectRefundView, KefuMerchantRefundView, KefuRejectSettlementView, \
KefuTransferHallView, KefuCancelDesignationView, KefuGetDashouListView, KefuGetDashouDetailView, \
KefuUpdateDashouView, KefuPunishmentListView, KefuPunishmentActionView, KefuPunishmentDetailView, \
KefuWithdrawListView, KefuWithdrawDetailView, KefuWithdrawActionView, KefuPunishView, AdKfglView, AdKftjView, \
AdKfxgView,TixianQueRenAutoView, TixianShenqingV3View, TixianCallbackV3View, KefuForceCompleteView,\
GuanshiRegisterView, WechatLoginAndGuanshiRegisterView, ZuzhangZhuceView, ZuzhangXinxiView,\
DashouJianquanView, LaobanJianquanView,HuoQuYaoQingRenView,FaKuanJiFenTongJiView, DaShouFaKuanLieBiaoView, \
FaKuanShenSuView, FaKuanPayView, FaKuanPayPollView, FaKuanPayFailView, FaKuanHuitiaoView,\
KaohePayView,KaohePayCallbackView, KaohePayPollView, KaohePayFailView, TixianAssetView
from .tixian_shenhe_views import TixianZddkshApplyView
urlpatterns = [
path('wechatlogin', WechatMiniProgramLoginView.as_view(), name='用户一键微信登录'),
path('xiugai', UserInfoUpdateView.as_view(), name='用户信息修改'),
# 打手信息接口
path('dashouxinxi', DashouXinxiAPIView.as_view(), name='打手信息查询'),
# 更改在线状态接口
path('zaixianzhuangtai', ZaixianZhuangtaiAPIView.as_view(), name='打手在线状态更改'),
path('guanshixinxi', GuanshiXinxiView.as_view(), name='获取管事信息'),
path('shangjiaxinxi', ShangJiaXinXiView.as_view(), name='获取商家信息'),
path('bossbiaoshi', BossBiaoshiView.as_view(), name='获取老板标识'),
path('yaoqingma', YaoqingmaView.as_view(), name='管事生成邀请码'),
path('dashouzhuce',DashouZhuceView.as_view(), name='打手邀请码注册'),
path('gshqyqds', GuanshiYaoqingDashouListView.as_view(), name='管事获取邀请打手'),
path('tixianhq', TixianXinxiHuoquView.as_view(), name='获取体现缓存信息'), # 获取提现信息
path('sksc', ShoukuanXinxiShangchuanView.as_view(), name='上传提现相关数据或收款码'), # 上传收款信息
path('tixian', TixianShenqingView.as_view(), name='提现申请'), # 提交提现申请
path('tixianjiluhq', TixianJiluHuoquViewV2.as_view(), name='打手提现记录查询'),
path('adlog', AdminLoginView.as_view(), name='管理元登录'),
path('adhq', AdminFinancialDataView.as_view(), name='管理元获取收支记录'),
path('adgetordertypes', AdGetOrderTypes.as_view(), name='管理员获取订单类型'),
# 订单列表获取接口
path('adddhq', AdGetDingdanList.as_view(), name='管理员获取订单列表'),
path('adyqds', AdYaoQingDaShou.as_view(), name='管理员获取邀请码'),
# 用户管理列表接口
path('adgl', AdGuanLiYongHu.as_view(), name='管理员获取用户'),
path('cfgl', CfGuanLi.as_view(), name='处罚记录获取'),
path('adtycf', AdTongYiChuFa.as_view(), name='同意或拒绝处罚'),
path('adckyhxq', AdckyhxqView.as_view(), name='管理员获取用户具体数据'),
# 修改用户信息接口
path('adcjxg',AdcjxgView.as_view(), name='管理员修改用户数据'),
path('addtxsh', AddtxshView.as_view(), name='管理员获取提现审核'),
# 处理提现申请接口
path('adtixianqk', AdtixianqkView.as_view(), name='管理员提现修改'),
# 打手资料获取
path('dszjxxhq', DashouZiliaoHuoquView.as_view(), name='打手获取自己信息'),
# 打手信息更新
path('dsgxxx', DashouGengxinView.as_view(), name='打手修改自己信息'),
# 🔥🟢 新增商家路由
path('shangjiahuce', ShangjiaZhuceView.as_view(), name='商家注册'),
path('paihangbang', PaihangbangGuanliQueryView.as_view(), name='管理查询排行榜'),
path('adhqphrq', PaihangbangRiqiliebiaoView.as_view(), name='管理原获取排行榜日期'),
path('wdlyhdl', WechatLoginAndDashouRegisterView.as_view(), name='打手扫码注册'),
path('yonghutxshxg', YonghuTixianShenheXiugaiView.as_view(), name='用户自己体现修改'),
path('dshqcfjl', ChufaJiluHuoquView.as_view(), name='打手处罚记录获取'),
# 打手申诉接口
path('dscfss', DashouShensuView.as_view(), name='打手处罚上诉申请'),
path('sjcfjlhq', ShangjiaChufaJiluHuoquView.as_view(), name='商家处罚记录获取'),
#path('officialcallback', csrf_exempt(WeixinOfficialCallbackView.as_view()), name='用户关注取关服务号回调'),
path('kefujinru', KefuLoginView.as_view(), name='客服登录'),
path('kfjrhqzl', KefuStatsView.as_view(), name='客服获取数据'),
path('kfhqptddlx', KefuGetOrderTypesView.as_view(), name='客服获取订单类型'),
path('kfhqddlb', KefuGetOrderListView.as_view(), name='客服获取订单列表'),
path('kfhqsjddlb', KefuGetShangjiaOrderListView.as_view(),name='客服获取商家订单列表'),
path('kefuhqddxq', KefuGetOrderDetailView.as_view(), name='获取订单详情页面'),
path('kefughds', KefuChangeDashouView.as_view(), name='客服更换打手'),
path('kefuhf', KefuRecoverOrderView.as_view(), name='客服恢复订单'),
path('kefupttk', KefuPlatformRefundView.as_view(), name='客服给平台订单退款'),
path('kefujjtk', KefuRejectRefundView.as_view(), name='客服拒绝商家退款'),
path('kefusjtk', KefuMerchantRefundView.as_view(), name='客服同意商家退款'),
path('kefujjjs', KefuRejectSettlementView.as_view(), name='客服拒绝结算'),
path('kefuzydt', KefuTransferHallView.as_view(), name='客服订单返回大厅'),
path('kefuqxzd', KefuCancelDesignationView.as_view(), name='客服取消指定'),
path('kefuhqdslb', KefuGetDashouListView.as_view(), name='客服获取打手数据'),
path('kefuhqdsxq', KefuGetDashouDetailView.as_view(), name='客服获取打手具体信息'),
path('kefuxgds', KefuUpdateDashouView.as_view(), name='客服修改打手数据'),
path('kefu_cfgl', KefuPunishmentListView.as_view(), name='客服获取处罚记录'),
path('kefu_cf_detail', KefuPunishmentDetailView.as_view(), name='kefu_cf_detail'),
path('kefu_cf_action', KefuPunishmentActionView.as_view(), name='客服处理处罚'),
path('kefu_txsh_list', KefuWithdrawListView.as_view(), name='客服获取体现数据'),
path('kefu_txsh_detail', KefuWithdrawDetailView.as_view(), name='客服获取体现详情数据'),
path('kefu_txsh_action', KefuWithdrawActionView.as_view(), name='客服处理体现'),
path('kefuchufa', KefuPunishView.as_view(), name='客服申请出发打手'),
path('adkfgl', AdKfglView.as_view(), name='管理员获取客服数据'),
path('adkftj', AdKftjView.as_view(), name='管理添加客服'),
path('adkfxg', AdKfxgView.as_view(), name='管理修改客服'),
path('tixiansq', TixianShenqingV3View.as_view(), name='提现申请'),
path('tixianqr', TixianQueRenAutoView.as_view(), name='新提现确认'),
path('tixiancallback', csrf_exempt(TixianCallbackV3View.as_view()), name='提现回调'),
path('kefuqiangzhijiedan', KefuForceCompleteView.as_view(), name='客服强制结单'),
# 已登录用户注册管事
path('guanshizhuce', GuanshiRegisterView.as_view(), name='管事注册,已经登陆'),
# 未登录用户微信登录+管事注册
path('wdlyqmzc', WechatLoginAndGuanshiRegisterView.as_view(), name='管事注册,没有登录'),
path('zuzhangzhuce', ZuzhangZhuceView.as_view(), name='组长注册'),
path('zuzhangxinxi', ZuzhangXinxiView.as_view(), name='组长刷新获取信息'),
path('hqwdyqr', HuoQuYaoQingRenView.as_view(), name='打手联系获取管事'),
path('dshqltqx', DashouJianquanView.as_view(), name='前端鉴权打手是否有使用消息功能'), # 打手鉴权
path('lbhqltqx', LaobanJianquanView.as_view(), name='鉴权老板是否有使用消息功能'), # 老板鉴权
path('cffktjhq', FaKuanJiFenTongJiView.as_view(), name='获取罚款 + 积分处罚综合统计'),
# 获取打手自己的罚款列表
path('dsfklbhq', DaShouFaKuanLieBiaoView.as_view(), name='获取打手自己的罚款列表'),
# 提交罚款申诉
path('fkss', FaKuanShenSuView.as_view(), name='提交罚款申诉'),
path('fkjn', FaKuanPayView.as_view(), name='提交罚款微信支付申请'), # 下单
path('fk_huitiao', csrf_exempt(FaKuanHuitiaoView.as_view()), name='提交罚款微信支付回调'), # 回调
path('fkzffc', FaKuanPayPollView.as_view(), name='提交罚款申微信支付成功轮询'), # 轮询
path('fkzfsb', FaKuanPayFailView.as_view(), name='提交罚款微信支付失败'), # 失败
path('khzf', KaohePayView.as_view(), name='考核支付下单'),
path('kh_huitiao', csrf_exempt(KaohePayCallbackView.as_view()), name='考核支付回调'),
path('khzffc', KaohePayPollView.as_view(), name='考核支付复查轮询'),
path('khzfsb', KaohePayFailView.as_view(), name='考核支付失败'),
path('tixianzichan', TixianAssetView.as_view(), name='小程序提现数据获取'),
path('zddksh', TixianZddkshApplyView.as_view(), name='自动提现审核申请'),
]

17268
yonghu/views.py Normal file

File diff suppressed because it is too large Load Diff