# 标准库 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(yonghuid=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__yonghuid=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.yonghuid, 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.yonghuid, 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__yonghuid=last_record.shenheguan_id ).update(shenhe_zhuangtai=0) else: # 首次申请 max_cishu = ShenheJilu.objects.filter( shenqingren_id=user.yonghuid, 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.yonghuid, 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__yonghuid=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.yonghuid}, 订单={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.yonghuid} 已拥有标签 {chenghao.mingcheng}") return False, '您已拥有该标签,无需重复考核', None # 检查是否有进行中的审核 if ShenheJilu.objects.filter( shenqingren_id=user.yonghuid, chenghao=chenghao, zhuangtai__in=[0, 3] ).exists(): logger.warning(f"用户 {user.yonghuid} 有未完成的考核申请") 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.yonghuid, 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__yonghuid=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.yonghuid, 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__yonghuid=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