Files
Django/orders/tasks.py

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