Files
Django/rank/utils.py

407 lines
16 KiB
Python
Raw Blame History

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