407 lines
16 KiB
Python
407 lines
16 KiB
Python
# 标准库
|
||
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 users.business_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 |