修复了已知的生产环境问题

This commit is contained in:
2026-06-17 21:25:45 +08:00
parent d00f0d08e5
commit 4aca437d2b
25 changed files with 13547 additions and 13423 deletions

View File

@@ -119,8 +119,8 @@ SIMPLE_JWT = {
'LEEWAY': 0, 'LEEWAY': 0,
'AUTH_HEADER_TYPES': ('Bearer',), 'AUTH_HEADER_TYPES': ('Bearer',),
'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION', 'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',
'USER_ID_FIELD': 'yonghuid', 'USER_ID_FIELD': 'UserUID',
'USER_ID_CLAIM': 'yonghuid', 'USER_ID_CLAIM': 'UserUID',
'USER_AUTHENTICATION_RULE': 'rest_framework_simplejwt.authentication.default_user_authentication_rule', 'USER_AUTHENTICATION_RULE': 'rest_framework_simplejwt.authentication.default_user_authentication_rule',
'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',), 'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
'TOKEN_TYPE_CLAIM': 'token_type', 'TOKEN_TYPE_CLAIM': 'token_type',

View File

@@ -581,7 +581,7 @@ class AddAdminUserView(APIView):
# 生成唯一的 yonghuid7位数字 # 生成唯一的 yonghuid7位数字
while True: while True:
yonghuid = str(random.randint(1000000, 9999999)) yonghuid = str(random.randint(1000000, 9999999))
if not User.query.filter(yonghuid=yonghuid).exists(): if not User.query.filter(UserUID=yonghuid).exists():
break break
# 生成唯一的 openid格式admin_{时间戳}_{随机6位} # 生成唯一的 openid格式admin_{时间戳}_{随机6位}
@@ -1064,7 +1064,7 @@ class KefuUpdateDashouView(APIView):
# 3. 查询打手 # 3. 查询打手
try: try:
dashou_user = User.query.get(yonghuid=dashou_id) dashou_user = User.query.get(UserUID=dashou_id)
dashou_profile = dashou_user.dashou_profile dashou_profile = dashou_user.dashou_profile
except User.DoesNotExist: except User.DoesNotExist:
return Response({'code': 404, 'msg': '打手不存在'}) return Response({'code': 404, 'msg': '打手不存在'})
@@ -1496,7 +1496,7 @@ class KefuGetShangjiaDetailView(APIView):
# 查询商家 # 查询商家
try: try:
shangjia = UserShangjia.query.select_related('user').get(user__yonghuid=yonghuid) shangjia = UserShangjia.query.select_related('user').get(user__UserUID=yonghuid)
except UserShangjia.DoesNotExist: except UserShangjia.DoesNotExist:
return Response({'code': 404, 'msg': '商家不存在'}) return Response({'code': 404, 'msg': '商家不存在'})
@@ -1566,7 +1566,7 @@ class KefuUpdateShangjiaView(APIView):
# 使用事务select_for_update 必须在事务内 # 使用事务select_for_update 必须在事务内
with transaction.atomic(): with transaction.atomic():
try: try:
shangjia = UserShangjia.objects.select_for_update().get(user__yonghuid=yonghuid) shangjia = UserShangjia.objects.select_for_update().get(user__UserUID=yonghuid)
except UserShangjia.DoesNotExist: except UserShangjia.DoesNotExist:
return Response({'code': 404, 'msg': '商家不存在'}) return Response({'code': 404, 'msg': '商家不存在'})
@@ -2968,7 +2968,7 @@ class GetGuanliDetailView(APIView):
# 查询用户主表和管事扩展表 # 查询用户主表和管事扩展表
try: try:
user = User.query.select_related('guanshi_profile', 'boss_profile').get(yonghuid=yonghuid) user = User.query.select_related('guanshi_profile', 'boss_profile').get(UserUID=yonghuid)
guanshi = user.guanshi_profile guanshi = user.guanshi_profile
boss = user.boss_profile if hasattr(user, 'boss_profile') else None boss = user.boss_profile if hasattr(user, 'boss_profile') else None
except User.DoesNotExist: except User.DoesNotExist:
@@ -3015,7 +3015,7 @@ class GetGuanliDetailView(APIView):
# 获取多次分红配置(按次数和会员组织) # 获取多次分红配置(按次数和会员组织)
# 查询该管事的所有多次分红记录 # 查询该管事的所有多次分红记录
duoci_records = DuociFenhong.query.filter(yonghuid=yonghuid).order_by('cishu') duoci_records = DuociFenhong.query.filter(UserUID=yonghuid).order_by('cishu')
custom_first = {} # 首次分红定制cishu=1 custom_first = {} # 首次分红定制cishu=1
extra_map = {} # 其他次数 { cishu: { huiyuan_id: { guanshi_fenhong, jieshao, jiage } } } extra_map = {} # 其他次数 { cishu: { huiyuan_id: { guanshi_fenhong, jieshao, jiage } } }
@@ -3089,7 +3089,7 @@ class UpdateGuanliView(APIView):
# 查询管事对象(不在事务外加锁,事务内加锁) # 查询管事对象(不在事务外加锁,事务内加锁)
try: try:
user = User.query.get(yonghuid=yonghuid) user = User.query.get(UserUID=yonghuid)
guanshi = user.guanshi_profile guanshi = user.guanshi_profile
boss = user.boss_profile if hasattr(user, 'boss_profile') else None boss = user.boss_profile if hasattr(user, 'boss_profile') else None
except User.DoesNotExist: except User.DoesNotExist:
@@ -3100,7 +3100,7 @@ class UpdateGuanliView(APIView):
# 开始事务,内部使用 select_for_update # 开始事务,内部使用 select_for_update
with transaction.atomic(): with transaction.atomic():
# 重新获取加锁对象 # 重新获取加锁对象
user = User.objects.select_for_update().get(yonghuid=yonghuid) user = User.objects.select_for_update().get(UserUID=yonghuid)
guanshi = user.guanshi_profile guanshi = user.guanshi_profile
boss = user.boss_profile if hasattr(user, 'boss_profile') else None boss = user.boss_profile if hasattr(user, 'boss_profile') else None
@@ -3196,7 +3196,7 @@ class UpdateGuanliView(APIView):
# 4.2 首次定制分红cishu=1 # 4.2 首次定制分红cishu=1
if custom_first is not None and isinstance(custom_first, dict): if custom_first is not None and isinstance(custom_first, dict):
# 获取当前所有首次定制记录 # 获取当前所有首次定制记录
existing_first = DuociFenhong.query.filter(yonghuid=yonghuid, cishu=1) existing_first = DuociFenhong.query.filter(UserUID=yonghuid, cishu=1)
# 前端传来的定制字典 {会员ID: 金额} # 前端传来的定制字典 {会员ID: 金额}
for huiyuan_id, amount in custom_first.items(): for huiyuan_id, amount in custom_first.items():
try: try:
@@ -3205,7 +3205,7 @@ class UpdateGuanliView(APIView):
continue continue
if amount <= 0: if amount <= 0:
# 金额为0或负数表示删除定制 # 金额为0或负数表示删除定制
DuociFenhong.query.filter(yonghuid=yonghuid, huiyuan=huiyuan_id, cishu=1).delete() DuociFenhong.query.filter(UserUID=yonghuid, huiyuan=huiyuan_id, cishu=1).delete()
else: else:
DuociFenhong.query.update_or_create( DuociFenhong.query.update_or_create(
yonghuid=yonghuid, yonghuid=yonghuid,
@@ -3256,7 +3256,7 @@ class UpdateGuanliView(APIView):
} }
) )
# 删除不在 keep_set 中的额外次数记录 # 删除不在 keep_set 中的额外次数记录
existing_extra = DuociFenhong.query.filter(yonghuid=yonghuid, cishu__gte=2) existing_extra = DuociFenhong.query.filter(UserUID=yonghuid, cishu__gte=2)
for record in existing_extra: for record in existing_extra:
if (record.cishu, record.huiyuan) not in keep_set: if (record.cishu, record.huiyuan) not in keep_set:
record.delete() record.delete()
@@ -3660,7 +3660,7 @@ class GetZuzhangDetailView(APIView):
# 查询组长主表、扩展表、老板扩展表(昵称) # 查询组长主表、扩展表、老板扩展表(昵称)
try: try:
user = User.query.select_related('zuzhang_profile', 'boss_profile').get(yonghuid=yonghuid) user = User.query.select_related('zuzhang_profile', 'boss_profile').get(UserUID=yonghuid)
zuzhang = user.zuzhang_profile zuzhang = user.zuzhang_profile
boss = user.boss_profile if hasattr(user, 'boss_profile') else None boss = user.boss_profile if hasattr(user, 'boss_profile') else None
except User.DoesNotExist: except User.DoesNotExist:
@@ -3706,7 +3706,7 @@ class GetZuzhangDetailView(APIView):
m['zuzhangfc'] = str(m['zuzhangfc']) m['zuzhangfc'] = str(m['zuzhangfc'])
# 获取多次分红配置(按次数和会员组织) # 获取多次分红配置(按次数和会员组织)
duoci_records = DuociFenhong.query.filter(yonghuid=yonghuid).order_by('cishu') duoci_records = DuociFenhong.query.filter(UserUID=yonghuid).order_by('cishu')
custom_first = {} # 首次分红定制cishu=1 custom_first = {} # 首次分红定制cishu=1
extra_map = {} # 其他次数 { cishu: { huiyuan_id: { zuzhang_fenhong, jieshao, jiage } } } extra_map = {} # 其他次数 { cishu: { huiyuan_id: { zuzhang_fenhong, jieshao, jiage } } }
@@ -3783,7 +3783,7 @@ class UpdateZuzhangView(APIView):
# 查询组长对象 # 查询组长对象
try: try:
user = User.query.get(yonghuid=yonghuid) user = User.query.get(UserUID=yonghuid)
zuzhang = user.zuzhang_profile zuzhang = user.zuzhang_profile
boss = user.boss_profile if hasattr(user, 'boss_profile') else None boss = user.boss_profile if hasattr(user, 'boss_profile') else None
except User.DoesNotExist: except User.DoesNotExist:
@@ -3879,7 +3879,7 @@ class UpdateZuzhangView(APIView):
# 4.2 首次定制分红cishu=1 # 4.2 首次定制分红cishu=1
if custom_first is not None and isinstance(custom_first, dict): if custom_first is not None and isinstance(custom_first, dict):
existing_first = DuociFenhong.query.filter(yonghuid=yonghuid, cishu=1) existing_first = DuociFenhong.query.filter(UserUID=yonghuid, cishu=1)
for huiyuan_id, amount in custom_first.items(): for huiyuan_id, amount in custom_first.items():
try: try:
amount = Decimal(str(amount)) amount = Decimal(str(amount))
@@ -3887,7 +3887,7 @@ class UpdateZuzhangView(APIView):
continue continue
if amount <= 0: if amount <= 0:
# 删除定制(恢复默认) # 删除定制(恢复默认)
DuociFenhong.query.filter(yonghuid=yonghuid, huiyuan=huiyuan_id, cishu=1).delete() DuociFenhong.query.filter(UserUID=yonghuid, huiyuan=huiyuan_id, cishu=1).delete()
else: else:
DuociFenhong.query.update_or_create( DuociFenhong.query.update_or_create(
yonghuid=yonghuid, yonghuid=yonghuid,
@@ -3936,7 +3936,7 @@ class UpdateZuzhangView(APIView):
} }
) )
# 删除不在 keep_set 中的额外次数记录 # 删除不在 keep_set 中的额外次数记录
existing_extra = DuociFenhong.query.filter(yonghuid=yonghuid, cishu__gte=2) existing_extra = DuociFenhong.query.filter(UserUID=yonghuid, cishu__gte=2)
for record in existing_extra: for record in existing_extra:
if (record.cishu, record.huiyuan) not in keep_set: if (record.cishu, record.huiyuan) not in keep_set:
record.delete() record.delete()
@@ -5026,7 +5026,7 @@ class ShopModifyView(APIView):
return Response({'code': 400, 'msg': '必填字段缺失用户ID、账号、密码、店铺名称'}) return Response({'code': 400, 'msg': '必填字段缺失用户ID、账号、密码、店铺名称'})
# 检查用户是否存在 # 检查用户是否存在
if not User.query.filter(yonghuid=yonghu_id).exists(): if not User.query.filter(UserUID=yonghu_id).exists():
return Response({'code': 404, 'msg': '用户不存在'}) return Response({'code': 404, 'msg': '用户不存在'})
# 检查凭证是否已存在 # 检查凭证是否已存在
@@ -5962,7 +5962,7 @@ class FaKuanChuangJianView(APIView):
# 验证用户是否存在对应的扩展表 # 验证用户是否存在对应的扩展表
try: try:
user = User.query.get(yonghuid=beichufa_id) user = User.query.get(UserUID=beichufa_id)
profile_attr = SHENFEN_PROFILE_MAP.get(shenfen) profile_attr = SHENFEN_PROFILE_MAP.get(shenfen)
if not profile_attr or not hasattr(user, profile_attr): if not profile_attr or not hasattr(user, profile_attr):
return Response({'code': 400, 'msg': '该用户不是所选身份'}) return Response({'code': 400, 'msg': '该用户不是所选身份'})
@@ -6162,7 +6162,7 @@ class PunishDashouView(APIView):
# 查询打手 # 查询打手
try: try:
dashou_user = User.query.get(yonghuid=dashou_id) dashou_user = User.query.get(UserUID=dashou_id)
dashou = dashou_user.dashou_profile dashou = dashou_user.dashou_profile
except User.DoesNotExist: except User.DoesNotExist:
return Response({'code': 404, 'msg': '打手用户不存在'}) return Response({'code': 404, 'msg': '打手用户不存在'})
@@ -6484,7 +6484,7 @@ class CaiwuView(APIView):
amount_sum = Czjilu.query.filter( amount_sum = Czjilu.query.filter(
create_time__gte=today_start, create_time__gte=today_start,
create_time__lt=today_end, create_time__lt=today_end,
yonghuid__in=new_huiyuan_user_ids, UserUID__in=new_huiyuan_user_ids,
leixing=1, leixing=1,
zhuangtai=3 zhuangtai=3
).aggregate(total=Sum('jine')) ).aggregate(total=Sum('jine'))
@@ -7946,7 +7946,7 @@ class KhgglView(APIView):
queryset = UserShenheguan.query.select_related('user__dashou_profile') queryset = UserShenheguan.query.select_related('user__dashou_profile')
if filter_yonghuid: if filter_yonghuid:
queryset = queryset.filter(user__yonghuid=filter_yonghuid) queryset = queryset.filter(user__UserUID=filter_yonghuid)
if filter_zhuangtai is not None: if filter_zhuangtai is not None:
queryset = queryset.filter(zhuangtai=filter_zhuangtai) queryset = queryset.filter(zhuangtai=filter_zhuangtai)
if filter_shenhe_zhuangtai is not None: if filter_shenhe_zhuangtai is not None:
@@ -7960,7 +7960,7 @@ class KhgglView(APIView):
shenheguan_ids = KaoheguanBankuai.query.filter( shenheguan_ids = KaoheguanBankuai.query.filter(
bankuai_id__in=bankuai_ids bankuai_id__in=bankuai_ids
).values_list('kaoheguan_id', flat=True) ).values_list('kaoheguan_id', flat=True)
queryset = queryset.filter(user__yonghuid__in=shenheguan_ids) queryset = queryset.filter(user__UserUID__in=shenheguan_ids)
total = queryset.count() total = queryset.count()
start = (page - 1) * page_size start = (page - 1) * page_size
@@ -8070,7 +8070,7 @@ class ShgxgsjView(APIView):
return Response({'code': 1, 'msg': '缺少用户ID'}, status=400) return Response({'code': 1, 'msg': '缺少用户ID'}, status=400)
try: try:
shenheguan = UserShenheguan.query.select_related('user').get(user__yonghuid=yonghuid) shenheguan = UserShenheguan.query.select_related('user').get(user__UserUID=yonghuid)
except UserShenheguan.DoesNotExist: except UserShenheguan.DoesNotExist:
return Response({'code': 1, 'msg': '审核官不存在'}, status=404) return Response({'code': 1, 'msg': '审核官不存在'}, status=404)
@@ -8189,7 +8189,7 @@ class ZxkfghdsView(APIView):
shangjia_ext = old_order.shangjia_kuozhan shangjia_ext = old_order.shangjia_kuozhan
shangjia_id = shangjia_ext.shangjia_id shangjia_id = shangjia_ext.shangjia_id
# 获取商家昵称用于新订单扩展表 # 获取商家昵称用于新订单扩展表
shangjia_user = User.query.get(yonghuid=shangjia_id) shangjia_user = User.query.get(UserUID=shangjia_id)
shangjia_nicheng = shangjia_user.shop_profile.nicheng or f"商家{shangjia_id}" shangjia_nicheng = shangjia_user.shop_profile.nicheng or f"商家{shangjia_id}"
except (ObjectDoesNotExist, UserShangjia.DoesNotExist): except (ObjectDoesNotExist, UserShangjia.DoesNotExist):
logger.error(f"商家信息缺失,订单: {dingdan_id}") logger.error(f"商家信息缺失,订单: {dingdan_id}")
@@ -8206,7 +8206,7 @@ class ZxkfghdsView(APIView):
dashou_id = old_order.jiedan_dashou_id dashou_id = old_order.jiedan_dashou_id
if dashou_id: if dashou_id:
try: try:
dashou_user = User.query.get(yonghuid=dashou_id) dashou_user = User.query.get(UserUID=dashou_id)
dashou_profile = dashou_user.dashou_profile dashou_profile = dashou_user.dashou_profile
dashou_profile.tuikuanliang += 1 # 退款次数+1 dashou_profile.tuikuanliang += 1 # 退款次数+1
dashou_profile.zhuangtai = 1 # 设为空闲 dashou_profile.zhuangtai = 1 # 设为空闲

View File

@@ -1,4 +1,4 @@
# Generated by Django 4.2.27 on 2026-06-17 16:31 # Generated by Django 4.2.27 on 2026-06-17 21:18
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion

View File

@@ -11,7 +11,7 @@ from decimal import Decimal, InvalidOperation
from django.conf import settings from django.conf import settings
from django.db import transaction, connection from django.db import transaction, connection
from django.db.models import Q, F, Max, Prefetch from django.db.models import Q, F, Max, Prefetch
from gvsdsdk.fluent import db, func, FQ from gvsdsdk.fluent import db, func, FQ
from django.core.cache import cache from django.core.cache import cache
from django.core.paginator import Paginator from django.core.paginator import Paginator
@@ -2191,7 +2191,7 @@ class KehuGetDingdanLianjieView(APIView):
# 获取商家昵称 # 获取商家昵称
shangjia_nicheng = '' shangjia_nicheng = ''
try: try:
user_main = User.query.get(yonghuid=lianjie_obj.yonghu_id) user_main = User.query.get(UserUID=lianjie_obj.yonghu_id)
shangjia_obj = user_main.shop_profile shangjia_obj = user_main.shop_profile
shangjia_nicheng = shangjia_obj.nicheng shangjia_nicheng = shangjia_obj.nicheng
except (User.DoesNotExist, UserShangjia.DoesNotExist): except (User.DoesNotExist, UserShangjia.DoesNotExist):
@@ -2473,7 +2473,7 @@ class KehuTianxieDingdanView(APIView):
# 验证打手是否存在且有效 # 验证打手是否存在且有效
try: try:
# 先查询用户主表 # 先查询用户主表
dashou_user = User.query.get(yonghuid=zhiding_dashou) dashou_user = User.query.get(UserUID=zhiding_dashou)
logger.info(f"找到打手用户 - 用户ID: {zhiding_dashou}") logger.info(f"找到打手用户 - 用户ID: {zhiding_dashou}")
# 通过反向关系获取打手扩展信息 # 通过反向关系获取打手扩展信息
@@ -2571,7 +2571,7 @@ class KehuTianxieDingdanView(APIView):
# 获取商家信息用于返回 # 获取商家信息用于返回
try: try:
user_main = User.query.get(yonghuid=lianjie_obj.yonghu_id) user_main = User.query.get(UserUID=lianjie_obj.yonghu_id)
shangjia_obj = user_main.shop_profile shangjia_obj = user_main.shop_profile
shangjia_mingcheng = shangjia_obj.nicheng shangjia_mingcheng = shangjia_obj.nicheng
except: except:

67
fix_fk.py Normal file
View File

@@ -0,0 +1,67 @@
#!/usr/bin/env python3
"""修复 yonghu_dianpu_bangding 表的 FK 约束"""
import MySQLdb
from app_secrets import DATABASE_HOST, DATABASE_PORT, DATABASE_USER, DATABASE_PASSWORD, DATABASE_NAME
conn = MySQLdb.connect(
host=DATABASE_HOST, port=int(DATABASE_PORT),
user=DATABASE_USER, password=DATABASE_PASSWORD,
database=DATABASE_NAME, charset='utf8mb4'
)
cursor = conn.cursor()
# 1. 查看所有引用 User 表的 FK 约束
cursor.execute("""
SELECT CONSTRAINT_NAME, TABLE_NAME, COLUMN_NAME, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME
FROM information_schema.KEY_COLUMN_USAGE
WHERE TABLE_SCHEMA = %s AND REFERENCED_TABLE_NAME = 'User'
""", [DATABASE_NAME])
fks = cursor.fetchall()
print("引用 User 表的 FK 约束:")
for fk in fks:
print(f" {fk[0]}: {fk[1]}.{fk[2]} -> {fk[3]}.{fk[4]}")
# 2. 删除所有引用 User.UserUID 的 FK 约束(类型不兼容的)
for fk in fks:
if fk[4] == 'UserUID': # 引用了 UserUID (varchar) 而不是 UserUUID (binary)
constraint_name = fk[0]
table_name = fk[1]
print(f"\n删除不兼容 FK: {constraint_name} on {table_name}")
try:
cursor.execute(f"ALTER TABLE `{table_name}` DROP FOREIGN KEY `{constraint_name}`")
conn.commit()
print(f" 已删除 {constraint_name}")
except Exception as e:
print(f" 删除失败: {e}")
# 3. 修改 yonghu_dianpu_bangding.UserUUID 列类型
print("\n修改 yonghu_dianpu_bangding.UserUUID 列类型...")
try:
cursor.execute("ALTER TABLE yonghu_dianpu_bangding MODIFY COLUMN UserUUID binary(16) NOT NULL")
conn.commit()
print(" 修改成功")
except Exception as e:
print(f" 修改失败: {e}")
# 4. 重新添加 FK 约束
print("\n重新添加 FK 约束...")
try:
cursor.execute("""
ALTER TABLE yonghu_dianpu_bangding
ADD CONSTRAINT yonghu_dianpu_bangding_UserUUID_fk
FOREIGN KEY (UserUUID) REFERENCES User(UserUUID)
""")
conn.commit()
print(" FK 约束添加成功")
except Exception as e:
print(f" FK 约束添加失败: {e}")
# 5. 验证
print("\n验证表结构:")
cursor.execute("DESCRIBE yonghu_dianpu_bangding")
for row in cursor.fetchall():
print(f" {row}")
conn.close()
print("\n完成!")

View File

@@ -388,6 +388,15 @@ class User(QModel):
def id(self): def id(self):
return self.ID return self.ID
@property
def shoujihao_renzheng(self):
"""兼容旧代码 — 手机号是否已认证"""
return self.PhoneVerified
@shoujihao_renzheng.setter
def shoujihao_renzheng(self, value):
self.PhoneVerified = bool(value)
def set_password(self, raw_password): def set_password(self, raw_password):
self.SetPassword(raw_password) self.SetPassword(raw_password)

View File

@@ -1,4 +1,4 @@
# Generated by Django 4.2.27 on 2026-06-17 16:31 # Generated by Django 4.2.27 on 2026-06-17 21:18
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion

View File

@@ -1,208 +1,208 @@
""" """
阿龙电竞 - 订单定时任务 阿龙电竞 - 订单定时任务
处理订单超时自动确认等逻辑 处理订单超时自动确认等逻辑
完整版本,包含所有必要的异常处理 完整版本,包含所有必要的异常处理
""" """
from celery import shared_task from celery import shared_task
from django.db import transaction from django.db import transaction
from django.db.models import F, Q from django.db.models import F, Q
from django.conf import settings from django.conf import settings
from django.utils import timezone from django.utils import timezone
from datetime import timedelta from datetime import timedelta
from decimal import Decimal from decimal import Decimal
import logging import logging
# 导入模型 - 确保路径正确 # 导入模型 - 确保路径正确
from orders.models import Dingdan from orders.models import Dingdan
from users.models import UserDashou, UserShangjia from users.models import UserDashou, UserShangjia
from gvsdsdk.models import User from gvsdsdk.models import User
from utils.celery_utils import safe_decimal_operation, log_task_execution, rollback_on_failure from utils.celery_utils import safe_decimal_operation, log_task_execution, rollback_on_failure
from gvsdsdk.fluent import db, func, FQ from gvsdsdk.fluent import db, func, FQ
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@shared_task(bind=True, max_retries=3, default_retry_delay=60) @shared_task(bind=True, max_retries=3, default_retry_delay=60)
def process_expired_order(self, dingdan_id): def process_expired_order(self, dingdan_id):
""" """
处理单个超时订单(订单状态=8超过48小时未处理 处理单个超时订单(订单状态=8超过48小时未处理
【已禁用】ORDER_AUTO_SETTLEMENT_ENABLED=False 且已从 Celery autodiscover 移除 【已禁用】ORDER_AUTO_SETTLEMENT_ENABLED=False 且已从 Celery autodiscover 移除
""" """
if not getattr(settings, 'ORDER_AUTO_SETTLEMENT_ENABLED', False): if not getattr(settings, 'ORDER_AUTO_SETTLEMENT_ENABLED', False):
logger.warning('订单%s自动结算已关闭(ORDER_AUTO_SETTLEMENT_ENABLED=False),拒绝执行', dingdan_id) logger.warning('订单%s自动结算已关闭(ORDER_AUTO_SETTLEMENT_ENABLED=False),拒绝执行', dingdan_id)
return f"订单{dingdan_id}自动结算已禁用,跳过" return f"订单{dingdan_id}自动结算已禁用,跳过"
# --- 以下原结算逻辑保留备查 --- # --- 以下原结算逻辑保留备查 ---
try: try:
# 使用select_for_update锁定记录防止并发修改 # 使用select_for_update锁定记录防止并发修改
with transaction.atomic(): with transaction.atomic():
# 获取订单,同时锁定记录 # 获取订单,同时锁定记录
order = Dingdan.objects.select_for_update().get( order = Dingdan.objects.select_for_update().get(
dingdan_id=dingdan_id dingdan_id=dingdan_id
) )
# 再次检查订单状态是否为8 # 再次检查订单状态是否为8
if order.zhuangtai != 8: if order.zhuangtai != 8:
logger.info(f"订单{dingdan_id}状态已不是8当前:{order.zhuangtai}),跳过处理") logger.info(f"订单{dingdan_id}状态已不是8当前:{order.zhuangtai}),跳过处理")
return f"订单{dingdan_id}状态已变更,跳过处理" return f"订单{dingdan_id}状态已变更,跳过处理"
# 获取发单平台类型 # 获取发单平台类型
fadan_pingtai = order.fadan_pingtai fadan_pingtai = order.fadan_pingtai
# 获取打手ID和分成金额 # 获取打手ID和分成金额
dashou_id = order.jiedan_dashou_id dashou_id = order.jiedan_dashou_id
dashou_fencheng = safe_decimal_operation(order.dashou_fencheng) dashou_fencheng = safe_decimal_operation(order.dashou_fencheng)
# 1. 更新订单状态为3已完成 # 1. 更新订单状态为3已完成
order.zhuangtai = 3 order.zhuangtai = 3
order.save(update_fields=['zhuangtai']) order.save(update_fields=['zhuangtai'])
# 2. 更新打手信息(如果存在) # 2. 更新打手信息(如果存在)
updated_dashou = False updated_dashou = False
if dashou_id: if dashou_id:
try: try:
# 查询打手用户主表 # 查询打手用户主表
dashou_user = User.query.filter(yonghuid=dashou_id).first() dashou_user = User.query.filter(UserUID=dashou_id).first()
if dashou_user: if dashou_user:
# 获取打手扩展表 # 获取打手扩展表
dashou_profile = getattr(dashou_user, 'dashou_profile', None) dashou_profile = getattr(dashou_user, 'dashou_profile', None)
if dashou_profile: if dashou_profile:
# 使用F表达式原子更新 # 使用F表达式原子更新
UserDashou.query.filter(pk=dashou_profile.pk).update( UserDashou.query.filter(pk=dashou_profile.pk).update(
chengjiaozongliang=F('chengjiaozongliang') + 1, chengjiaozongliang=F('chengjiaozongliang') + 1,
yue=F('yue') + dashou_fencheng, yue=F('yue') + dashou_fencheng,
zonge=F('zonge') + dashou_fencheng, zonge=F('zonge') + dashou_fencheng,
jinrishouyi=F('jinrishouyi') + dashou_fencheng, jinrishouyi=F('jinrishouyi') + dashou_fencheng,
jinyueshouyi=F('jinyueshouyi') + dashou_fencheng jinyueshouyi=F('jinyueshouyi') + dashou_fencheng
) )
updated_dashou = True updated_dashou = True
logger.info(f"更新打手{dashou_id}信息成功") logger.info(f"更新打手{dashou_id}信息成功")
except Exception as e: except Exception as e:
logger.error(f"更新打手信息失败打手ID: {dashou_id}, 错误: {str(e)}") logger.error(f"更新打手信息失败打手ID: {dashou_id}, 错误: {str(e)}")
# 继续执行,不中断流程 # 继续执行,不中断流程
# 3. 如果是商家发单,更新商家信息 # 3. 如果是商家发单,更新商家信息
updated_shangjia = False updated_shangjia = False
if fadan_pingtai == 2: # 商家发单 if fadan_pingtai == 2: # 商家发单
try: try:
# 获取商家扩展信息 # 获取商家扩展信息
shangjia_kuozhan = getattr(order, 'shangjia_kuozhan', None) shangjia_kuozhan = getattr(order, 'shangjia_kuozhan', None)
if shangjia_kuozhan: if shangjia_kuozhan:
shangjia_id = shangjia_kuozhan.shangjia_id shangjia_id = shangjia_kuozhan.shangjia_id
if shangjia_id: if shangjia_id:
# 查询商家用户 # 查询商家用户
shangjia_user = User.query.filter(yonghuid=shangjia_id).first() shangjia_user = User.query.filter(UserUID=shangjia_id).first()
if shangjia_user: if shangjia_user:
shangjia_profile = getattr(shangjia_user, 'shop_profile', None) shangjia_profile = getattr(shangjia_user, 'shop_profile', None)
if shangjia_profile: if shangjia_profile:
# 更新商家成交订单数量 # 更新商家成交订单数量
UserShangjia.query.filter(pk=shangjia_profile.pk).update( UserShangjia.query.filter(pk=shangjia_profile.pk).update(
chengjiao=F('chengjiao') + 1 chengjiao=F('chengjiao') + 1
) )
updated_shangjia = True updated_shangjia = True
logger.info(f"更新商家{shangjia_id}信息成功") logger.info(f"更新商家{shangjia_id}信息成功")
except Exception as e: except Exception as e:
logger.error(f"更新商家信息失败订单ID: {dingdan_id}, 错误: {str(e)}") logger.error(f"更新商家信息失败订单ID: {dingdan_id}, 错误: {str(e)}")
# 继续执行,不中断流程 # 继续执行,不中断流程
# 记录任务执行结果 # 记录任务执行结果
result_msg = f"订单{dingdan_id}自动结算完成" result_msg = f"订单{dingdan_id}自动结算完成"
if updated_dashou: if updated_dashou:
result_msg += ",打手信息已更新" result_msg += ",打手信息已更新"
if updated_shangjia: if updated_shangjia:
result_msg += ",商家信息已更新" result_msg += ",商家信息已更新"
if fadan_pingtai == 1: if fadan_pingtai == 1:
pass # 平台收益更新逻辑待完善 pass # 平台收益更新逻辑待完善
log_task_execution(f"自动结算订单 {dingdan_id}", True, result_msg) log_task_execution(f"自动结算订单 {dingdan_id}", True, result_msg)
return result_msg return result_msg
except Dingdan.DoesNotExist: except Dingdan.DoesNotExist:
error_msg = f"订单{dingdan_id}不存在" error_msg = f"订单{dingdan_id}不存在"
logger.warning(error_msg) logger.warning(error_msg)
return error_msg return error_msg
except Exception as e: except Exception as e:
error_msg = f"处理订单{dingdan_id}时发生错误: {str(e)}" error_msg = f"处理订单{dingdan_id}时发生错误: {str(e)}"
logger.error(error_msg) logger.error(error_msg)
# 重试机制 # 重试机制
if self.request.retries < self.max_retries: if self.request.retries < self.max_retries:
logger.info(f"订单{dingdan_id}处理失败,准备第{self.request.retries + 1}次重试") logger.info(f"订单{dingdan_id}处理失败,准备第{self.request.retries + 1}次重试")
raise self.retry(exc=e) raise self.retry(exc=e)
log_task_execution(f"自动结算订单 {dingdan_id}", False, error_msg) log_task_execution(f"自动结算订单 {dingdan_id}", False, error_msg)
return error_msg return error_msg
@shared_task @shared_task
@rollback_on_failure("批量检查超时订单") @rollback_on_failure("批量检查超时订单")
def check_order_expire_task(): def check_order_expire_task():
""" """
批量检查超时订单(补偿机制) 批量检查超时订单(补偿机制)
【已禁用】ORDER_AUTO_SETTLEMENT_ENABLED=False 【已禁用】ORDER_AUTO_SETTLEMENT_ENABLED=False
""" """
if not getattr(settings, 'ORDER_AUTO_SETTLEMENT_ENABLED', False): if not getattr(settings, 'ORDER_AUTO_SETTLEMENT_ENABLED', False):
logger.warning('订单自动结算补偿检查已关闭(ORDER_AUTO_SETTLEMENT_ENABLED=False),拒绝执行') logger.warning('订单自动结算补偿检查已关闭(ORDER_AUTO_SETTLEMENT_ENABLED=False),拒绝执行')
return {"success": True, "message": "自动结算已禁用", "count": 0} return {"success": True, "message": "自动结算已禁用", "count": 0}
# --- 以下原补偿逻辑保留备查 --- # --- 以下原补偿逻辑保留备查 ---
try: try:
# 计算更宽松的时间点当前时间减去72小时48+24小时 # 计算更宽松的时间点当前时间减去72小时48+24小时
# 这样避免误处理刚变为状态8的订单 # 这样避免误处理刚变为状态8的订单
check_time = timezone.now() - timedelta(seconds=settings.ORDER_EXPIRE_SECONDS + 86400) # 48+24=72小时 check_time = timezone.now() - timedelta(seconds=settings.ORDER_EXPIRE_SECONDS + 86400) # 48+24=72小时
# 查询状态为8且创建时间早于检查时间的订单 # 查询状态为8且创建时间早于检查时间的订单
expired_orders = Dingdan.query.filter( expired_orders = Dingdan.query.filter(
zhuangtai=8, zhuangtai=8,
create_time__lt=check_time create_time__lt=check_time
).values_list('dingdan_id', flat=True) ).values_list('dingdan_id', flat=True)
expired_count = expired_orders.count() expired_count = expired_orders.count()
if expired_count == 0: if expired_count == 0:
logger.info("补偿检查:无超时订单") logger.info("补偿检查:无超时订单")
return {"success": True, "message": "无超时订单", "count": 0} return {"success": True, "message": "无超时订单", "count": 0}
# 分批处理超时订单(避免一次处理太多) # 分批处理超时订单(避免一次处理太多)
batch_size = 10 batch_size = 10
processed_count = 0 processed_count = 0
for i in range(0, expired_count, batch_size): for i in range(0, expired_count, batch_size):
batch = expired_orders[i:i+batch_size] batch = expired_orders[i:i+batch_size]
# 异步处理每个超时订单 # 异步处理每个超时订单
for dingdan_id in batch: for dingdan_id in batch:
process_expired_order.apply_async( process_expired_order.apply_async(
args=[dingdan_id], args=[dingdan_id],
queue='order_tasks', queue='order_tasks',
priority=8 # 补偿任务的优先级低一些 priority=8 # 补偿任务的优先级低一些
) )
processed_count += 1 processed_count += 1
result_msg = f"补偿检查:发现{expired_count}个可能超时的订单,已提交处理{processed_count}" result_msg = f"补偿检查:发现{expired_count}个可能超时的订单,已提交处理{processed_count}"
log_task_execution("批量检查超时订单", True, result_msg) log_task_execution("批量检查超时订单", True, result_msg)
return { return {
"success": True, "success": True,
"message": result_msg, "message": result_msg,
"total_count": expired_count, "total_count": expired_count,
"processed_count": processed_count "processed_count": processed_count
} }
except Exception as e: except Exception as e:
error_msg = f"批量检查超时订单失败: {str(e)}" error_msg = f"批量检查超时订单失败: {str(e)}"
logger.error(error_msg) logger.error(error_msg)
log_task_execution("批量检查超时订单", False, error_msg) log_task_execution("批量检查超时订单", False, error_msg)
return { return {
"success": False, "success": False,
"message": error_msg, "message": error_msg,
"error": str(e) "error": str(e)
} }

View File

@@ -1,204 +1,204 @@
import logging import logging
from datetime import date from datetime import date
from decimal import Decimal from decimal import Decimal
from django.db import transaction from django.db import transaction
from django.db.models import F from django.db.models import F
from config.models import DailyIncomeStat, DailyPayoutStat from config.models import DailyIncomeStat, DailyPayoutStat
from orders.models import Dingdan, DingdanPingtai, DingdanShangjia, Lilubiao from orders.models import Dingdan, DingdanPingtai, DingdanShangjia, Lilubiao
from products.models import Gsfenhong from products.models import Gsfenhong
from users.models import UserDashou, UserGuanshi from users.models import UserDashou, UserGuanshi
from backend.utils import update_guanshi_daily_by_action from backend.utils import update_guanshi_daily_by_action
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def get_order_user_id(order): def get_order_user_id(order):
if order.fadan_pingtai == 1: if order.fadan_pingtai == 1:
try: try:
ext = DingdanPingtai.objects.get(dingdan=order) ext = DingdanPingtai.objects.get(dingdan=order)
return ext.laoban_id return ext.laoban_id
except DingdanPingtai.DoesNotExist: except DingdanPingtai.DoesNotExist:
return None return None
elif order.fadan_pingtai == 2: elif order.fadan_pingtai == 2:
try: try:
ext = DingdanShangjia.objects.get(dingdan=order) ext = DingdanShangjia.objects.get(dingdan=order)
return ext.shangjia_id return ext.shangjia_id
except DingdanShangjia.DoesNotExist: except DingdanShangjia.DoesNotExist:
return None return None
return None return None
def update_daily_income(amount): def update_daily_income(amount):
""" """
原子更新当日收入统计金额累加笔数加1 原子更新当日收入统计金额累加笔数加1
用于微信支付成功回调。 用于微信支付成功回调。
参数: 参数:
amount: Decimal 本次收入金额 amount: Decimal 本次收入金额
""" """
today = date.today() today = date.today()
year, month, day = today.year, today.month, today.day year, month, day = today.year, today.month, today.day
with transaction.atomic(): with transaction.atomic():
stat, created = DailyIncomeStat.objects.select_for_update().get_or_create( stat, created = DailyIncomeStat.objects.select_for_update().get_or_create(
date=today, date=today,
defaults={ defaults={
'year': year, 'year': year,
'month': month, 'month': month,
'day': day, 'day': day,
'total_amount': amount, 'total_amount': amount,
'total_count': 1 'total_count': 1
} }
) )
if not created: if not created:
# 原子累加 # 原子累加
stat.total_amount = F('total_amount') + amount stat.total_amount = F('total_amount') + amount
stat.total_count = F('total_count') + 1 stat.total_count = F('total_count') + 1
stat.save(update_fields=['total_amount', 'total_count']) stat.save(update_fields=['total_amount', 'total_count'])
logger.info( logger.info(
f"每日收入更新: {today}, +{amount}元, 总金额={stat.total_amount if created else stat.total_amount + amount}, 总笔数={stat.total_count if created else stat.total_count + 1}") f"每日收入更新: {today}, +{amount}元, 总金额={stat.total_amount if created else stat.total_amount + amount}, 总笔数={stat.total_count if created else stat.total_count + 1}")
def update_daily_payout(amount): def update_daily_payout(amount):
""" """
原子更新当日出款统计金额累加笔数加1 原子更新当日出款统计金额累加笔数加1
用于提现成功、结算打款等场景。 用于提现成功、结算打款等场景。
参数: 参数:
amount: Decimal 本次出款金额 amount: Decimal 本次出款金额
""" """
today = date.today() today = date.today()
year, month, day = today.year, today.month, today.day year, month, day = today.year, today.month, today.day
with transaction.atomic(): with transaction.atomic():
stat, created = DailyPayoutStat.objects.select_for_update().get_or_create( stat, created = DailyPayoutStat.objects.select_for_update().get_or_create(
date=today, date=today,
defaults={ defaults={
'year': year, 'year': year,
'month': month, 'month': month,
'day': day, 'day': day,
'total_amount': amount, 'total_amount': amount,
'total_count': 1 'total_count': 1
} }
) )
if not created: if not created:
# 原子累加 # 原子累加
stat.total_amount = F('total_amount') + amount stat.total_amount = F('total_amount') + amount
stat.total_count = F('total_count') + 1 stat.total_count = F('total_count') + 1
stat.save(update_fields=['total_amount', 'total_count']) stat.save(update_fields=['total_amount', 'total_count'])
logger.info(f"每日出款更新: {today}, +{amount}元, 总金额={stat.total_amount if created else stat.total_amount + amount}, 总笔数={stat.total_count if created else stat.total_count + 1}") logger.info(f"每日出款更新: {today}, +{amount}元, 总金额={stat.total_amount if created else stat.total_amount + amount}, 总笔数={stat.total_count if created else stat.total_count + 1}")
def calc_shangjia_order_fencheng(jine): def calc_shangjia_order_fencheng(jine):
""" """
商家发单时计算打手/管事分成。 商家发单时计算打手/管事分成。
打手优先:打手+管事 > 订单金额时,管事分成为 0。 打手优先:打手+管事 > 订单金额时,管事分成为 0。
""" """
jine = Decimal(str(jine)) jine = Decimal(str(jine))
try: try:
lilu_obj = Lilubiao.objects.get(fadanpingtai='3') lilu_obj = Lilubiao.objects.get(fadanpingtai='3')
rate_dashou = Decimal(str(lilu_obj.lilu)) if lilu_obj.lilu and lilu_obj.lilu > 0 else Decimal('1') rate_dashou = Decimal(str(lilu_obj.lilu)) if lilu_obj.lilu and lilu_obj.lilu > 0 else Decimal('1')
except Lilubiao.DoesNotExist: except Lilubiao.DoesNotExist:
rate_dashou = Decimal('1') rate_dashou = Decimal('1')
lilu_guanshi_obj = Lilubiao.objects.filter(fadanpingtai='13').first() lilu_guanshi_obj = Lilubiao.objects.filter(fadanpingtai='13').first()
rate_guanshi = ( rate_guanshi = (
Decimal(str(lilu_guanshi_obj.lilu)) Decimal(str(lilu_guanshi_obj.lilu))
if lilu_guanshi_obj and lilu_guanshi_obj.lilu is not None if lilu_guanshi_obj and lilu_guanshi_obj.lilu is not None
else Decimal('0') else Decimal('0')
) )
dashou_fencheng = (jine * rate_dashou).quantize(Decimal('0.01')) dashou_fencheng = (jine * rate_dashou).quantize(Decimal('0.01'))
guanshi_raw = (jine * rate_guanshi).quantize(Decimal('0.01')) guanshi_raw = (jine * rate_guanshi).quantize(Decimal('0.01'))
if dashou_fencheng + guanshi_raw > jine: if dashou_fencheng + guanshi_raw > jine:
guanshi_fencheng = Decimal('0.00') guanshi_fencheng = Decimal('0.00')
else: else:
guanshi_fencheng = guanshi_raw guanshi_fencheng = guanshi_raw
return dashou_fencheng, guanshi_fencheng return dashou_fencheng, guanshi_fencheng
def settle_shangjia_order_guanshi_fenhong(order, dashou_id): def settle_shangjia_order_guanshi_fenhong(order, dashou_id):
""" """
商家订单结单时结算管事分红(幂等,失败不抛异常阻断主流程)。 商家订单结单时结算管事分红(幂等,失败不抛异常阻断主流程)。
""" """
if getattr(order, 'fadan_pingtai', None) != 2: if getattr(order, 'fadan_pingtai', None) != 2:
return return
guanshi_fencheng = order.guanshi_fencheng or Decimal('0') guanshi_fencheng = order.guanshi_fencheng or Decimal('0')
if guanshi_fencheng <= 0: if guanshi_fencheng <= 0:
return return
if Gsfenhong.objects.filter(dingdan_id=order.dingdan_id).exists(): if Gsfenhong.objects.filter(dingdan_id=order.dingdan_id).exists():
logger.info(f"商家订单管事分红已处理: {order.dingdan_id}") logger.info(f"商家订单管事分红已处理: {order.dingdan_id}")
return return
if not dashou_id: if not dashou_id:
return return
try: try:
dashou = UserDashou.objects.select_related('user').get(user__yonghuid=dashou_id) dashou = UserDashou.objects.select_related('user').get(user__UserUID=dashou_id)
except UserDashou.DoesNotExist: except UserDashou.DoesNotExist:
logger.info(f"商家订单管事分红跳过: 打手{dashou_id}不存在") logger.info(f"商家订单管事分红跳过: 打手{dashou_id}不存在")
return return
guanshi_id = dashou.yaoqingren guanshi_id = dashou.yaoqingren
if not guanshi_id: if not guanshi_id:
logger.info(f"商家订单管事分红跳过: 打手{dashou_id}无邀请管事") logger.info(f"商家订单管事分红跳过: 打手{dashou_id}无邀请管事")
return return
try: try:
with transaction.atomic(): with transaction.atomic():
guanshi = UserGuanshi.objects.select_for_update().get(user__yonghuid=guanshi_id) guanshi = UserGuanshi.objects.select_for_update().get(user__UserUID=guanshi_id)
UserGuanshi.objects.filter(id=guanshi.id).update( UserGuanshi.objects.filter(id=guanshi.id).update(
yue=F('yue') + guanshi_fencheng, yue=F('yue') + guanshi_fencheng,
chongzhifenrun=F('chongzhifenrun') + guanshi_fencheng, chongzhifenrun=F('chongzhifenrun') + guanshi_fencheng,
) )
user_main = dashou.user user_main = dashou.user
Gsfenhong.objects.create( Gsfenhong.objects.create(
dingdan_id=order.dingdan_id, dingdan_id=order.dingdan_id,
guanshi=guanshi_id, guanshi=guanshi_id,
dashouid=dashou_id, dashouid=dashou_id,
shuoming='商家订单分红', shuoming='商家订单分红',
fenhong=guanshi_fencheng, fenhong=guanshi_fencheng,
avatar=user_main.avatar if user_main else None, avatar=user_main.avatar if user_main else None,
nicheng=dashou.nicheng or '未知打手', nicheng=dashou.nicheng or '未知打手',
fenhong_leixing=3, fenhong_leixing=3,
) )
logger.info( logger.info(
f"商家订单管事分红成功: 订单{order.dingdan_id}, 管事{guanshi_id}, " f"商家订单管事分红成功: 订单{order.dingdan_id}, 管事{guanshi_id}, "
f"打手{dashou_id}, 金额{guanshi_fencheng}" f"打手{dashou_id}, 金额{guanshi_fencheng}"
) )
except UserGuanshi.DoesNotExist: except UserGuanshi.DoesNotExist:
logger.warning(f"商家订单管事分红跳过: 管事{guanshi_id}不存在") logger.warning(f"商家订单管事分红跳过: 管事{guanshi_id}不存在")
return return
except Exception as e: except Exception as e:
logger.error(f"商家订单管事分红失败: {e}", exc_info=True) logger.error(f"商家订单管事分红失败: {e}", exc_info=True)
return return
try: try:
update_guanshi_daily_by_action( update_guanshi_daily_by_action(
yonghuid=guanshi_id, yonghuid=guanshi_id,
action=3, action=3,
amount=guanshi_fencheng, amount=guanshi_fencheng,
) )
except Exception as e: except Exception as e:
logger.error(f"商家订单管事日统计更新失败: {e}") logger.error(f"商家订单管事日统计更新失败: {e}")

View File

@@ -62,7 +62,7 @@ from orders.models import (
Lilubiao, Pingfen, Tuikuanjilu Lilubiao, Pingfen, Tuikuanjilu
) )
from products.models import Shangpin, ShangpinLeixing, Huiyuangoumai from products.models import Shangpin, ShangpinLeixing, Huiyuangoumai
from users.models import UserDashou, UserShangjia, UserBoss from users.models import UserDashou, UserShangjia, UserBoss
from gvsdsdk.models import User from gvsdsdk.models import User
from rank.models import DashouBiaoxian, Chenghao, DingdanBiaoqian, YonghuChenghao from rank.models import DashouBiaoxian, Chenghao, DingdanBiaoqian, YonghuChenghao
from config.models import ( from config.models import (
@@ -241,7 +241,7 @@ class WechatPayNotifyView(APIView):
if hasattr(dingdan, 'pingtai_kuozhan'): if hasattr(dingdan, 'pingtai_kuozhan'):
laoban_id = dingdan.pingtai_kuozhan.laoban_id laoban_id = dingdan.pingtai_kuozhan.laoban_id
if laoban_id: if laoban_id:
user_main = User.query.filter(yonghuid=laoban_id).first() user_main = User.query.filter(UserUID=laoban_id).first()
if user_main and hasattr(user_main, 'boss_profile'): if user_main and hasattr(user_main, 'boss_profile'):
boss = user_main.boss_profile boss = user_main.boss_profile
boss.zonge = (boss.zonge or 0) + (dingdan.jine or 0) boss.zonge = (boss.zonge or 0) + (dingdan.jine or 0)
@@ -525,7 +525,7 @@ class PaymentVerifyView(APIView):
# 更新老板扩展表 # 更新老板扩展表
laoban_id = dingdan.pingtai_kuozhan.laoban_id if hasattr(dingdan, 'pingtai_kuozhan') else None laoban_id = dingdan.pingtai_kuozhan.laoban_id if hasattr(dingdan, 'pingtai_kuozhan') else None
if laoban_id: if laoban_id:
user_main = User.query.filter(yonghuid=laoban_id).first() user_main = User.query.filter(UserUID=laoban_id).first()
if user_main and hasattr(user_main, 'boss_profile'): if user_main and hasattr(user_main, 'boss_profile'):
boss = user_main.boss_profile boss = user_main.boss_profile
boss.zonge = (boss.zonge or 0) + (dingdan.jine or 0) boss.zonge = (boss.zonge or 0) + (dingdan.jine or 0)
@@ -712,7 +712,7 @@ class CreateOrderView(APIView):
if zhiding: if zhiding:
# 查询主表中是否存在该打手 # 查询主表中是否存在该打手
zhiding_user = User.query.filter( zhiding_user = User.query.filter(
yonghuid=zhiding, UserUID=zhiding,
#user_type='dashou' #user_type='dashou'
).first() ).first()
@@ -1349,7 +1349,7 @@ class JiedanView(APIView):
# 7. 更新打手扩展表如果有打手ID和分成 # 7. 更新打手扩展表如果有打手ID和分成
if jiedan_dashou_id and dashou_fencheng > 0: if jiedan_dashou_id and dashou_fencheng > 0:
# 查询打手用户 # 查询打手用户
dashou_user = User.query.filter(yonghuid=jiedan_dashou_id).first() dashou_user = User.query.filter(UserUID=jiedan_dashou_id).first()
if dashou_user: if dashou_user:
# 查询打手扩展表 # 查询打手扩展表
@@ -1512,7 +1512,7 @@ class DingdanXiangqingView2(APIView):
jiedan_time = '' jiedan_time = ''
tijiao_time = '' tijiao_time = ''
if jiedan_dashou_id: if jiedan_dashou_id:
dashou_user = User.query.filter(yonghuid=jiedan_dashou_id).first() dashou_user = User.query.filter(UserUID=jiedan_dashou_id).first()
if dashou_user: if dashou_user:
dashou_touxiang = dashou_user.avatar or '' dashou_touxiang = dashou_user.avatar or ''
try: try:
@@ -1661,7 +1661,7 @@ class JiedanView2(APIView):
# 9. 更新打手收益与状态 # 9. 更新打手收益与状态
if jiedan_dashou_id and dashou_fencheng > 0: if jiedan_dashou_id and dashou_fencheng > 0:
dashou_user = User.query.filter(yonghuid=jiedan_dashou_id).first() dashou_user = User.query.filter(UserUID=jiedan_dashou_id).first()
if dashou_user: if dashou_user:
try: try:
dashou_ext = dashou_user.dashou_profile dashou_ext = dashou_user.dashou_profile
@@ -1916,7 +1916,7 @@ class ShangjiaPaifaView(APIView):
zhiding_dashou = None zhiding_dashou = None
if zhiding_uid: if zhiding_uid:
try: try:
zhiding_user = User.query.get(yonghuid=zhiding_uid) zhiding_user = User.query.get(UserUID=zhiding_uid)
zhiding_dashou = zhiding_user.dashou_profile zhiding_dashou = zhiding_user.dashou_profile
if zhiding_dashou.zhanghaozhuangtai != 1: if zhiding_dashou.zhanghaozhuangtai != 1:
return Response({'code': 400, 'msg': '指定打手状态异常'}) return Response({'code': 400, 'msg': '指定打手状态异常'})
@@ -2223,7 +2223,7 @@ class ShangjiaDingdanXiangqingView(APIView):
dashou_avatar = '' dashou_avatar = ''
if dashou_yonghuid: if dashou_yonghuid:
dashou_user = User.query.filter( dashou_user = User.query.filter(
yonghuid=dashou_yonghuid UserUID=dashou_yonghuid
).select_related('dashou_profile').first() ).select_related('dashou_profile').first()
if dashou_user: if dashou_user:
dashou_avatar = dashou_user.avatar or '' dashou_avatar = dashou_user.avatar or ''
@@ -2426,7 +2426,7 @@ class ShangjiaJiesuanView(APIView):
# ========== 本地订单正常结算给打手 ========== # ========== 本地订单正常结算给打手 ==========
# 查询打手信息 # 查询打手信息
try: try:
dashou_user = User.query.get(yonghuid=jiedan_dashou_id) dashou_user = User.query.get(UserUID=jiedan_dashou_id)
dashou = dashou_user.dashou_profile dashou = dashou_user.dashou_profile
except (User.DoesNotExist, UserDashou.DoesNotExist): except (User.DoesNotExist, UserDashou.DoesNotExist):
return Response({ return Response({
@@ -2769,7 +2769,7 @@ class ShangjiaTuikuanShenqingView(APIView):
if dingdan.jiedan_dashou_id: if dingdan.jiedan_dashou_id:
try: try:
dashou_main = User.query.filter( dashou_main = User.query.filter(
yonghuid=dingdan.jiedan_dashou_id UserUID=dingdan.jiedan_dashou_id
).first() ).first()
if dashou_main and hasattr(dashou_main, 'dashou_profile'): if dashou_main and hasattr(dashou_main, 'dashou_profile'):
dashou_profile = dashou_main.dashou_profile dashou_profile = dashou_main.dashou_profile
@@ -2851,7 +2851,7 @@ class ShangjiaChufaShenqingView(APIView):
with transaction.atomic(): with transaction.atomic():
# 验证打手身份 # 验证打手身份
try: try:
dashou_user = User.query.get(yonghuid=dashou_id) dashou_user = User.query.get(UserUID=dashou_id)
dashou = dashou_user.dashou_profile dashou = dashou_user.dashou_profile
except User.DoesNotExist: except User.DoesNotExist:
return Response({ return Response({
@@ -3030,7 +3030,7 @@ class DashouDingdanHuoquView(APIView):
zhiding_info = {} zhiding_info = {}
if zhiding_ids: if zhiding_ids:
dashou_query = User.query.filter( dashou_query = User.query.filter(
yonghuid__in=zhiding_ids UserUID__in=zhiding_ids
).select_related('dashou_profile').annotate( ).select_related('dashou_profile').annotate(
nicheng=F('dashou_profile__nicheng') nicheng=F('dashou_profile__nicheng')
).values('yonghuid', 'avatar', 'nicheng') ).values('yonghuid', 'avatar', 'nicheng')
@@ -3082,7 +3082,7 @@ class DashouDingdanHuoquView(APIView):
# 将 yonghuid 字符串转换为 User 的主键 id # 将 yonghuid 字符串转换为 User 的主键 id
user_id_map = {} user_id_map = {}
if yonghuid_set: if yonghuid_set:
users = User.query.filter(yonghuid__in=yonghuid_set).values('id', 'yonghuid') users = User.query.filter(UserUID__in=yonghuid_set).values('id', 'yonghuid')
for u in users: for u in users:
user_id_map[u['yonghuid']] = u['id'] user_id_map[u['yonghuid']] = u['id']
@@ -3347,7 +3347,7 @@ def send_group_message(
def check_user_permission(identity_type, uid, order): def check_user_permission(identity_type, uid, order):
"""验证用户身份、账号状态、以及是否属于该订单""" """验证用户身份、账号状态、以及是否属于该订单"""
try: try:
user = User.query.get(yonghuid=uid) user = User.query.get(UserUID=uid)
except User.DoesNotExist: except User.DoesNotExist:
return False, '用户不存在' return False, '用户不存在'
@@ -4674,7 +4674,7 @@ class AdGengHuanDaShou(APIView):
# 8. 验证新打手ID是否存在并且是打手身份 # 8. 验证新打手ID是否存在并且是打手身份
try: try:
new_dashou_user = User.query.get( new_dashou_user = User.query.get(
yonghuid=new_dashou_id, UserUID=new_dashou_id,
#user_type='dashou' #user_type='dashou'
) )
except User.DoesNotExist: except User.DoesNotExist:
@@ -4769,7 +4769,7 @@ class AdGengHuanDaShou(APIView):
try: try:
# 查询原打手主表 # 查询原打手主表
old_dashou_user = User.query.get( old_dashou_user = User.query.get(
yonghuid=old_dashou_id, UserUID=old_dashou_id,
#user_type='dashou' #user_type='dashou'
) )
@@ -4913,7 +4913,7 @@ class AdQiangZhiJieDan(APIView):
try: try:
# 查询打手用户主表 # 查询打手用户主表
dashou_user = User.query.get( dashou_user = User.query.get(
yonghuid=jiedan_dashou_id, UserUID=jiedan_dashou_id,
#user_type='dashou' #user_type='dashou'
) )
@@ -4956,7 +4956,7 @@ class AdQiangZhiJieDan(APIView):
if shangjia_id: if shangjia_id:
# 查询商家用户主表 # 查询商家用户主表
shangjia_user = User.query.get( shangjia_user = User.query.get(
yonghuid=shangjia_id, UserUID=shangjia_id,
#user_type='shop' #user_type='shop'
) )
@@ -5089,7 +5089,7 @@ class AdJuJueTuiKuan(APIView):
try: try:
# 查询打手用户主表 # 查询打手用户主表
dashou_user = User.query.get( dashou_user = User.query.get(
yonghuid=jiedan_dashou_id, UserUID=jiedan_dashou_id,
#user_type='dashou' #user_type='dashou'
) )
@@ -5132,7 +5132,7 @@ class AdJuJueTuiKuan(APIView):
if shangjia_id: if shangjia_id:
# 查询商家用户主表 # 查询商家用户主表
shangjia_user = User.query.get( shangjia_user = User.query.get(
yonghuid=shangjia_id, UserUID=shangjia_id,
#user_type='shop' #user_type='shop'
) )
@@ -5320,7 +5320,7 @@ class AdTongYiTuiKuanShangJia(APIView):
try: try:
# 查询打手用户主表 # 查询打手用户主表
dashou_user = User.query.get( dashou_user = User.query.get(
yonghuid=jiedan_dashou_id, UserUID=jiedan_dashou_id,
#user_type='dashou' #user_type='dashou'
) )
@@ -5345,7 +5345,7 @@ class AdTongYiTuiKuanShangJia(APIView):
try: try:
# 查询商家用户主表 # 查询商家用户主表
shangjia_user = User.query.get( shangjia_user = User.query.get(
yonghuid=shangjia_id, UserUID=shangjia_id,
#user_type='shop' #user_type='shop'
) )
@@ -5529,7 +5529,7 @@ class AdTongYiTuiKuanPingTai(APIView):
# 14. 更新打手扩展表 # 14. 更新打手扩展表
if jiedan_dashou_id: if jiedan_dashou_id:
try: try:
dashou_user = User.query.get(yonghuid=jiedan_dashou_id) dashou_user = User.query.get(UserUID=jiedan_dashou_id)
dashou_profile = dashou_user.dashou_profile dashou_profile = dashou_user.dashou_profile
dashou_profile.zhuangtai = 1 # 打手状态设为空闲 dashou_profile.zhuangtai = 1 # 打手状态设为空闲
dashou_profile.tuikuanliang += 1 dashou_profile.tuikuanliang += 1
@@ -5540,7 +5540,7 @@ class AdTongYiTuiKuanPingTai(APIView):
# 15. 更新老板扩展表 # 15. 更新老板扩展表
if laoban_id: if laoban_id:
try: try:
laoban_user = User.query.get(yonghuid=laoban_id) laoban_user = User.query.get(UserUID=laoban_id)
laoban_profile = laoban_user.boss_profile laoban_profile = laoban_user.boss_profile
laoban_profile.alltui += 1 laoban_profile.alltui += 1
laoban_profile.zonge -= jine laoban_profile.zonge -= jine
@@ -5865,7 +5865,7 @@ class AdJuJueJieSuan(APIView):
# 8. 更新打手扩展表 # 8. 更新打手扩展表
try: try:
dashou_user = User.query.get(yonghuid=jiedan_dashou_id) dashou_user = User.query.get(UserUID=jiedan_dashou_id)
dashou_profile = dashou_user.dashou_profile dashou_profile = dashou_user.dashou_profile
dashou_profile.zhuangtai = 1 # 打手状态设为正常 dashou_profile.zhuangtai = 1 # 打手状态设为正常
dashou_profile.tuikuanliang += 1 # 退款订单总量+1 dashou_profile.tuikuanliang += 1 # 退款订单总量+1
@@ -5947,7 +5947,7 @@ class AdZhuanYiDaTing(APIView):
# 如果有接单打手,更新其扩展表 # 如果有接单打手,更新其扩展表
if jiedan_dashou_id: if jiedan_dashou_id:
try: try:
dashou_user = User.query.get(yonghuid=jiedan_dashou_id) dashou_user = User.query.get(UserUID=jiedan_dashou_id)
dashou_profile = dashou_user.dashou_profile dashou_profile = dashou_user.dashou_profile
dashou_profile.zhuangtai = 1 dashou_profile.zhuangtai = 1
dashou_profile.tuikuanliang += 1 dashou_profile.tuikuanliang += 1
@@ -6225,7 +6225,7 @@ class ZxsjghdsView(APIView):
# 6.2 释放打手 # 6.2 释放打手
if dashou_id: if dashou_id:
try: try:
dashou_user = User.query.get(yonghuid=dashou_id) dashou_user = User.query.get(UserUID=dashou_id)
dashou_profile = dashou_user.dashou_profile dashou_profile = dashou_user.dashou_profile
dashou_profile.tuikuanliang = (dashou_profile.tuikuanliang or 0) + 1 dashou_profile.tuikuanliang = (dashou_profile.tuikuanliang or 0) + 1
dashou_profile.zhuangtai = 1 # 空闲 dashou_profile.zhuangtai = 1 # 空闲

View File

@@ -1,4 +1,4 @@
# Generated by Django 4.2.27 on 2026-06-17 16:31 # Generated by Django 4.2.27 on 2026-06-17 21:18
from django.db import migrations, models from django.db import migrations, models

View File

@@ -1,4 +1,4 @@
# Generated by Django 4.2.27 on 2026-06-17 16:31 # Generated by Django 4.2.27 on 2026-06-17 21:18
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion
@@ -9,9 +9,9 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
('products', '0001_initial'),
('rank', '0001_initial'), ('rank', '0001_initial'),
('shop', '0001_initial'), ('shop', '0001_initial'),
('products', '0001_initial'),
] ]
operations = [ operations = [

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
# Generated by Django 4.2.27 on 2026-06-17 16:31 # Generated by Django 4.2.27 on 2026-06-17 21:18
from django.conf import settings from django.conf import settings
from django.db import migrations, models from django.db import migrations, models

View File

@@ -1,407 +1,407 @@
# 标准库 # 标准库
import time import time
import random import random
import logging import logging
from decimal import Decimal from decimal import Decimal
# Django 内置 # Django 内置
from django.db.models import F, Max from django.db.models import F, Max
# 项目模型 # 项目模型
## 当前dengji应用 ## 当前dengji应用
from .models import ( from .models import (
Chenghao, KaoheCishuFeiyong, ShenheJilu, KaoheJiluFeiyong, Chenghao, KaoheCishuFeiyong, ShenheJilu, KaoheJiluFeiyong,
YonghuChenghao, KaoheguanBankuai, DingdanBiaoqian YonghuChenghao, KaoheguanBankuai, DingdanBiaoqian
) )
## users应用 ## users应用
from users.models import UserShenheguan, UserDashou from users.models import UserShenheguan, UserDashou
from gvsdsdk.models import User from gvsdsdk.models import User
## orders应用 ## orders应用
from .models import YonghuChenghao from .models import YonghuChenghao
# 日志对象 # 日志对象
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def check_dashou_biaoqian_required(order_id, dashou_yonghuid): def check_dashou_biaoqian_required(order_id, dashou_yonghuid):
""" """
检查打手是否满足订单的标签需求。 检查打手是否满足订单的标签需求。
- 如果订单没有需求标签,直接放行。 - 如果订单没有需求标签,直接放行。
- 如果有,则要求打手至少拥有其中一个标签。 - 如果有,则要求打手至少拥有其中一个标签。
返回 (allowed: bool, message: str) 返回 (allowed: bool, message: str)
""" """
try: try:
# 1. 获取订单的需求标签ID集合 # 1. 获取订单的需求标签ID集合
required_ids = set( required_ids = set(
DingdanBiaoqian.objects.filter(dingdan_id=order_id) DingdanBiaoqian.objects.filter(dingdan_id=order_id)
.values_list('chenghao_id', flat=True) .values_list('chenghao_id', flat=True)
) )
if not required_ids: if not required_ids:
return True, '' return True, ''
# 2. 找到打手对应的用户记录 # 2. 找到打手对应的用户记录
try: try:
user = User.objects.get(yonghuid=dashou_yonghuid) user = User.objects.get(UserUID=dashou_yonghuid)
except User.DoesNotExist: except User.DoesNotExist:
return False, '用户信息异常' return False, '用户信息异常'
# 3. 获取打手已拥有的标签ID集合只取打手类型 # 3. 获取打手已拥有的标签ID集合只取打手类型
owned_ids = set( owned_ids = set(
YonghuChenghao.objects.filter( YonghuChenghao.objects.filter(
yonghu=user, yonghu=user,
chenghao__leixing='dashou' chenghao__leixing='dashou'
).values_list('chenghao_id', flat=True) ).values_list('chenghao_id', flat=True)
) )
if not owned_ids: if not owned_ids:
return False, '您未拥有任何打手标签,无法抢此订单' return False, '您未拥有任何打手标签,无法抢此订单'
# 4. 交集判断 # 4. 交集判断
if required_ids.intersection(owned_ids): if required_ids.intersection(owned_ids):
return True, '' return True, ''
else: else:
return False, '您的标签不符合此订单要求,无法抢单' return False, '您的标签不符合此订单要求,无法抢单'
except Exception as e: except Exception as e:
# 标签校验失败不影响主流程,记录日志并保守放行(也可保守拒绝,按需求选择) # 标签校验失败不影响主流程,记录日志并保守放行(也可保守拒绝,按需求选择)
logger.error(f"标签校验异常: {e}", exc_info=True) logger.error(f"标签校验异常: {e}", exc_info=True)
# 安全起见,如果校验出错,选择拒绝,避免越权 # 安全起见,如果校验出错,选择拒绝,避免越权
return False, '订单标签校验异常,请稍后重试' return False, '订单标签校验异常,请稍后重试'
def get_tag_fee(chenghao, cishu): def get_tag_fee(chenghao, cishu):
""" """
获取标签在指定考核次数下的费用。 获取标签在指定考核次数下的费用。
- 若有对应次数的配置,直接返回。 - 若有对应次数的配置,直接返回。
- 若没有该次数,取该标签下已有最大次数的费用(作为后续次数的价格)。 - 若没有该次数,取该标签下已有最大次数的费用(作为后续次数的价格)。
- 若该标签完全没有费用记录,返回 0.00(免费)。 - 若该标签完全没有费用记录,返回 0.00(免费)。
""" """
fee_obj = KaoheCishuFeiyong.objects.filter(chenghao=chenghao, cishu=cishu).first() fee_obj = KaoheCishuFeiyong.objects.filter(chenghao=chenghao, cishu=cishu).first()
if fee_obj: if fee_obj:
return fee_obj.feiyong return fee_obj.feiyong
max_obj = KaoheCishuFeiyong.objects.filter(chenghao=chenghao).order_by('-cishu').first() max_obj = KaoheCishuFeiyong.objects.filter(chenghao=chenghao).order_by('-cishu').first()
if max_obj: if max_obj:
return max_obj.feiyong return max_obj.feiyong
return Decimal('0.00') return Decimal('0.00')
def generate_unique_jilu_id(): def generate_unique_jilu_id():
""" """
生成唯一的审核记录 ID格式SH + 时间戳(10位) + 随机数(4位) 生成唯一的审核记录 ID格式SH + 时间戳(10位) + 随机数(4位)
循环检查数据库避免重复,最多尝试 10 次。 循环检查数据库避免重复,最多尝试 10 次。
""" """
for _ in range(10): for _ in range(10):
timestamp = str(int(time.time() * 1000))[-10:] timestamp = str(int(time.time() * 1000))[-10:]
random_part = str(random.randint(1000, 9999)) random_part = str(random.randint(1000, 9999))
jilu_id = f'SH{timestamp}{random_part}' jilu_id = f'SH{timestamp}{random_part}'
if not ShenheJilu.objects.filter(jilu_id=jilu_id).exists(): if not ShenheJilu.objects.filter(jilu_id=jilu_id).exists():
return jilu_id return jilu_id
raise Exception('无法生成唯一记录ID请稍后重试') raise Exception('无法生成唯一记录ID请稍后重试')
def validate_shenheguan(shenheguan_id, bankuai, fee, applicant_user): def validate_shenheguan(shenheguan_id, bankuai, fee, applicant_user):
""" """
校验指定考核官是否合法 校验指定考核官是否合法
- 考核官必须存在且未被禁用 - 考核官必须存在且未被禁用
- 必须属于对应板块 - 必须属于对应板块
- 必须处于空闲状态 - 必须处于空闲状态
- 若费用>0则要求已认证 - 若费用>0则要求已认证
返回 (valid, error_msg) 返回 (valid, error_msg)
""" """
if not shenheguan_id: if not shenheguan_id:
return True, '' return True, ''
try: try:
kg = UserShenheguan.objects.select_related('user').get( kg = UserShenheguan.objects.select_related('user').get(
user__yonghuid=shenheguan_id, user__UserUID=shenheguan_id,
zhuangtai=1 zhuangtai=1
) )
except UserShenheguan.DoesNotExist: except UserShenheguan.DoesNotExist:
return False, '考核官不存在或已被禁用' return False, '考核官不存在或已被禁用'
# 板块权限 # 板块权限
if not KaoheguanBankuai.objects.filter(kaoheguan_id=shenheguan_id, bankuai=bankuai).exists(): if not KaoheguanBankuai.objects.filter(kaoheguan_id=shenheguan_id, bankuai=bankuai).exists():
return False, '该考核官不属于此板块' return False, '该考核官不属于此板块'
# 空闲状态 # 空闲状态
if kg.shenhe_zhuangtai != 0: if kg.shenhe_zhuangtai != 0:
return False, '该考核官当前忙碌,无法指定' return False, '该考核官当前忙碌,无法指定'
# 费用>0需要认证 # 费用>0需要认证
if float(fee) > 0 and not kg.is_renzheng: if float(fee) > 0 and not kg.is_renzheng:
return False, '费用大于0时只能指定已认证的考核官' return False, '费用大于0时只能指定已认证的考核官'
return True, '' return True, ''
def create_shenhe_jilu(user, tag_id, game_nick, remark, reapply, jilu_id=None, shenheguan_id=''): def create_shenhe_jilu(user, tag_id, game_nick, remark, reapply, jilu_id=None, shenheguan_id=''):
""" """
创建或更新审核记录。 创建或更新审核记录。
- 首次申请:创建新记录,生成唯一 jilu_id。 - 首次申请:创建新记录,生成唯一 jilu_id。
- 再次申请:基于原记录(必须状态为未通过)更新次数、累加总费用、更新备注和游戏昵称, - 再次申请:基于原记录(必须状态为未通过)更新次数、累加总费用、更新备注和游戏昵称,
保留审核官信息,状态重置为待审核。不创建新记录。 保留审核官信息,状态重置为待审核。不创建新记录。
- 每次申请均创建一条费用明细记录KaoheJiluFeiyong记录本次缴费。 - 每次申请均创建一条费用明细记录KaoheJiluFeiyong记录本次缴费。
- 若原记录有考核官,则将其状态改为审核中。 - 若原记录有考核官,则将其状态改为审核中。
- 新增 shenheguan_id 参数指定考核官ID仅在原记录无考核官时可传入。 - 新增 shenheguan_id 参数指定考核官ID仅在原记录无考核官时可传入。
返回 (success, message, record) 返回 (success, message, record)
""" """
try: try:
# 1. 校验标签存在 # 1. 校验标签存在
try: try:
chenghao = Chenghao.objects.get(id=tag_id) chenghao = Chenghao.objects.get(id=tag_id)
except Chenghao.DoesNotExist: except Chenghao.DoesNotExist:
return False, '标签不存在', None return False, '标签不存在', None
# 2. 判断用户是否已拥有该标签 # 2. 判断用户是否已拥有该标签
if YonghuChenghao.objects.filter(yonghu=user, chenghao=chenghao).exists(): if YonghuChenghao.objects.filter(yonghu=user, chenghao=chenghao).exists():
return False, '您已拥有该标签,无需重复考核', None return False, '您已拥有该标签,无需重复考核', None
# 3. 检查是否有进行中的审核记录(待审核、审核中) # 3. 检查是否有进行中的审核记录(待审核、审核中)
has_pending = ShenheJilu.objects.filter( has_pending = ShenheJilu.objects.filter(
shenqingren_id=user.yonghuid, shenqingren_id=user.yonghuid,
chenghao=chenghao, chenghao=chenghao,
zhuangtai__in=[0, 3] zhuangtai__in=[0, 3]
).exists() ).exists()
if has_pending: if has_pending:
return False, '您有未完成的考核申请,请等待结果', None return False, '您有未完成的考核申请,请等待结果', None
last_record = None last_record = None
current_fee = Decimal('0.00') current_fee = Decimal('0.00')
# 4. 处理再次申请 # 4. 处理再次申请
if reapply and jilu_id: if reapply and jilu_id:
# 查询原记录(未通过状态) # 查询原记录(未通过状态)
last_record = ShenheJilu.objects.filter( last_record = ShenheJilu.objects.filter(
jilu_id=jilu_id, jilu_id=jilu_id,
shenqingren_id=user.yonghuid, shenqingren_id=user.yonghuid,
zhuangtai=2 zhuangtai=2
).first() ).first()
if not last_record: if not last_record:
return False, '原记录不存在或状态不是未通过', None return False, '原记录不存在或状态不是未通过', None
new_cishu = last_record.cishu + 1 new_cishu = last_record.cishu + 1
current_fee = get_tag_fee(chenghao, new_cishu) current_fee = get_tag_fee(chenghao, new_cishu)
# 确定最终状态:有考核官 = 审核中(0),否则待审核(3) # 确定最终状态:有考核官 = 审核中(0),否则待审核(3)
final_kg_id = last_record.shenheguan_id # 保留原来的 final_kg_id = last_record.shenheguan_id # 保留原来的
if shenheguan_id and not last_record.shenheguan_id: if shenheguan_id and not last_record.shenheguan_id:
final_kg_id = shenheguan_id # 新指定 final_kg_id = shenheguan_id # 新指定
final_zhuangtai = 0 if final_kg_id else 3 # 有考核官就是审核中 final_zhuangtai = 0 if final_kg_id else 3 # 有考核官就是审核中
if final_zhuangtai == 3: if final_zhuangtai == 3:
final_kg_id = None final_kg_id = None
# 原子化更新 # 原子化更新
ShenheJilu.objects.filter(pk=last_record.pk).update( ShenheJilu.objects.filter(pk=last_record.pk).update(
cishu=new_cishu, cishu=new_cishu,
jiaofei_jine=F('jiaofei_jine') + current_fee, jiaofei_jine=F('jiaofei_jine') + current_fee,
dashou_youxi_id=game_nick, dashou_youxi_id=game_nick,
dashou_beizhu=remark, dashou_beizhu=remark,
guize_neirong=chenghao.kaohe_guize or '', guize_neirong=chenghao.kaohe_guize or '',
zhuangtai=final_zhuangtai, zhuangtai=final_zhuangtai,
shenheguan_id=final_kg_id, shenheguan_id=final_kg_id,
) )
last_record.refresh_from_db() last_record.refresh_from_db()
record = last_record record = last_record
# 如果原考核官被替换或清除,释放旧考核官 # 如果原考核官被替换或清除,释放旧考核官
if last_record.shenheguan_id != final_kg_id: if last_record.shenheguan_id != final_kg_id:
if last_record.shenheguan_id: if last_record.shenheguan_id:
UserShenheguan.objects.filter( UserShenheguan.objects.filter(
user__yonghuid=last_record.shenheguan_id user__UserUID=last_record.shenheguan_id
).update(shenhe_zhuangtai=0) ).update(shenhe_zhuangtai=0)
else: else:
# 首次申请 # 首次申请
max_cishu = ShenheJilu.objects.filter( max_cishu = ShenheJilu.objects.filter(
shenqingren_id=user.yonghuid, shenqingren_id=user.yonghuid,
chenghao=chenghao, chenghao=chenghao,
zhuangtai__in=[1, 2] zhuangtai__in=[1, 2]
).aggregate(max=Max('cishu'))['max'] or 0 ).aggregate(max=Max('cishu'))['max'] or 0
new_cishu = max_cishu + 1 new_cishu = max_cishu + 1
current_fee = get_tag_fee(chenghao, new_cishu) current_fee = get_tag_fee(chenghao, new_cishu)
bankuai = chenghao.bankuai bankuai = chenghao.bankuai
rule_text = chenghao.kaohe_guize or '' rule_text = chenghao.kaohe_guize or ''
new_jilu_id = generate_unique_jilu_id() new_jilu_id = generate_unique_jilu_id()
initial_zhuangtai = 0 if shenheguan_id else 3 # 指定→审核中,否则待审核 initial_zhuangtai = 0 if shenheguan_id else 3 # 指定→审核中,否则待审核
record = ShenheJilu.objects.create( record = ShenheJilu.objects.create(
jilu_id=new_jilu_id, jilu_id=new_jilu_id,
shenqingren_id=user.yonghuid, shenqingren_id=user.yonghuid,
zhuangtai=initial_zhuangtai, zhuangtai=initial_zhuangtai,
bankuai=bankuai, bankuai=bankuai,
chenghao=chenghao, chenghao=chenghao,
cishu=new_cishu, cishu=new_cishu,
jiaofei_jine=current_fee, jiaofei_jine=current_fee,
dashou_youxi_id=game_nick, dashou_youxi_id=game_nick,
dashou_beizhu=remark, dashou_beizhu=remark,
guize_neirong=rule_text, guize_neirong=rule_text,
shenheguan_id=shenheguan_id if shenheguan_id else None, shenheguan_id=shenheguan_id if shenheguan_id else None,
) )
# 5. 创建费用明细(防重复) # 5. 创建费用明细(防重复)
KaoheJiluFeiyong.objects.get_or_create( KaoheJiluFeiyong.objects.get_or_create(
jilu=record, jilu=record,
cishu=record.cishu, cishu=record.cishu,
defaults={'jine': current_fee} defaults={'jine': current_fee}
) )
# 6. 更新考核官统计(仅当状态为审核中且有考核官) # 6. 更新考核官统计(仅当状态为审核中且有考核官)
if record.zhuangtai == 0 and record.shenheguan_id: if record.zhuangtai == 0 and record.shenheguan_id:
UserShenheguan.objects.filter( UserShenheguan.objects.filter(
user__yonghuid=record.shenheguan_id user__UserUID=record.shenheguan_id
).update( ).update(
shenhe_zongshu=F('shenhe_zongshu') + 1, shenhe_zongshu=F('shenhe_zongshu') + 1,
shenhe_zhuangtai=1 shenhe_zhuangtai=1
) )
return True, '申请成功', record return True, '申请成功', record
except Exception as e: except Exception as e:
logger.error(f"创建审核记录异常: {e}", exc_info=True) logger.error(f"创建审核记录异常: {e}", exc_info=True)
return False, '系统异常', None return False, '系统异常', None
def create_shenhe_jilu_from_temp(user, temp_data): def create_shenhe_jilu_from_temp(user, temp_data):
""" """
根据临时表数据创建审核记录(专供支付回调使用) 根据临时表数据创建审核记录(专供支付回调使用)
参数 temp_data 是 KaohePayTemp 对象 参数 temp_data 是 KaohePayTemp 对象
返回 (success, message, record) 返回 (success, message, record)
""" """
try: try:
logger.info(f"开始从临时表创建审核记录: 用户={user.yonghuid}, 订单={temp_data.dingdan_id}") logger.info(f"开始从临时表创建审核记录: 用户={user.yonghuid}, 订单={temp_data.dingdan_id}")
chenghao = Chenghao.objects.get(id=temp_data.tag_id) chenghao = Chenghao.objects.get(id=temp_data.tag_id)
logger.info(f"获取标签成功: {chenghao.mingcheng}") logger.info(f"获取标签成功: {chenghao.mingcheng}")
# 检查是否已拥有标签 # 检查是否已拥有标签
if YonghuChenghao.objects.filter(yonghu=user, chenghao=chenghao).exists(): if YonghuChenghao.objects.filter(yonghu=user, chenghao=chenghao).exists():
logger.warning(f"用户 {user.yonghuid} 已拥有标签 {chenghao.mingcheng}") logger.warning(f"用户 {user.yonghuid} 已拥有标签 {chenghao.mingcheng}")
return False, '您已拥有该标签,无需重复考核', None return False, '您已拥有该标签,无需重复考核', None
# 检查是否有进行中的审核 # 检查是否有进行中的审核
if ShenheJilu.objects.filter( if ShenheJilu.objects.filter(
shenqingren_id=user.yonghuid, shenqingren_id=user.yonghuid,
chenghao=chenghao, chenghao=chenghao,
zhuangtai__in=[0, 3] zhuangtai__in=[0, 3]
).exists(): ).exists():
logger.warning(f"用户 {user.yonghuid} 有未完成的考核申请") logger.warning(f"用户 {user.yonghuid} 有未完成的考核申请")
return False, '您有未完成的考核申请,请等待结果', None return False, '您有未完成的考核申请,请等待结果', None
# 使用临时表中预计算好的次数和费用 # 使用临时表中预计算好的次数和费用
new_cishu = temp_data.cishu new_cishu = temp_data.cishu
current_fee = temp_data.fee current_fee = temp_data.fee
reapply = temp_data.reapply reapply = temp_data.reapply
jilu_id = temp_data.jilu_id jilu_id = temp_data.jilu_id
shenheguan_id = temp_data.shenheguan_id shenheguan_id = temp_data.shenheguan_id
logger.info(f"临时表数据: cishu={new_cishu}, fee={current_fee}, reapply={reapply}, jilu_id={jilu_id}, shenheguan_id={shenheguan_id}") logger.info(f"临时表数据: cishu={new_cishu}, fee={current_fee}, reapply={reapply}, jilu_id={jilu_id}, shenheguan_id={shenheguan_id}")
# 再次申请校验 # 再次申请校验
if reapply: if reapply:
if not jilu_id: if not jilu_id:
logger.error("再次申请但未提供原记录ID") logger.error("再次申请但未提供原记录ID")
return False, '再次申请必须提供原记录ID', None return False, '再次申请必须提供原记录ID', None
last = ShenheJilu.objects.filter( last = ShenheJilu.objects.filter(
jilu_id=jilu_id, jilu_id=jilu_id,
shenqingren_id=user.yonghuid, shenqingren_id=user.yonghuid,
zhuangtai=2 zhuangtai=2
).first() ).first()
if not last: if not last:
logger.error(f"原记录不存在或状态不是未通过: jilu_id={jilu_id}") logger.error(f"原记录不存在或状态不是未通过: jilu_id={jilu_id}")
return False, '原记录不存在或状态不是未通过', None return False, '原记录不存在或状态不是未通过', None
if new_cishu != last.cishu + 1: if new_cishu != last.cishu + 1:
logger.error(f"考核次数不一致: 临时表={new_cishu}, 原记录次数={last.cishu}") logger.error(f"考核次数不一致: 临时表={new_cishu}, 原记录次数={last.cishu}")
return False, '考核次数不一致', None return False, '考核次数不一致', None
logger.info(f"再次申请校验通过原记录ID: {jilu_id}") logger.info(f"再次申请校验通过原记录ID: {jilu_id}")
# 创建或更新审核记录 # 创建或更新审核记录
if reapply and jilu_id: if reapply and jilu_id:
# 更新原记录 # 更新原记录
final_kg_id = last.shenheguan_id final_kg_id = last.shenheguan_id
if shenheguan_id and not last.shenheguan_id: if shenheguan_id and not last.shenheguan_id:
final_kg_id = shenheguan_id final_kg_id = shenheguan_id
final_zhuangtai = 0 if final_kg_id else 3 final_zhuangtai = 0 if final_kg_id else 3
if final_zhuangtai == 3: if final_zhuangtai == 3:
final_kg_id = None final_kg_id = None
ShenheJilu.objects.filter(pk=last.pk).update( ShenheJilu.objects.filter(pk=last.pk).update(
cishu=new_cishu, cishu=new_cishu,
jiaofei_jine=F('jiaofei_jine') + current_fee, jiaofei_jine=F('jiaofei_jine') + current_fee,
dashou_youxi_id=temp_data.game_nick, dashou_youxi_id=temp_data.game_nick,
dashou_beizhu=temp_data.remark, dashou_beizhu=temp_data.remark,
guize_neirong=chenghao.kaohe_guize or '', guize_neirong=chenghao.kaohe_guize or '',
zhuangtai=final_zhuangtai, zhuangtai=final_zhuangtai,
shenheguan_id=final_kg_id, shenheguan_id=final_kg_id,
) )
last.refresh_from_db() last.refresh_from_db()
record = last record = last
# 释放旧考核官 # 释放旧考核官
if last.shenheguan_id != final_kg_id and last.shenheguan_id: if last.shenheguan_id != final_kg_id and last.shenheguan_id:
UserShenheguan.objects.filter(user__yonghuid=last.shenheguan_id).update(shenhe_zhuangtai=0) UserShenheguan.objects.filter(user__UserUID=last.shenheguan_id).update(shenhe_zhuangtai=0)
logger.info(f"释放旧考核官: {last.shenheguan_id}") logger.info(f"释放旧考核官: {last.shenheguan_id}")
logger.info(f"更新审核记录成功: jilu_id={record.jilu_id}, 新次数={new_cishu}") logger.info(f"更新审核记录成功: jilu_id={record.jilu_id}, 新次数={new_cishu}")
else: else:
# 首次申请 # 首次申请
bankuai = chenghao.bankuai bankuai = chenghao.bankuai
rule_text = chenghao.kaohe_guize or '' rule_text = chenghao.kaohe_guize or ''
new_jilu_id = generate_unique_jilu_id() new_jilu_id = generate_unique_jilu_id()
initial_zhuangtai = 0 if shenheguan_id else 3 initial_zhuangtai = 0 if shenheguan_id else 3
record = ShenheJilu.objects.create( record = ShenheJilu.objects.create(
jilu_id=new_jilu_id, jilu_id=new_jilu_id,
shenqingren_id=user.yonghuid, shenqingren_id=user.yonghuid,
zhuangtai=initial_zhuangtai, zhuangtai=initial_zhuangtai,
bankuai=bankuai, bankuai=bankuai,
chenghao=chenghao, chenghao=chenghao,
cishu=new_cishu, cishu=new_cishu,
jiaofei_jine=current_fee, jiaofei_jine=current_fee,
dashou_youxi_id=temp_data.game_nick, dashou_youxi_id=temp_data.game_nick,
dashou_beizhu=temp_data.remark, dashou_beizhu=temp_data.remark,
guize_neirong=rule_text, guize_neirong=rule_text,
shenheguan_id=shenheguan_id if shenheguan_id else None, shenheguan_id=shenheguan_id if shenheguan_id else None,
) )
logger.info(f"创建审核记录成功: jilu_id={new_jilu_id}, 状态={initial_zhuangtai}") logger.info(f"创建审核记录成功: jilu_id={new_jilu_id}, 状态={initial_zhuangtai}")
# 记录费用明细 # 记录费用明细
fee_detail, created = KaoheJiluFeiyong.objects.get_or_create( fee_detail, created = KaoheJiluFeiyong.objects.get_or_create(
jilu=record, jilu=record,
cishu=record.cishu, cishu=record.cishu,
defaults={'jine': current_fee} defaults={'jine': current_fee}
) )
if created: if created:
logger.info(f"创建费用明细成功: 记录ID={record.jilu_id}, 金额={current_fee}") logger.info(f"创建费用明细成功: 记录ID={record.jilu_id}, 金额={current_fee}")
else: else:
logger.warning(f"费用明细已存在: 记录ID={record.jilu_id}, 次数={record.cishu}") logger.warning(f"费用明细已存在: 记录ID={record.jilu_id}, 次数={record.cishu}")
# 更新考核官状态 # 更新考核官状态
if record.zhuangtai == 0 and record.shenheguan_id: if record.zhuangtai == 0 and record.shenheguan_id:
UserShenheguan.objects.filter(user__yonghuid=record.shenheguan_id).update( UserShenheguan.objects.filter(user__UserUID=record.shenheguan_id).update(
shenhe_zongshu=F('shenhe_zongshu') + 1, shenhe_zongshu=F('shenhe_zongshu') + 1,
shenhe_zhuangtai=1 shenhe_zhuangtai=1
) )
logger.info(f"更新考核官状态: {record.shenheguan_id}, 审核总数+1, 状态=忙碌") logger.info(f"更新考核官状态: {record.shenheguan_id}, 审核总数+1, 状态=忙碌")
logger.info(f"从临时表创建审核记录完成: jilu_id={record.jilu_id}") logger.info(f"从临时表创建审核记录完成: jilu_id={record.jilu_id}")
return True, '申请成功', record return True, '申请成功', record
except Chenghao.DoesNotExist: except Chenghao.DoesNotExist:
logger.error(f"标签不存在: tag_id={temp_data.tag_id}") logger.error(f"标签不存在: tag_id={temp_data.tag_id}")
return False, '标签不存在', None return False, '标签不存在', None
except Exception as e: except Exception as e:
logger.error(f"从临时表创建审核记录异常: {str(e)}", exc_info=True) logger.error(f"从临时表创建审核记录异常: {str(e)}", exc_info=True)
return False, '系统异常', None return False, '系统异常', None

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
# Generated by Django 4.2.27 on 2026-06-17 16:31 # Generated by Django 4.2.27 on 2026-06-17 21:18
from django.conf import settings from django.conf import settings
from django.db import migrations, models from django.db import migrations, models
@@ -131,7 +131,7 @@ class Migration(migrations.Migration):
('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')), ('update_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
('dianpu', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='shop.dianpu', verbose_name='关联店铺ID')), ('dianpu', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='shop.dianpu', verbose_name='关联店铺ID')),
('yonghu', models.ForeignKey(db_column='UserUUID', on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, to_field='UserUID', verbose_name='用户ID')), ('yonghu', models.ForeignKey(db_column='UserUUID', on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='用户ID')),
], ],
options={ options={
'verbose_name': '用户店铺绑定关系', 'verbose_name': '用户店铺绑定关系',

View File

@@ -149,7 +149,6 @@ class YonghuDianpuBangding(QModel):
id = models.AutoField(primary_key=True, verbose_name='绑定自增ID') id = models.AutoField(primary_key=True, verbose_name='绑定自增ID')
yonghu = models.ForeignKey( yonghu = models.ForeignKey(
'gvsdsdk.User', 'gvsdsdk.User',
to_field='UserUID',
on_delete=models.CASCADE, on_delete=models.CASCADE,
db_column='UserUUID', db_column='UserUUID',
db_index=True, db_index=True,

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -1,218 +1,218 @@
""" """
排行榜接口 — 基于 houtai 日统计表聚合查询 排行榜接口 — 基于 houtai 日统计表聚合查询
POST /yonghu/phbhqsj POST /yonghu/phbhqsj
""" """
import logging import logging
from datetime import date, timedelta from datetime import date, timedelta
from decimal import Decimal from decimal import Decimal
from django.db.models import Sum from django.db.models import Sum
from rest_framework.permissions import IsAuthenticated from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.views import APIView from rest_framework.views import APIView
from backend.models import ( from backend.models import (
DashouRiTongji, DashouRiTongji,
GuanshiRiTongji, GuanshiRiTongji,
ZuzhangRiTongji, ZuzhangRiTongji,
ShangjiaRiTongji, ShangjiaRiTongji,
) )
from users.models import UserDashou, UserShangjia, UserBoss from users.models import UserDashou, UserShangjia, UserBoss
from gvsdsdk.models import User from gvsdsdk.models import User
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
MAX_RANK = 50 MAX_RANK = 50
RIQI_OPTIONS = frozenset({'今日', '本周', '本月', '总榜', '昨日', '上周', '上月'}) RIQI_OPTIONS = frozenset({'今日', '本周', '本月', '总榜', '昨日', '上周', '上月'})
SHENFEN_OPTIONS = frozenset({'dashou', 'guanshi', 'zuzhang', 'shangjia'}) SHENFEN_OPTIONS = frozenset({'dashou', 'guanshi', 'zuzhang', 'shangjia'})
ROLE_CONFIG = { ROLE_CONFIG = {
'dashou': { 'dashou': {
'model': DashouRiTongji, 'model': DashouRiTongji,
'sort_field': 'chengjiao_zonge', 'sort_field': 'chengjiao_zonge',
'fields': ('jiedan_zongliang', 'chengjiao_zongliang', 'jiedan_zonge', 'chengjiao_zonge'), 'fields': ('jiedan_zongliang', 'chengjiao_zongliang', 'jiedan_zonge', 'chengjiao_zonge'),
'int_fields': frozenset({'jiedan_zongliang', 'chengjiao_zongliang'}), 'int_fields': frozenset({'jiedan_zongliang', 'chengjiao_zongliang'}),
}, },
'guanshi': { 'guanshi': {
'model': GuanshiRiTongji, 'model': GuanshiRiTongji,
'sort_field': 'shouru_zonge', 'sort_field': 'shouru_zonge',
'fields': ('yaoqing_dashou_shu', 'chongzhi_dashou_shu', 'shouru_zonge'), 'fields': ('yaoqing_dashou_shu', 'chongzhi_dashou_shu', 'shouru_zonge'),
'int_fields': frozenset({'yaoqing_dashou_shu', 'chongzhi_dashou_shu'}), 'int_fields': frozenset({'yaoqing_dashou_shu', 'chongzhi_dashou_shu'}),
}, },
'zuzhang': { 'zuzhang': {
'model': ZuzhangRiTongji, 'model': ZuzhangRiTongji,
'sort_field': 'shouru_zonge', 'sort_field': 'shouru_zonge',
'fields': ('yaoqing_guanshi_shu', 'fenyong_jine', 'shouru_zonge'), 'fields': ('yaoqing_guanshi_shu', 'fenyong_jine', 'shouru_zonge'),
'int_fields': frozenset({'yaoqing_guanshi_shu'}), 'int_fields': frozenset({'yaoqing_guanshi_shu'}),
}, },
'shangjia': { 'shangjia': {
'model': ShangjiaRiTongji, 'model': ShangjiaRiTongji,
'sort_field': 'jiesuan_jine', 'sort_field': 'jiesuan_jine',
'fields': ('paifa_dingdan_shu', 'paifa_jine', 'jiesuan_dingdan_shu', 'jiesuan_jine'), 'fields': ('paifa_dingdan_shu', 'paifa_jine', 'jiesuan_dingdan_shu', 'jiesuan_jine'),
'int_fields': frozenset({'paifa_dingdan_shu', 'jiesuan_dingdan_shu'}), 'int_fields': frozenset({'paifa_dingdan_shu', 'jiesuan_dingdan_shu'}),
}, },
} }
def _resolve_date_range(riqi: str): def _resolve_date_range(riqi: str):
"""根据前端 riqi 参数返回 (start_date, end_date) 闭区间。""" """根据前端 riqi 参数返回 (start_date, end_date) 闭区间。"""
today = date.today() today = date.today()
if riqi == '今日': if riqi == '今日':
return today, today return today, today
if riqi == '昨日': if riqi == '昨日':
d = today - timedelta(days=1) d = today - timedelta(days=1)
return d, d return d, d
if riqi == '本周': if riqi == '本周':
monday = today - timedelta(days=today.weekday()) monday = today - timedelta(days=today.weekday())
return monday, today return monday, today
if riqi == '上周': if riqi == '上周':
this_monday = today - timedelta(days=today.weekday()) this_monday = today - timedelta(days=today.weekday())
last_sunday = this_monday - timedelta(days=1) last_sunday = this_monday - timedelta(days=1)
last_monday = last_sunday - timedelta(days=6) last_monday = last_sunday - timedelta(days=6)
return last_monday, last_sunday return last_monday, last_sunday
if riqi == '本月': if riqi == '本月':
return today.replace(day=1), today return today.replace(day=1), today
if riqi == '上月': if riqi == '上月':
first_this_month = today.replace(day=1) first_this_month = today.replace(day=1)
last_day_prev = first_this_month - timedelta(days=1) last_day_prev = first_this_month - timedelta(days=1)
return last_day_prev.replace(day=1), last_day_prev return last_day_prev.replace(day=1), last_day_prev
return None return None
def _fmt_value(val, is_int: bool): def _fmt_value(val, is_int: bool):
if val is None: if val is None:
return 0 if is_int else 0.0 return 0 if is_int else 0.0
if is_int: if is_int:
return int(val) return int(val)
if isinstance(val, Decimal): if isinstance(val, Decimal):
return float(val.quantize(Decimal('0.01'))) return float(val.quantize(Decimal('0.01')))
return float(val) return float(val)
class PhbHqsjView(APIView): class PhbHqsjView(APIView):
""" """
排行榜数据接口 排行榜数据接口
POST /yonghu/phbhqsj POST /yonghu/phbhqsj
请求参数: 请求参数:
shenfen: dashou | guanshi | zuzhang | shangjia shenfen: dashou | guanshi | zuzhang | shangjia
riqi: 今日 | 本周 | 本月 | 总榜 | 昨日 | 上周 | 上月 riqi: 今日 | 本周 | 本月 | 总榜 | 昨日 | 上周 | 上月
响应 data.list[]最多50条已按各身份排序字段降序: 响应 data.list[]最多50条已按各身份排序字段降序:
mingci, yonghuid, nicheng, touxiang + 各身份统计字段 mingci, yonghuid, nicheng, touxiang + 各身份统计字段
""" """
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]
def post(self, request): def post(self, request):
shenfen = (request.data.get('shenfen') or '').strip() shenfen = (request.data.get('shenfen') or '').strip()
riqi = (request.data.get('riqi') or '').strip() riqi = (request.data.get('riqi') or '').strip()
if shenfen not in SHENFEN_OPTIONS: if shenfen not in SHENFEN_OPTIONS:
return Response({ return Response({
'code': 400, 'code': 400,
'msg': '参数错误shenfen 必须为 dashou/guanshi/zuzhang/shangjia', 'msg': '参数错误shenfen 必须为 dashou/guanshi/zuzhang/shangjia',
'data': {'list': []}, 'data': {'list': []},
}) })
if riqi not in RIQI_OPTIONS: if riqi not in RIQI_OPTIONS:
return Response({ return Response({
'code': 400, 'code': 400,
'msg': '参数错误riqi 必须为 今日/本周/本月/总榜/昨日/上周/上月', 'msg': '参数错误riqi 必须为 今日/本周/本月/总榜/昨日/上周/上月',
'data': {'list': []}, 'data': {'list': []},
}) })
try: try:
if riqi == '总榜': if riqi == '总榜':
rows = self._query_rank_rows(shenfen, all_time=True) rows = self._query_rank_rows(shenfen, all_time=True)
else: else:
date_range = _resolve_date_range(riqi) date_range = _resolve_date_range(riqi)
if date_range is None: if date_range is None:
return Response({ return Response({
'code': 400, 'code': 400,
'msg': '参数错误:无效的日期范围', 'msg': '参数错误:无效的日期范围',
'data': {'list': []}, 'data': {'list': []},
}) })
rows = self._query_rank_rows(shenfen, date_range[0], date_range[1]) rows = self._query_rank_rows(shenfen, date_range[0], date_range[1])
nick_map, avatar_map = self._load_user_display(rows, shenfen) nick_map, avatar_map = self._load_user_display(rows, shenfen)
cfg = ROLE_CONFIG[shenfen] cfg = ROLE_CONFIG[shenfen]
int_fields = cfg['int_fields'] int_fields = cfg['int_fields']
result_list = [] result_list = []
for idx, row in enumerate(rows): for idx, row in enumerate(rows):
yonghuid = row['yonghuid'] yonghuid = row['yonghuid']
item = { item = {
'mingci': idx + 1, 'mingci': idx + 1,
'yonghuid': yonghuid, 'yonghuid': yonghuid,
'nicheng': nick_map.get(yonghuid, '用户'), 'nicheng': nick_map.get(yonghuid, '用户'),
'touxiang': avatar_map.get(yonghuid, '') or '', 'touxiang': avatar_map.get(yonghuid, '') or '',
} }
for field in cfg['fields']: for field in cfg['fields']:
item[field] = _fmt_value(row.get(field), field in int_fields) item[field] = _fmt_value(row.get(field), field in int_fields)
result_list.append(item) result_list.append(item)
return Response({ return Response({
'code': 200, 'code': 200,
'msg': '获取成功', 'msg': '获取成功',
'data': {'list': result_list}, 'data': {'list': result_list},
}) })
except Exception as e: except Exception as e:
logger.error('排行榜查询失败 shenfen=%s riqi=%s: %s', shenfen, riqi, e, exc_info=True) logger.error('排行榜查询失败 shenfen=%s riqi=%s: %s', shenfen, riqi, e, exc_info=True)
return Response({ return Response({
'code': 500, 'code': 500,
'msg': '服务器内部错误', 'msg': '服务器内部错误',
'data': {'list': []}, 'data': {'list': []},
}) })
def _query_rank_rows(self, shenfen, start_date=None, end_date=None, all_time=False): def _query_rank_rows(self, shenfen, start_date=None, end_date=None, all_time=False):
cfg = ROLE_CONFIG[shenfen] cfg = ROLE_CONFIG[shenfen]
model = cfg['model'] model = cfg['model']
sort_field = cfg['sort_field'] sort_field = cfg['sort_field']
fields = cfg['fields'] fields = cfg['fields']
annotate_kwargs = {f: Sum(f) for f in fields} annotate_kwargs = {f: Sum(f) for f in fields}
if all_time: if all_time:
rows = ( rows = (
model.objects model.objects
.values('yonghuid') .values('yonghuid')
.annotate(**annotate_kwargs) .annotate(**annotate_kwargs)
.order_by(f'-{sort_field}')[:MAX_RANK] .order_by(f'-{sort_field}')[:MAX_RANK]
) )
return list(rows) return list(rows)
if start_date == end_date: if start_date == end_date:
qs = model.objects.filter(riqi=start_date).order_by(f'-{sort_field}')[:MAX_RANK] qs = model.objects.filter(riqi=start_date).order_by(f'-{sort_field}')[:MAX_RANK]
return [ return [
{'yonghuid': r.yonghuid, **{f: getattr(r, f) for f in fields}} {'yonghuid': r.yonghuid, **{f: getattr(r, f) for f in fields}}
for r in qs for r in qs
] ]
rows = ( rows = (
model.objects model.objects
.filter(riqi__gte=start_date, riqi__lte=end_date) .filter(riqi__gte=start_date, riqi__lte=end_date)
.values('yonghuid') .values('yonghuid')
.annotate(**annotate_kwargs) .annotate(**annotate_kwargs)
.order_by(f'-{sort_field}')[:MAX_RANK] .order_by(f'-{sort_field}')[:MAX_RANK]
) )
return list(rows) return list(rows)
def _load_user_display(self, rows, shenfen): def _load_user_display(self, rows, shenfen):
yonghuids = [r['yonghuid'] for r in rows if r.get('yonghuid')] yonghuids = [r['yonghuid'] for r in rows if r.get('yonghuid')]
if not yonghuids: if not yonghuids:
return {}, {} return {}, {}
users = User.objects.filter(yonghuid__in=yonghuids) users = User.objects.filter(UserUID__in=yonghuids)
avatar_map = {u.yonghuid: u.avatar or '' for u in users} avatar_map = {u.yonghuid: u.avatar or '' for u in users}
nick_map = {} nick_map = {}
if shenfen == 'dashou': if shenfen == 'dashou':
for p in UserDashou.objects.filter(user__yonghuid__in=yonghuids).select_related('user'): for p in UserDashou.objects.filter(user__UserUID__in=yonghuids).select_related('user'):
nick_map[p.user.yonghuid] = p.nicheng or '用户' nick_map[p.user.yonghuid] = p.nicheng or '用户'
elif shenfen == 'shangjia': elif shenfen == 'shangjia':
for p in UserShangjia.objects.filter(user__yonghuid__in=yonghuids).select_related('user'): for p in UserShangjia.objects.filter(user__UserUID__in=yonghuids).select_related('user'):
nick_map[p.user.yonghuid] = p.nicheng or '用户' nick_map[p.user.yonghuid] = p.nicheng or '用户'
else: else:
for b in UserBoss.objects.filter(user__yonghuid__in=yonghuids).select_related('user'): for b in UserBoss.objects.filter(user__UserUID__in=yonghuids).select_related('user'):
nick_map[b.user.yonghuid] = b.nickname or '用户' nick_map[b.user.yonghuid] = b.nickname or '用户'
return nick_map, avatar_map return nick_map, avatar_map

File diff suppressed because it is too large Load Diff

View File

@@ -39,8 +39,8 @@ from rest_framework.throttling import AnonRateThrottle
from rest_framework_simplejwt.tokens import RefreshToken from rest_framework_simplejwt.tokens import RefreshToken
from rest_framework_simplejwt.authentication import JWTAuthentication from rest_framework_simplejwt.authentication import JWTAuthentication
from gvsdsdk.fluent import db, func, FQ from gvsdsdk.fluent import db, func, FQ
from utils.oss_utils import validate_image, upload_to_oss, delete_from_oss from utils.oss_utils import validate_image, upload_to_oss, delete_from_oss
from utils.fadan_utils import check_fadan_qiangdan_eligible from utils.fadan_utils import check_fadan_qiangdan_eligible
from utils.wechat_v3 import verify_wechat_sign, decrypt_callback_ciphertext from utils.wechat_v3 import verify_wechat_sign, decrypt_callback_ciphertext
@@ -343,7 +343,7 @@ class WechatMiniProgramLoginView(APIView):
user_id = timestamp_part + random_part user_id = timestamp_part + random_part
if len(user_id) == 7 and user_id.isdigit(): if len(user_id) == 7 and user_id.isdigit():
if not User.query.filter(yonghuid=user_id).exists(): if not User.query.filter(UserUID=user_id).exists():
return user_id return user_id
raise Exception('生成用户ID失败') raise Exception('生成用户ID失败')
@@ -827,7 +827,7 @@ class HuoQuYaoQingRenView(APIView):
# 3. 查询邀请人主表(头像) # 3. 查询邀请人主表(头像)
try: try:
inviter_main = User.query.get(yonghuid=yaoqingren_id) inviter_main = User.query.get(UserUID=yaoqingren_id)
touxiang = inviter_main.avatar or '' touxiang = inviter_main.avatar or ''
except User.DoesNotExist: except User.DoesNotExist:
return Response({ return Response({
@@ -1081,7 +1081,7 @@ class ShangJiaXinXiView(APIView):
# ------------------- 3. 从 ShangjiaRiTongji 获取今日统计 ------------------- # ------------------- 3. 从 ShangjiaRiTongji 获取今日统计 -------------------
try: try:
today_stat = ShangjiaRiTongji.query.get(yonghuid=yonghuid, riqi=today) today_stat = ShangjiaRiTongji.query.get(UserUID=yonghuid, riqi=today)
jinri_paifa_dingdan = today_stat.paifa_dingdan_shu jinri_paifa_dingdan = today_stat.paifa_dingdan_shu
jinri_paifa_jine = float(today_stat.paifa_jine) jinri_paifa_jine = float(today_stat.paifa_jine)
jinri_tuikuan_dingdan = today_stat.tuikuan_dingdan_shu jinri_tuikuan_dingdan = today_stat.tuikuan_dingdan_shu
@@ -1096,7 +1096,7 @@ class ShangJiaXinXiView(APIView):
# ------------------- 4. 从 ShangjiaRiTongji 获取本月统计 ------------------- # ------------------- 4. 从 ShangjiaRiTongji 获取本月统计 -------------------
month_stats = ShangjiaRiTongji.query.filter( month_stats = ShangjiaRiTongji.query.filter(
yonghuid=yonghuid, UserUID=yonghuid,
riqi__gte=this_month_start, riqi__gte=this_month_start,
riqi__lte=today riqi__lte=today
).aggregate( ).aggregate(
@@ -2161,7 +2161,7 @@ class TixianJiluHuoquViewV2(APIView):
limit = 100 limit = 100
offset = (page - 1) * limit offset = (page - 1) * limit
qs = Tixianjilu.query.filter(yonghuid=yonghuid) qs = Tixianjilu.query.filter(UserUID=yonghuid)
if mode == 2: if mode == 2:
# 自动提现含新审核关联记录zhuangtai>0 时按状态筛选 # 自动提现含新审核关联记录zhuangtai>0 时按状态筛选
if zhuangtai_filter > 0: if zhuangtai_filter > 0:
@@ -3668,7 +3668,7 @@ class AdTongYiChuFa(APIView):
# 11.2 查询打手扩展表(只是验证存在性) # 11.2 查询打手扩展表(只是验证存在性)
try: try:
dashou = UserDashou.query.get(user__yonghuid=chufajilu.dashouid) dashou = UserDashou.query.get(user__UserUID=chufajilu.dashouid)
except UserDashou.DoesNotExist: except UserDashou.DoesNotExist:
return Response( return Response(
{'code': 404, 'message': '被处罚打手不存在', 'data': None}, {'code': 404, 'message': '被处罚打手不存在', 'data': None},
@@ -3698,7 +3698,7 @@ class AdTongYiChuFa(APIView):
# 🔴【新增】11.5 返还打手积分加5分 # 🔴【新增】11.5 返还打手积分加5分
if chufajilu.jifen > 0: if chufajilu.jifen > 0:
try: try:
dashou = UserDashou.query.get(user__yonghuid=chufajilu.dashouid) dashou = UserDashou.query.get(user__UserUID=chufajilu.dashouid)
# 🔴【新增】安全验证必须积分小于等于5分才允许加分 # 🔴【新增】安全验证必须积分小于等于5分才允许加分
if dashou.jifen <= 5: # 判断积分是否小于等于5分 if dashou.jifen <= 5: # 判断积分是否小于等于5分
@@ -3827,7 +3827,7 @@ class AdckyhxqView(APIView):
}, status=status.HTTP_400_BAD_REQUEST) }, status=status.HTTP_400_BAD_REQUEST)
# 查询用户主表 - 使用select_related优化查询 # 查询用户主表 - 使用select_related优化查询
user_main = User.query.filter(yonghuid=uid).first() user_main = User.query.filter(UserUID=uid).first()
if not user_main: if not user_main:
return Response({ return Response({
'code': 404, 'code': 404,
@@ -3856,7 +3856,7 @@ class AdckyhxqView(APIView):
# 根据用户类型查询扩展信息 # 根据用户类型查询扩展信息
if user_type == 1: # 老板 if user_type == 1: # 老板
# 使用select_related预取boss_profile # 使用select_related预取boss_profile
user_main = User.query.filter(yonghuid=uid).select_related('boss_profile').first() user_main = User.query.filter(UserUID=uid).select_related('boss_profile').first()
if user_main.boss_profile: if user_main.boss_profile:
boss_profile = user_main.boss_profile boss_profile = user_main.boss_profile
user_info.update({ user_info.update({
@@ -3869,7 +3869,7 @@ class AdckyhxqView(APIView):
elif user_type == 2: # 打手 elif user_type == 2: # 打手
# 使用select_related预取dashou_profile # 使用select_related预取dashou_profile
user_main = User.query.filter(yonghuid=uid).select_related('dashou_profile').first() user_main = User.query.filter(UserUID=uid).select_related('dashou_profile').first()
if user_main.dashou_profile: if user_main.dashou_profile:
dashou_profile = user_main.dashou_profile dashou_profile = user_main.dashou_profile
@@ -3928,7 +3928,7 @@ class AdckyhxqView(APIView):
elif user_type == 3: # 管事 elif user_type == 3: # 管事
# 使用select_related预取guanshi_profile # 使用select_related预取guanshi_profile
user_main = User.query.filter(yonghuid=uid).select_related('guanshi_profile').first() user_main = User.query.filter(UserUID=uid).select_related('guanshi_profile').first()
if user_main.guanshi_profile: if user_main.guanshi_profile:
guanshi_profile = user_main.guanshi_profile guanshi_profile = user_main.guanshi_profile
user_info.update({ user_info.update({
@@ -3947,7 +3947,7 @@ class AdckyhxqView(APIView):
elif user_type == 4: # 商家 elif user_type == 4: # 商家
# 使用select_related预取shop_profile # 使用select_related预取shop_profile
user_main = User.query.filter(yonghuid=uid).select_related('shop_profile').first() user_main = User.query.filter(UserUID=uid).select_related('shop_profile').first()
if user_main.shop_profile: if user_main.shop_profile:
shop_profile = user_main.shop_profile shop_profile = user_main.shop_profile
user_info.update({ user_info.update({
@@ -4061,7 +4061,7 @@ class AdcjxgView(APIView):
}, status=status.HTTP_400_BAD_REQUEST) }, status=status.HTTP_400_BAD_REQUEST)
# 查询用户主表 # 查询用户主表
user_main = User.query.filter(yonghuid=uid).first() user_main = User.query.filter(UserUID=uid).first()
if not user_main: if not user_main:
return Response({ return Response({
'code': 404, 'code': 404,
@@ -5457,7 +5457,7 @@ class WechatLoginAndDashouRegisterView(APIView):
user_id = timestamp_part + random_part user_id = timestamp_part + random_part
if len(user_id) == 7 and user_id.isdigit(): if len(user_id) == 7 and user_id.isdigit():
if not User.query.filter(yonghuid=user_id).exists(): if not User.query.filter(UserUID=user_id).exists():
return user_id return user_id
raise Exception('生成用户ID失败') raise Exception('生成用户ID失败')
@@ -5730,7 +5730,7 @@ class YonghuTixianShenheXiugaiView(APIView):
try: try:
tixian_record = Tixianjilu.objects.select_for_update().get( tixian_record = Tixianjilu.objects.select_for_update().get(
id=tixian_id, id=tixian_id,
yonghuid=current_yonghuid # 确保只能修改自己的记录 UserUID=current_yonghuid # 确保只能修改自己的记录
) )
except Tixianjilu.DoesNotExist: except Tixianjilu.DoesNotExist:
return Response({ return Response({
@@ -6158,7 +6158,7 @@ class ChufaJiluHuoquView(APIView):
zhengju_mapping = {} zhengju_mapping = {}
if dingdan_ids and shangjia_ids: if dingdan_ids and shangjia_ids:
# 构建Q对象dingdan_id在列表中 AND yonghuid在商家ID列表中 # 构建Q对象dingdan_id在列表中 AND yonghuid在商家ID列表中
zhengju_q = Q(dingdan_id__in=dingdan_ids, yonghuid__in=shangjia_ids) zhengju_q = Q(dingdan_id__in=dingdan_ids, UserUID__in=shangjia_ids)
zhengju_queryset = Chufatupian.query.filter(zhengju_q).values('dingdan_id', 'yonghuid', 'tupian') zhengju_queryset = Chufatupian.query.filter(zhengju_q).values('dingdan_id', 'yonghuid', 'tupian')
for item in zhengju_queryset: for item in zhengju_queryset:
@@ -6353,7 +6353,7 @@ class DashouShensuView(APIView):
# 检查是否已经有申诉图片 # 检查是否已经有申诉图片
existing_shensu_tupian = Chufatupian.query.filter( existing_shensu_tupian = Chufatupian.query.filter(
dingdan_id=chufa_record.dingdan_id, dingdan_id=chufa_record.dingdan_id,
yonghuid=yonghuid UserUID=yonghuid
).exists() ).exists()
if existing_shensu_tupian: if existing_shensu_tupian:
@@ -6600,7 +6600,7 @@ class ShangjiaChufaJiluHuoquView(APIView):
shensu_mapping = {} shensu_mapping = {}
if dingdan_ids and dashou_ids: if dingdan_ids and dashou_ids:
# 构建Q对象dingdan_id在列表中 AND yonghuid在打手ID列表中 # 构建Q对象dingdan_id在列表中 AND yonghuid在打手ID列表中
shensu_q = Q(dingdan_id__in=dingdan_ids, yonghuid__in=dashou_ids) shensu_q = Q(dingdan_id__in=dingdan_ids, UserUID__in=dashou_ids)
shensu_queryset = Chufatupian.query.filter(shensu_q).values('dingdan_id', 'yonghuid', 'tupian') shensu_queryset = Chufatupian.query.filter(shensu_q).values('dingdan_id', 'yonghuid', 'tupian')
for item in shensu_queryset: for item in shensu_queryset:
@@ -7064,7 +7064,7 @@ class KefuGetOrderListView(APIView):
laoban_ids = [o.pingtai_kuozhan.laoban_id for o in orders_qs if hasattr(o, 'pingtai_kuozhan') and o.pingtai_kuozhan.laoban_id] laoban_ids = [o.pingtai_kuozhan.laoban_id for o in orders_qs if hasattr(o, 'pingtai_kuozhan') and o.pingtai_kuozhan.laoban_id]
nickname_map = {} nickname_map = {}
if laoban_ids: if laoban_ids:
users = User.query.filter(yonghuid__in=laoban_ids).select_related('boss_profile').only( users = User.query.filter(UserUID__in=laoban_ids).select_related('boss_profile').only(
'yonghuid', 'boss_profile__nickname' 'yonghuid', 'boss_profile__nickname'
) )
for user in users: for user in users:
@@ -7233,7 +7233,7 @@ class KefuGetShangjiaOrderListView(APIView):
shangjia_ids = [o.shangjia_kuozhan.shangjia_id for o in orders_qs if hasattr(o, 'shangjia_kuozhan') and o.shangjia_kuozhan.shangjia_id] shangjia_ids = [o.shangjia_kuozhan.shangjia_id for o in orders_qs if hasattr(o, 'shangjia_kuozhan') and o.shangjia_kuozhan.shangjia_id]
nickname_map = {} nickname_map = {}
if shangjia_ids: if shangjia_ids:
users = User.query.filter(yonghuid__in=shangjia_ids).select_related('shop_profile').only( users = User.query.filter(UserUID__in=shangjia_ids).select_related('shop_profile').only(
'yonghuid', 'shop_profile__nicheng' 'yonghuid', 'shop_profile__nicheng'
) )
for user in users: for user in users:
@@ -7339,7 +7339,7 @@ class KefuChangeDashouView(APIView):
# 5. 查询新打手 # 5. 查询新打手
try: try:
new_dashou_user = User.query.get(yonghuid=new_dashou_id) new_dashou_user = User.query.get(UserUID=new_dashou_id)
except User.DoesNotExist: except User.DoesNotExist:
return Response({'code': 404, 'msg': '打手不存在'}, status=status.HTTP_404_NOT_FOUND) return Response({'code': 404, 'msg': '打手不存在'}, status=status.HTTP_404_NOT_FOUND)
@@ -7401,7 +7401,7 @@ class KefuChangeDashouView(APIView):
old_dashou_id = order.jiedan_dashou_id old_dashou_id = order.jiedan_dashou_id
if old_dashou_id: if old_dashou_id:
try: try:
old_dashou_user = User.query.get(yonghuid=old_dashou_id) old_dashou_user = User.query.get(UserUID=old_dashou_id)
old_dashou_profile = old_dashou_user.dashou_profile old_dashou_profile = old_dashou_user.dashou_profile
old_dashou_profile.zhuangtai = 1 # 恢复空闲 old_dashou_profile.zhuangtai = 1 # 恢复空闲
old_dashou_profile.tuikuanliang += 1 # 原打手退款总量+1业务逻辑 old_dashou_profile.tuikuanliang += 1 # 原打手退款总量+1业务逻辑
@@ -7577,7 +7577,7 @@ class KefuPlatformRefundView(APIView):
jiedan_dashou_id = order.jiedan_dashou_id jiedan_dashou_id = order.jiedan_dashou_id
if jiedan_dashou_id: if jiedan_dashou_id:
try: try:
dashou_user = User.query.get(yonghuid=jiedan_dashou_id) dashou_user = User.query.get(UserUID=jiedan_dashou_id)
dashou_profile = dashou_user.dashou_profile dashou_profile = dashou_user.dashou_profile
dashou_profile.tuikuanliang += 1 dashou_profile.tuikuanliang += 1
dashou_profile.zhuangtai = 1 # 打手状态设为空闲 dashou_profile.zhuangtai = 1 # 打手状态设为空闲
@@ -7842,7 +7842,7 @@ class KefuRejectRefundView(APIView):
# 7. 给打手结算(返还分成) # 7. 给打手结算(返还分成)
if jiedan_dashou_id: if jiedan_dashou_id:
try: try:
dashou_user = User.query.get(yonghuid=jiedan_dashou_id) dashou_user = User.query.get(UserUID=jiedan_dashou_id)
dashou_profile = dashou_user.dashou_profile dashou_profile = dashou_user.dashou_profile
# 增加打手相关统计数据 # 增加打手相关统计数据
dashou_profile.chengjiaozongliang += 1 dashou_profile.chengjiaozongliang += 1
@@ -7862,7 +7862,7 @@ class KefuRejectRefundView(APIView):
shangjia_kuozhan = order.shangjia_kuozhan shangjia_kuozhan = order.shangjia_kuozhan
shangjia_id = shangjia_kuozhan.shangjia_id shangjia_id = shangjia_kuozhan.shangjia_id
if shangjia_id: if shangjia_id:
shangjia_user = User.query.get(yonghuid=shangjia_id) shangjia_user = User.query.get(UserUID=shangjia_id)
shangjia_profile = shangjia_user.shop_profile shangjia_profile = shangjia_user.shop_profile
shangjia_profile.chengjiao += 1 shangjia_profile.chengjiao += 1
shangjia_profile.save() shangjia_profile.save()
@@ -8019,7 +8019,7 @@ class KefuMerchantRefundView(APIView):
# 更新打手 # 更新打手
if jiedan_dashou_id: if jiedan_dashou_id:
try: try:
dashou_user = User.query.get(yonghuid=jiedan_dashou_id) dashou_user = User.query.get(UserUID=jiedan_dashou_id)
dashou_profile = dashou_user.dashou_profile dashou_profile = dashou_user.dashou_profile
dashou_profile.tuikuanliang += 1 dashou_profile.tuikuanliang += 1
dashou_profile.zhuangtai = 1 dashou_profile.zhuangtai = 1
@@ -8029,7 +8029,7 @@ class KefuMerchantRefundView(APIView):
# 更新商家 # 更新商家
try: try:
shangjia_user = User.query.get(yonghuid=shangjia_id) shangjia_user = User.query.get(UserUID=shangjia_id)
shangjia_profile = shangjia_user.shop_profile shangjia_profile = shangjia_user.shop_profile
shangjia_profile.tuikuan += 1 shangjia_profile.tuikuan += 1
shangjia_profile.yue += jine shangjia_profile.yue += jine
@@ -8156,7 +8156,7 @@ class KefuRejectSettlementView(APIView):
# 5.3 更新打手扩展表 # 5.3 更新打手扩展表
try: try:
dashou_user = User.query.get(yonghuid=jiedan_dashou_id) dashou_user = User.query.get(UserUID=jiedan_dashou_id)
dashou_profile = dashou_user.dashou_profile dashou_profile = dashou_user.dashou_profile
dashou_profile.zhuangtai = 1 # 打手状态设为空闲 dashou_profile.zhuangtai = 1 # 打手状态设为空闲
dashou_profile.tuikuanliang += 1 # 退款订单总量+1 dashou_profile.tuikuanliang += 1 # 退款订单总量+1
@@ -8240,7 +8240,7 @@ class KefuTransferHallView(APIView):
if order.jiedan_dashou_id: if order.jiedan_dashou_id:
UserDashou.query.filter(user__yonghuid=order.jiedan_dashou_id).update(zhuangtai=1) UserDashou.query.filter(user__UserUID=order.jiedan_dashou_id).update(zhuangtai=1)
else: else:
pass pass
@@ -8617,7 +8617,7 @@ class KefuUpdateDashouView(APIView):
# 3. 查询打手是否存在 # 3. 查询打手是否存在
try: try:
dashou_user = User.query.get(yonghuid=dashou_id, user_type='dashou') dashou_user = User.query.get(UserUID=dashou_id, user_type='dashou')
dashou_profile = dashou_user.dashou_profile dashou_profile = dashou_user.dashou_profile
except User.DoesNotExist: except User.DoesNotExist:
return Response({'code': 404, 'msg': '打手不存在'}) return Response({'code': 404, 'msg': '打手不存在'})
@@ -9189,11 +9189,11 @@ class KefuPunishmentDetailView(APIView):
shensu_images = [] shensu_images = []
try: try:
# 商家证据图片:上传者为请求人 (qingqiuid) # 商家证据图片:上传者为请求人 (qingqiuid)
zhengju_qs = Chufatupian.query.filter(dingdan_id=dingdan_id, yonghuid=record.qingqiuid) zhengju_qs = Chufatupian.query.filter(dingdan_id=dingdan_id, UserUID=record.qingqiuid)
zhengju_images = [item.tupian for item in zhengju_qs if item.tupian] zhengju_images = [item.tupian for item in zhengju_qs if item.tupian]
# 打手申诉图片:上传者为打手 (dashouid) # 打手申诉图片:上传者为打手 (dashouid)
shensu_qs = Chufatupian.query.filter(dingdan_id=dingdan_id, yonghuid=record.dashouid) shensu_qs = Chufatupian.query.filter(dingdan_id=dingdan_id, UserUID=record.dashouid)
shensu_images = [item.tupian for item in shensu_qs if item.tupian] shensu_images = [item.tupian for item in shensu_qs if item.tupian]
except Exception as e: except Exception as e:
logger.error(f"查询图片失败: {e}") logger.error(f"查询图片失败: {e}")
@@ -9294,7 +9294,7 @@ class KefuPunishmentActionView(APIView):
# 可选验证打手存在 # 可选验证打手存在
if record.dashouid: if record.dashouid:
try: try:
dashou = UserDashou.query.get(user__yonghuid=record.dashouid) dashou = UserDashou.query.get(user__UserUID=record.dashouid)
except UserDashou.DoesNotExist: except UserDashou.DoesNotExist:
return Response({'code': 400, 'msg': '被处罚打手不存在'}, status=status.HTTP_400_BAD_REQUEST) return Response({'code': 400, 'msg': '被处罚打手不存在'}, status=status.HTTP_400_BAD_REQUEST)
@@ -9315,7 +9315,7 @@ class KefuPunishmentActionView(APIView):
# 返还积分 # 返还积分
if record.jifen > 0 and record.dashouid: if record.jifen > 0 and record.dashouid:
try: try:
dashou = UserDashou.query.get(user__yonghuid=record.dashouid) dashou = UserDashou.query.get(user__UserUID=record.dashouid)
if dashou.jifen <= 1000: # 安全限制 if dashou.jifen <= 1000: # 安全限制
dashou.jifen += record.jifen dashou.jifen += record.jifen
dashou.save() dashou.save()
@@ -9410,7 +9410,7 @@ class KefuForceCompleteView(APIView):
# 5. 给打手结算 # 5. 给打手结算
try: try:
dashou_user = User.query.get(yonghuid=dashou_id) dashou_user = User.query.get(UserUID=dashou_id)
dashou_profile = dashou_user.dashou_profile dashou_profile = dashou_user.dashou_profile
# 原子更新(避免并发重复加) # 原子更新(避免并发重复加)
dashou_profile.chengjiaozongliang = F('chengjiaozongliang') + 1 dashou_profile.chengjiaozongliang = F('chengjiaozongliang') + 1
@@ -9431,7 +9431,7 @@ class KefuForceCompleteView(APIView):
# 通过 DingdanShangjia 获取商家ID # 通过 DingdanShangjia 获取商家ID
shangjia_ext = order.shangjia_kuozhan # 假设 related_name='shangjia_kuozhan' shangjia_ext = order.shangjia_kuozhan # 假设 related_name='shangjia_kuozhan'
if shangjia_ext and shangjia_ext.shangjia_id: if shangjia_ext and shangjia_ext.shangjia_id:
shangjia_user = User.query.get(yonghuid=shangjia_ext.shangjia_id) shangjia_user = User.query.get(UserUID=shangjia_ext.shangjia_id)
shangjia_profile = shangjia_user.shop_profile shangjia_profile = shangjia_user.shop_profile
shangjia_profile.chengjiao = F('chengjiao') + 1 shangjia_profile.chengjiao = F('chengjiao') + 1
shangjia_profile.save(update_fields=['chengjiao']) shangjia_profile.save(update_fields=['chengjiao'])
@@ -9874,7 +9874,7 @@ class KefuWithdrawDetailView(APIView):
# 查询用户主表 # 查询用户主表
try: try:
user = User.query.get(yonghuid=record.yonghuid) user = User.query.get(UserUID=record.yonghuid)
except User.DoesNotExist: except User.DoesNotExist:
user = None user = None
@@ -10047,7 +10047,7 @@ class KefuWithdrawActionView(APIView):
raise ValueError(f'提现记录{tixian_id}:审核记录非审核中状态') raise ValueError(f'提现记录{tixian_id}:审核记录非审核中状态')
try: try:
user = User.objects.select_for_update().get(yonghuid=req_yonghuid) user = User.objects.select_for_update().get(UserUID=req_yonghuid)
except User.DoesNotExist: except User.DoesNotExist:
raise ValueError(f'用户{req_yonghuid}不存在') raise ValueError(f'用户{req_yonghuid}不存在')
@@ -10100,7 +10100,7 @@ class KefuWithdrawActionView(APIView):
raise ValueError(f'提现记录{tixian_id}:自动打款请走自动流程') raise ValueError(f'提现记录{tixian_id}:自动打款请走自动流程')
try: try:
user = User.query.get(yonghuid=tixian.yonghuid) user = User.query.get(UserUID=tixian.yonghuid)
except User.DoesNotExist: except User.DoesNotExist:
raise ValueError(f'用户{tixian.yonghuid}不存在') raise ValueError(f'用户{tixian.yonghuid}不存在')
@@ -10247,7 +10247,7 @@ class KefuPunishView(APIView):
# 5. 查询打手 # 5. 查询打手
try: try:
dashou_user = User.query.get(yonghuid=dashou_id) dashou_user = User.query.get(UserUID=dashou_id)
dashou = dashou_user.dashou_profile dashou = dashou_user.dashou_profile
except User.DoesNotExist: except User.DoesNotExist:
return Response({'code': 404, 'msg': '打手用户不存在'}, status=status.HTTP_404_NOT_FOUND) return Response({'code': 404, 'msg': '打手用户不存在'}, status=status.HTTP_404_NOT_FOUND)
@@ -10329,7 +10329,7 @@ class AdKftjView(APIView):
timestamp = str(int(time.time()))[-5:] timestamp = str(int(time.time()))[-5:]
rand = str(random.randint(0, 99)).zfill(2) rand = str(random.randint(0, 99)).zfill(2)
uid = timestamp + rand uid = timestamp + rand
if len(uid) == 7 and not User.query.filter(yonghuid=uid).exists(): if len(uid) == 7 and not User.query.filter(UserUID=uid).exists():
return uid return uid
raise Exception('无法生成唯一用户ID') raise Exception('无法生成唯一用户ID')
@@ -10645,7 +10645,7 @@ class WechatLoginAndGuanshiRegisterView(APIView):
random_part = str(random.randint(0, 99)).zfill(2) random_part = str(random.randint(0, 99)).zfill(2)
user_id = timestamp_part + random_part user_id = timestamp_part + random_part
if len(user_id) == 7 and user_id.isdigit(): if len(user_id) == 7 and user_id.isdigit():
if not User.query.filter(yonghuid=user_id).exists(): if not User.query.filter(UserUID=user_id).exists():
return user_id return user_id
raise Exception('生成用户ID失败') raise Exception('生成用户ID失败')
@@ -11931,7 +11931,7 @@ class FaKuanPayPollView(APIView):
if not dingdanid: if not dingdanid:
return Response({'code': 400, 'message': '订单ID不能为空'}) return Response({'code': 400, 'message': '订单ID不能为空'})
order = Czjilu.query.get(dingdan_id=dingdanid, yonghuid=request.user.yonghuid) order = Czjilu.query.get(dingdan_id=dingdanid, UserUID=request.user.yonghuid)
if order.zhuangtai == 3: if order.zhuangtai == 3:
return Response({'code': 200, 'message': '支付成功'}) return Response({'code': 200, 'message': '支付成功'})
else: else:
@@ -11954,7 +11954,7 @@ class FaKuanPayFailView(APIView):
if not dingdanid: if not dingdanid:
return Response({'code': 400, 'message': '订单ID不能为空'}) return Response({'code': 400, 'message': '订单ID不能为空'})
order = Czjilu.query.get(dingdan_id=dingdanid, yonghuid=request.user.yonghuid) order = Czjilu.query.get(dingdan_id=dingdanid, UserUID=request.user.yonghuid)
if order.zhuangtai == 9: # 未支付 if order.zhuangtai == 9: # 未支付
order.delete() order.delete()
logger.info(f"用户{request.user.yonghuid}删除未支付订单: {dingdanid}") logger.info(f"用户{request.user.yonghuid}删除未支付订单: {dingdanid}")
@@ -12004,7 +12004,7 @@ class KaohePayView(APIView):
# 1. 检查是否有未支付的考核订单 # 1. 检查是否有未支付的考核订单
"""unpaid_order = Czjilu.query.filter( """unpaid_order = Czjilu.query.filter(
yonghuid=user.yonghuid, UserUID=user.yonghuid,
leixing=5, leixing=5,
zhuangtai=9 zhuangtai=9
).exists() ).exists()
@@ -12366,10 +12366,10 @@ class KaohePayCallbackView(View):
# 从临时表获取业务参数并创建审核记录 # 从临时表获取业务参数并创建审核记录
try: try:
temp = KaohePayTemp.query.get(dingdan_id=out_trade_no, yonghuid=order.yonghuid) temp = KaohePayTemp.query.get(dingdan_id=out_trade_no, UserUID=order.yonghuid)
logger.info(f"找到临时表记录: {out_trade_no}, 用户ID: {order.yonghuid}") logger.info(f"找到临时表记录: {out_trade_no}, 用户ID: {order.yonghuid}")
user = User.query.get(yonghuid=order.yonghuid) user = User.query.get(UserUID=order.yonghuid)
logger.info(f"获取用户信息成功: {user.yonghuid}") logger.info(f"获取用户信息成功: {user.yonghuid}")
success, msg, record = create_shenhe_jilu_from_temp(user, temp) success, msg, record = create_shenhe_jilu_from_temp(user, temp)
@@ -12486,7 +12486,7 @@ class KaohePayPollView(APIView):
if not dingdanid: if not dingdanid:
return Response({'code': 400, 'message': '订单ID不能为空'}) return Response({'code': 400, 'message': '订单ID不能为空'})
try: try:
order = Czjilu.query.get(dingdan_id=dingdanid, yonghuid=request.user.yonghuid, leixing=5) order = Czjilu.query.get(dingdan_id=dingdanid, UserUID=request.user.yonghuid, leixing=5)
if order.zhuangtai == 3: if order.zhuangtai == 3:
return Response({'code': 200, 'message': '支付成功'}) return Response({'code': 200, 'message': '支付成功'})
return Response({'code': 400, 'message': '订单尚未支付'}) return Response({'code': 400, 'message': '订单尚未支付'})
@@ -12503,7 +12503,7 @@ class KaohePayFailView(APIView):
if not dingdanid: if not dingdanid:
return Response({'code': 400, 'message': '订单ID不能为空'}) return Response({'code': 400, 'message': '订单ID不能为空'})
try: try:
order = Czjilu.query.get(dingdan_id=dingdanid, yonghuid=request.user.yonghuid, leixing=5) order = Czjilu.query.get(dingdan_id=dingdanid, UserUID=request.user.yonghuid, leixing=5)
if order.zhuangtai == 9: if order.zhuangtai == 9:
order.delete() order.delete()
return Response({'code': 200, 'message': '订单已删除'}) return Response({'code': 200, 'message': '订单已删除'})
@@ -12676,7 +12676,7 @@ class GuanshiContactView(APIView):
# 4. 根据邀请人用户ID查询用户主表 # 4. 根据邀请人用户ID查询用户主表
try: try:
inviter_user = User.query.get(yonghuid=inviter_yonghuid) inviter_user = User.query.get(UserUID=inviter_yonghuid)
except User.DoesNotExist: except User.DoesNotExist:
logger.error(f"邀请人用户不存在: yonghuid={inviter_yonghuid}") logger.error(f"邀请人用户不存在: yonghuid={inviter_yonghuid}")
return Response({ return Response({
@@ -12855,7 +12855,7 @@ class TixianQueRenAutoView(APIView):
try: try:
auto_record = TixianAutoRecord.objects.select_for_update().get( auto_record = TixianAutoRecord.objects.select_for_update().get(
tixian_id=tixian_id, tixian_id=tixian_id,
yonghuid=user_main.yonghuid, UserUID=user_main.yonghuid,
) )
except TixianAutoRecord.DoesNotExist: except TixianAutoRecord.DoesNotExist:
return Response({'code': 4, 'msg': '提现记录不存在'}, status=status.HTTP_404_NOT_FOUND) return Response({'code': 4, 'msg': '提现记录不存在'}, status=status.HTTP_404_NOT_FOUND)

View File

@@ -1,198 +1,198 @@
# utils/chat_utils.py # utils/chat_utils.py
import json import json
import logging import logging
import requests import requests
from django.conf import settings from django.conf import settings
from orders.models import Dingdan, DingdanPingtai, DingdanShangjia from orders.models import Dingdan, DingdanPingtai, DingdanShangjia
from users.models import UserDashou, UserBoss, UserShangjia from users.models import UserDashou, UserBoss, UserShangjia
from gvsdsdk.models import User from gvsdsdk.models import User
logger = logging.getLogger('chat_utils') logger = logging.getLogger('chat_utils')
# ========== 辅助配置获取 ========== # ========== 辅助配置获取 ==========
def _get_self_goeasy_appkey(): def _get_self_goeasy_appkey():
return getattr(settings, 'GOEASY_APPKEY', '') return getattr(settings, 'GOEASY_APPKEY', '')
def _get_self_goeasy_secret(): def _get_self_goeasy_secret():
return getattr(settings, 'GOEASY_SECRET', '') return getattr(settings, 'GOEASY_SECRET', '')
# ========== 头像拼接 ========== # ========== 头像拼接 ==========
def _full_local_avatar(relative_url): def _full_local_avatar(relative_url):
if not relative_url: if not relative_url:
return '' return ''
if relative_url.startswith('http'): if relative_url.startswith('http'):
return relative_url return relative_url
return relative_url return relative_url
# ========== GoEasy 订阅 ========== # ========== GoEasy 订阅 ==========
def _subscribe_users_to_group(user_ids, group_ids, appkey=None, secret=None): def _subscribe_users_to_group(user_ids, group_ids, appkey=None, secret=None):
if not appkey: if not appkey:
appkey = _get_self_goeasy_appkey() appkey = _get_self_goeasy_appkey()
if not secret: if not secret:
secret = _get_self_goeasy_secret() secret = _get_self_goeasy_secret()
if not appkey: if not appkey:
logger.error("GoEasy AppKey 未配置") logger.error("GoEasy AppKey 未配置")
return False return False
url = 'https://rest-hangzhou.goeasy.io/v2/im/subscribe-groups' url = 'https://rest-hangzhou.goeasy.io/v2/im/subscribe-groups'
body = {"appkey": appkey, "userIds": user_ids, "groupIds": group_ids} body = {"appkey": appkey, "userIds": user_ids, "groupIds": group_ids}
headers = {"Content-Type": "application/json"} headers = {"Content-Type": "application/json"}
if secret: if secret:
headers["Authorization"] = f"Bearer {secret}" headers["Authorization"] = f"Bearer {secret}"
try: try:
resp = requests.post(url, headers=headers, json=body, timeout=10) resp = requests.post(url, headers=headers, json=body, timeout=10)
if resp.status_code == 200: if resp.status_code == 200:
return True return True
logger.error(f"订阅失败: {resp.status_code} {resp.text}") logger.error(f"订阅失败: {resp.status_code} {resp.text}")
return False return False
except Exception as e: except Exception as e:
logger.error(f"订阅异常: {e}", exc_info=True) logger.error(f"订阅异常: {e}", exc_info=True)
return False return False
# ========== 发送群消息(完整参数) ========== # ========== 发送群消息(完整参数) ==========
def _send_group_message(appkey, secret, group_id, sender_id, sender_name, sender_avatar, def _send_group_message(appkey, secret, group_id, sender_id, sender_name, sender_avatar,
message_text, custom_payload=None, group_name=None, order_id=None): message_text, custom_payload=None, group_name=None, order_id=None):
if not appkey: if not appkey:
appkey = _get_self_goeasy_appkey() appkey = _get_self_goeasy_appkey()
if not secret: if not secret:
secret = _get_self_goeasy_secret() secret = _get_self_goeasy_secret()
if not appkey: if not appkey:
logger.error("GoEasy AppKey 未配置") logger.error("GoEasy AppKey 未配置")
return False return False
url = 'https://rest-hangzhou.goeasy.io/v2/im/message' url = 'https://rest-hangzhou.goeasy.io/v2/im/message'
# to.data 包含群聊展示信息及业务字段 # to.data 包含群聊展示信息及业务字段
to_data = { to_data = {
"name": group_name or group_id, "name": group_name or group_id,
"avatar": sender_avatar or "", "avatar": sender_avatar or "",
} }
if order_id: if order_id:
to_data["orderId"] = order_id to_data["orderId"] = order_id
payload_str = custom_payload.get("text", message_text) if custom_payload else message_text payload_str = custom_payload.get("text", message_text) if custom_payload else message_text
request_body = { request_body = {
"appkey": appkey, "appkey": appkey,
"senderId": sender_id, "senderId": sender_id,
"senderData": {"avatar": sender_avatar, "name": sender_name}, "senderData": {"avatar": sender_avatar, "name": sender_name},
"to": { "to": {
"type": "group", "type": "group",
"id": group_id, "id": group_id,
"data": to_data "data": to_data
}, },
"type": "text", "type": "text",
"payload": payload_str "payload": payload_str
} }
headers = {"Content-Type": "application/json"} headers = {"Content-Type": "application/json"}
if secret: if secret:
headers["Authorization"] = f"Bearer {secret}" headers["Authorization"] = f"Bearer {secret}"
try: try:
resp = requests.post(url, headers=headers, json=request_body, timeout=10) resp = requests.post(url, headers=headers, json=request_body, timeout=10)
if resp.status_code == 200: if resp.status_code == 200:
return True return True
logger.error(f"群聊消息发送失败,状态码:{resp.status_code},响应:{resp.text}") logger.error(f"群聊消息发送失败,状态码:{resp.status_code},响应:{resp.text}")
return False return False
except Exception as e: except Exception as e:
logger.error(f"发送群聊消息异常: {e}", exc_info=True) logger.error(f"发送群聊消息异常: {e}", exc_info=True)
return False return False
# ========== 核心入口 ========== # ========== 核心入口 ==========
def establish_order_chat(dingdan_id): def establish_order_chat(dingdan_id):
try: try:
order = Dingdan.objects.select_related('pingtai_kuozhan', 'shangjia_kuozhan').get(dingdan_id=dingdan_id) order = Dingdan.objects.select_related('pingtai_kuozhan', 'shangjia_kuozhan').get(dingdan_id=dingdan_id)
except Dingdan.DoesNotExist: except Dingdan.DoesNotExist:
logger.error(f"订单 {dingdan_id} 不存在") logger.error(f"订单 {dingdan_id} 不存在")
return False return False
dashou_uid = order.jiedan_dashou_id dashou_uid = order.jiedan_dashou_id
dashou_goeasy_id = f"Ds{dashou_uid}" dashou_goeasy_id = f"Ds{dashou_uid}"
dashou_nickname = f'打手{dashou_uid[:6]}' dashou_nickname = f'打手{dashou_uid[:6]}'
dashou_avatar_relative = '' dashou_avatar_relative = ''
try: try:
dashou_user = User.objects.get(yonghuid=dashou_uid) dashou_user = User.objects.get(UserUID=dashou_uid)
dashou_avatar_relative = dashou_user.avatar or '' dashou_avatar_relative = dashou_user.avatar or ''
dashou_profile = UserDashou.objects.get(user=dashou_user) dashou_profile = UserDashou.objects.get(user=dashou_user)
if dashou_profile.nicheng: if dashou_profile.nicheng:
dashou_nickname = dashou_profile.nicheng dashou_nickname = dashou_profile.nicheng
except Exception as e: except Exception as e:
logger.warning(f"获取打手信息失败: {e}") logger.warning(f"获取打手信息失败: {e}")
dashou_avatar = _full_local_avatar(dashou_avatar_relative) dashou_avatar = _full_local_avatar(dashou_avatar_relative)
appkey = _get_self_goeasy_appkey() appkey = _get_self_goeasy_appkey()
secret = _get_self_goeasy_secret() secret = _get_self_goeasy_secret()
if not appkey: if not appkey:
logger.error("GoEasy AppKey 未配置") logger.error("GoEasy AppKey 未配置")
return False return False
# 本地订单处理 # 本地订单处理
return _handle_local_order(order, dashou_goeasy_id, dashou_nickname, dashou_avatar, appkey, secret) return _handle_local_order(order, dashou_goeasy_id, dashou_nickname, dashou_avatar, appkey, secret)
# ========== 普通订单 / 我方派单 ========== # ========== 普通订单 / 我方派单 ==========
def _handle_local_order(order, dashou_goeasy_id, dashou_name, dashou_avatar, appkey, secret): def _handle_local_order(order, dashou_goeasy_id, dashou_name, dashou_avatar, appkey, secret):
group_id = f"group_{order.dingdan_id}" group_id = f"group_{order.dingdan_id}"
group_name = (order.jieshao[:20] + '') if order.jieshao and len(order.jieshao) > 20 else (order.jieshao or f"订单{order.dingdan_id}") group_name = (order.jieshao[:20] + '') if order.jieshao and len(order.jieshao) > 20 else (order.jieshao or f"订单{order.dingdan_id}")
group_avatar = _full_local_avatar(order.tupian) if order.tupian else _full_local_avatar('') group_avatar = _full_local_avatar(order.tupian) if order.tupian else _full_local_avatar('')
partner_goeasy_id, partner_name, partner_avatar = _get_local_partner_info(order) partner_goeasy_id, partner_name, partner_avatar = _get_local_partner_info(order)
if not partner_goeasy_id: if not partner_goeasy_id:
return False return False
# 订阅双方 # 订阅双方
if not _subscribe_users_to_group([dashou_goeasy_id, partner_goeasy_id], [group_id], appkey, secret): if not _subscribe_users_to_group([dashou_goeasy_id, partner_goeasy_id], [group_id], appkey, secret):
return False return False
# 1. 打手发送初始化消息 # 1. 打手发送初始化消息
init_msg_text = f"订单已接单,内容:{order.jieshao},备注:{order.beizhu}游戏ID{order.nicheng}" init_msg_text = f"订单已接单,内容:{order.jieshao},备注:{order.beizhu}游戏ID{order.nicheng}"
success1 = _send_group_message( success1 = _send_group_message(
appkey, secret, group_id, dashou_goeasy_id, dashou_name, group_avatar, appkey, secret, group_id, dashou_goeasy_id, dashou_name, group_avatar,
init_msg_text, None, group_name=group_name, order_id=order.dingdan_id init_msg_text, None, group_name=group_name, order_id=order.dingdan_id
) )
# 2. 【新增】派单方也发一条消息,确保他也能看到群聊 # 2. 【新增】派单方也发一条消息,确保他也能看到群聊
partner_msg = f"订单已确认,请开始服务。" partner_msg = f"订单已确认,请开始服务。"
success2 = _send_group_message( success2 = _send_group_message(
appkey, secret, group_id, partner_goeasy_id, partner_name, partner_avatar, appkey, secret, group_id, partner_goeasy_id, partner_name, partner_avatar,
partner_msg, None, group_name=group_name, order_id=order.dingdan_id partner_msg, None, group_name=group_name, order_id=order.dingdan_id
) )
return success1 and success2 return success1 and success2
def _get_local_partner_info(order): def _get_local_partner_info(order):
"""本地订单下单方:老板或商家""" """本地订单下单方:老板或商家"""
if order.fadan_pingtai == 1: # 老板 if order.fadan_pingtai == 1: # 老板
try: try:
ext = order.pingtai_kuozhan ext = order.pingtai_kuozhan
laoban_id = ext.laoban_id laoban_id = ext.laoban_id
avatar_full = _full_local_avatar('') avatar_full = _full_local_avatar('')
nickname = f'老板{laoban_id[:6]}' nickname = f'老板{laoban_id[:6]}'
try: try:
boss_user = User.objects.get(yonghuid=laoban_id) boss_user = User.objects.get(UserUID=laoban_id)
avatar_full = _full_local_avatar(boss_user.avatar or '') avatar_full = _full_local_avatar(boss_user.avatar or '')
boss_profile = UserBoss.objects.get(user=boss_user) boss_profile = UserBoss.objects.get(user=boss_user)
if boss_profile.nickname: if boss_profile.nickname:
nickname = boss_profile.nickname nickname = boss_profile.nickname
except Exception: except Exception:
pass pass
return f"Boss{laoban_id}", nickname, avatar_full return f"Boss{laoban_id}", nickname, avatar_full
except Exception as e: except Exception as e:
logger.error(f"获取老板信息失败: {e}") logger.error(f"获取老板信息失败: {e}")
return None, None, None return None, None, None
elif order.fadan_pingtai == 2: # 商家 elif order.fadan_pingtai == 2: # 商家
try: try:
ext = order.shangjia_kuozhan ext = order.shangjia_kuozhan
shangjia_id = ext.shangjia_id shangjia_id = ext.shangjia_id
nickname = ext.sjnicheng or f'商家{shangjia_id[:6]}' nickname = ext.sjnicheng or f'商家{shangjia_id[:6]}'
avatar_full = _full_local_avatar('') avatar_full = _full_local_avatar('')
try: try:
sj_user = User.objects.get(yonghuid=shangjia_id) sj_user = User.objects.get(UserUID=shangjia_id)
avatar_full = _full_local_avatar(sj_user.avatar or '') avatar_full = _full_local_avatar(sj_user.avatar or '')
except Exception: except Exception:
pass pass
return f"Sj{shangjia_id}", nickname, avatar_full return f"Sj{shangjia_id}", nickname, avatar_full
except Exception as e: except Exception as e:
logger.error(f"获取商家信息失败: {e}") logger.error(f"获取商家信息失败: {e}")
return None, None, None return None, None, None
else: else:
if order.user1_id: if order.user1_id:
return order.user1_id, "用户", _full_local_avatar('') return order.user1_id, "用户", _full_local_avatar('')
return None, None, None return None, None, None

49
verify_fixes.py Normal file
View File

@@ -0,0 +1,49 @@
#!/usr/bin/env python3
"""验证所有兼容性修复"""
import os; os.environ['DJANGO_SETTINGS_MODULE']='a_long_dianjing.settings'
import django; django.setup()
from gvsdsdk.models import User
from rest_framework_simplejwt.tokens import RefreshToken
from rest_framework_simplejwt.authentication import JWTAuthentication
from unittest.mock import Mock
u = User.objects.filter(UserName__isnull=False).first()
print(f'测试用户: {u.UserName}, UserUID: {u.UserUID}')
# 1. JWT 认证
refresh = RefreshToken.for_user(u)
access = refresh.access_token
print('1. JWT Token 生成成功')
auth = JWTAuthentication()
request = Mock()
request.META = {'HTTP_AUTHORIZATION': f'Bearer {access}'}
request._request = request
validated_user, _ = auth.authenticate(request)
print(f' JWT 验证成功: {validated_user.UserName}')
# 2. yonghuid 兼容属性
print(f'2. yonghuid: {u.yonghuid}')
# 3. dashou_profile
dp = u.dashou_profile
print(f'3. dashou_profile: {dp}')
# 4. shoujihao_renzheng
print(f'4. shoujihao_renzheng: {u.shoujihao_renzheng}')
# 5. user_type
print(f'5. user_type: {u.user_type}')
# 6. User.query.get(UserUID=...)
u2 = User.query.get(UserUID=u.UserUID)
print(f'6. User.query.get(UserUID=...) OK: {u2.UserName}')
# 7. user.id
print(f'7. user.id: {u.id}, bool: {bool(u.id)}')
# 8. has_role
print(f'8. has_role(dashou): {u.has_role("dashou")}')
print()
print('所有兼容性测试通过!')