修复了一些

This commit is contained in:
2026-06-18 18:02:45 +08:00
parent e67bc17fa2
commit 53049d1588
20 changed files with 3671 additions and 2541 deletions

View File

@@ -50,8 +50,8 @@ from shop.models import YonghuDianpuBangding, ShangpinLeixingDianpu, DianpuShang
from products.models import ShangpinLeixing, ShangpinZhuanqu, Shangpin, Huiyuan
from orders.models import (
Dingdan, DingdanPingtai, Dashoutupian, Tuikuanjilu,
OrderDashouHistory, Fadan
Order, PlatformOrderExt, PlayerDeliveryImage, RefundRecord,
OrderPlayerHistory, Penalty
)
logger = logging.getLogger(__name__)
@@ -2124,8 +2124,8 @@ class ShopOrderStatisticsView(APIView):
# 3. 获取本店铺所有订单的主键ID列表通过平台扩展表
order_pks = list(
DingdanPingtai.query.filter(dianpu_id=shop_id)
.values_list('dingdan_id', flat=True) # 这里取的是订单主表的主键id
PlatformOrderExt.query.filter(dianpu_id=shop_id)
.values_list('Order_id', flat=True) # 这里取的是订单主表的主键id
)
total_orders = 0
@@ -2134,15 +2134,15 @@ class ShopOrderStatisticsView(APIView):
if order_pks:
# 4. 用主键列表进行聚合统计,按商品类型和订单状态分组
aggregation = (
Dingdan.objects
Order.objects
.filter(id__in=order_pks) # 修正点使用id__in而不是dingdan_id__in
.values('leixing_id', 'zhuangtai')
.values('ProductTypeID', 'Status')
.annotate(cnt=Count('id'))
)
for row in aggregation:
lid = row['leixing_id'] # 商品类型ID
st = row['zhuangtai'] # 订单状态码
lid = row['ProductTypeID'] # 商品类型ID
st = row['Status'] # 订单状态码
cnt = row['cnt']
# 转为字符串键,方便前端展示
@@ -2217,12 +2217,12 @@ def _fetch_images(order, oss_domain):
punishment_info = {}
# 仅当订单有接单打手ID时才查询打手图片
if order.jiedan_dashou_id:
if order.PlayerID:
# 从打手图片表中查询该订单、该打手的所有图片记录
image_urls = Dashoutupian.query.filter(
dingdan_id=order.dingdan_id, # 订单ID匹配
dashou=order.jiedan_dashou_id # 接单打手ID匹配
).values_list('tupian', flat=True) # 只取图片URL字段
image_urls = PlayerDeliveryImage.query.filter(
OrderID=order.OrderID, # 订单ID匹配
PlayerID=order.PlayerID # 接单打手ID匹配
).values_list('ImageURL', flat=True) # 只取图片URL字段
# 遍历所有图片路径
for img_path in image_urls:
@@ -2258,7 +2258,7 @@ def _batch_images(orders, oss_domain):
with ThreadPoolExecutor(max_workers=10) as executor:
# 建立 future 到订单ID的映射
future_to_oid = {
executor.submit(_fetch_images, order, oss_domain): order.dingdan_id
executor.submit(_fetch_images, order, oss_domain): order.OrderID
for order in orders
}
# 等待所有任务完成
@@ -2353,9 +2353,9 @@ class ShopOrderManageView(APIView):
# ------------------------------------------------------------
# 从 DingdanPingtai 中过滤出属于当前店铺的订单扩展记录并提取订单主表ID
order_ids = list(
DingdanPingtai.query.filter(
PlatformOrderExt.query.filter(
dianpu_id=shop_id # 店铺ID匹配
).values_list('dingdan_id', flat=True) # 只取订单ID字段
).values_list('Order_id', flat=True) # 只取订单ID字段
)
# 统计变量
@@ -2367,11 +2367,11 @@ class ShopOrderManageView(APIView):
# ------------------------------------------------------------
if order_ids:
# 使用 Django 聚合查询:按 leixing_id商品类型和 zhuangtai订单状态分组计数
aggregation = Dingdan.query.filter(
dingdan_id__in=order_ids # 从该店铺的订单中查询
aggregation = Order.query.filter(
OrderID__in=order_ids # 从该店铺的订单中查询
).values(
'leixing_id', # 按类型ID分组
'zhuangtai' # 按状态分组
'ProductTypeID', # 按类型ID分组
'Status' # 按状态分组
).annotate(
cnt=Count('id') # 统计每个分组的记录数
)
@@ -2379,8 +2379,8 @@ class ShopOrderManageView(APIView):
# 遍历每个聚合结果,累加到对应的类型和全局计数中
for row in aggregation:
# 提取分组字段
lid = row['leixing_id'] # 商品类型ID
st = row['zhuangtai'] # 订单状态码
lid = row['ProductTypeID'] # 商品类型ID
st = row['Status'] # 订单状态码
cnt = row['cnt'] # 该分组下的订单数量
# 累加到全局总数
@@ -2434,25 +2434,25 @@ class ShopOrderManageView(APIView):
page_size = request.data.get('page_size', 20)
# 基础查询:从平台扩展表关联订单主表,并按创建时间倒序
qs = DingdanPingtai.query.filter(
qs = PlatformOrderExt.query.filter(
dianpu_id=shop_id
).select_related('dingdan').order_by('-dingdan__create_time')
).select_related('Order').order_by('-Order__CreateTime')
# 应用筛选条件
if leixing_id is not None:
qs = qs.filter(dingdan__leixing_id=leixing_id)
qs = qs.filter(Order__ProductTypeID=leixing_id)
if zhuangtai is not None:
qs = qs.filter(dingdan__zhuangtai=zhuangtai)
qs = qs.filter(Order__Status=zhuangtai)
if dingdan_id_key:
qs = qs.filter(dingdan__dingdan_id__icontains=dingdan_id_key)
qs = qs.filter(Order__OrderID__icontains=dingdan_id_key)
if jiedan_dashou_id_key:
qs = qs.filter(dingdan__jiedan_dashou_id=jiedan_dashou_id_key)
qs = qs.filter(Order__PlayerID=jiedan_dashou_id_key)
if nicheng_key:
qs = qs.filter(dingdan__nicheng__icontains=nicheng_key)
qs = qs.filter(Order__Nickname__icontains=nicheng_key)
if laoban_id_key:
qs = qs.filter(laoban_id=laoban_id_key)
qs = qs.filter(BossID=laoban_id_key)
if jieshao_key:
qs = qs.filter(dingdan__jieshao__icontains=jieshao_key)
qs = qs.filter(Order__Description__icontains=jieshao_key)
# 分页
paginator = Paginator(qs, page_size)
@@ -2462,7 +2462,7 @@ class ShopOrderManageView(APIView):
page_obj = paginator.page(1)
# 获取当前页的所有订单和扩展对象
orders_with_ext = [(item.dingdan, item) for item in page_obj]
orders_with_ext = [(item.Order, item) for item in page_obj]
# 提取订单对象列表,用于并发获取图片
order_objs = [order for order, _ in orders_with_ext]
oss_domain = get_oss_domain()
@@ -2471,27 +2471,27 @@ class ShopOrderManageView(APIView):
# 构建返回数据
list_data = []
for order, ext in orders_with_ext:
imgs, is_pun, _ = img_map.get(order.dingdan_id, ([], False, {}))
imgs, is_pun, _ = img_map.get(order.OrderID, ([], False, {}))
list_data.append({
'dingdan_id': order.dingdan_id,
'zhuangtai': order.zhuangtai,
'jine': float(order.jine) if order.jine else 0.00,
'dashou_fencheng': float(order.dashou_fencheng) if order.dashou_fencheng else 0.00,
'jiedan_dashou_id': order.jiedan_dashou_id or '',
'dingdan_id': order.OrderID,
'zhuangtai': order.Status,
'jine': float(order.Amount) if order.Amount else 0.00,
'dashou_fencheng': float(order.PlayerCommission) if order.PlayerCommission else 0.00,
'jiedan_dashou_id': order.PlayerID or '',
'dashou_liuyan': order.dashou_liuyan or '',
'zhiding_id': order.zhiding_id or '',
'shangpin_id': order.shangpin_id or '',
'tupian': order.tupian or '',
'jieshao': order.jieshao or '',
'beizhu': order.beizhu or '',
'nicheng': order.nicheng or '',
'leixing_id': order.leixing_id,
'create_time': order.create_time.strftime('%Y-%m-%d %H:%M:%S') if order.create_time else '',
'update_time': order.update_time.strftime('%Y-%m-%d %H:%M:%S') if order.update_time else '',
'shangpin_id': order.ProductID or '',
'tupian': order.ImageURL or '',
'jieshao': order.Description or '',
'beizhu': order.Remark or '',
'nicheng': order.Nickname or '',
'leixing_id': order.ProductTypeID,
'create_time': order.CreateTime.strftime('%Y-%m-%d %H:%M:%S') if order.CreateTime else '',
'update_time': order.UpdateTime.strftime('%Y-%m-%d %H:%M:%S') if order.UpdateTime else '',
'pingtai_kuozhan': {
'laoban_id': ext.laoban_id or '',
'laoban_pingjia': ext.laoban_pingjia or '',
'dianpu_shouyi': float(ext.dianpu_shouyi) if ext.dianpu_shouyi else 0.00,
'laoban_id': ext.BossID or '',
'laoban_pingjia': ext.BossReview or '',
'dianpu_shouyi': float(ext.ShopIncome) if ext.ShopIncome else 0.00,
},
'dashou_images': imgs,
'is_punished': is_pun,
@@ -2554,19 +2554,19 @@ class ShopRefundView(APIView):
# 3. 查询订单,必须属于本店铺(通过扩展表关联)
try:
# 通过扩展表确认归属,并 select_related 获取订单主表
pingtai_ext = DingdanPingtai.query.select_related('dingdan').get(
pingtai_ext = PlatformOrderExt.query.select_related('Order').get(
dianpu_id=shop_id,
dingdan__dingdan_id=dingdan_id
Order__OrderID=dingdan_id
)
order = pingtai_ext.dingdan
except DingdanPingtai.DoesNotExist:
order = pingtai_ext.Order
except PlatformOrderExt.DoesNotExist:
logger.warning(f"订单 {dingdan_id} 不属于店铺 {shop_id} 或不存在")
return Response({'code': 404, 'msg': '订单不存在或不属于本店铺'})
# 4. 订单状态校验(只有这些状态可退款)
allowed_statuses = [1, 7, 2, 8, 4]
if order.zhuangtai not in allowed_statuses:
logger.warning(f"订单状态不允许退款: {order.zhuangtai}")
if order.Status not in allowed_statuses:
logger.warning(f"订单状态不允许退款: {order.Status}")
return Response({'code': 400, 'msg': '订单状态不允许退款'})
# 5. 全部视为平台订单(我方派单),调用微信退款
@@ -2575,14 +2575,14 @@ class ShopRefundView(APIView):
return Response({'code': 400, 'msg': refund_result['msg']})
# 6. 事务内更新订单、打手、记录、统计
dashou_id = order.jiedan_dashou_id
dashou_id = order.PlayerID
try:
with transaction.atomic():
# 更新订单状态为已退款
order.zhuangtai = 5
order.clkf = str(shop_id) # 处理人记录为店铺ID
order.Status = 5
order.AssignedCS = str(shop_id) # 处理人记录为店铺ID
if reason:
order.tkly = reason
order.RefundReason = reason
order.save()
# 更新打手统计(退款量+1状态置为空闲
@@ -2603,7 +2603,7 @@ class ShopRefundView(APIView):
try:
update_dashou_daily_by_action(
yonghuid=dashou_id,
amount=order.dashou_fencheng or Decimal('0.00'),
amount=order.PlayerCommission or Decimal('0.00'),
action=3 # 3 表示退款
)
except Exception as e:
@@ -2611,25 +2611,25 @@ class ShopRefundView(APIView):
# 更新平台支出记录
try:
update_daily_payout(order.jine)
update_daily_payout(order.Amount)
except Exception as e:
logger.error(f"更新每日支出失败: {e}")
# ========== 新增:商品和店铺每日统计 ==========
try:
# 商品每日统计只要有商品ID就执行
if order.shangpin_id:
if order.ProductID:
# 从扩展表获取已计算好的收益值(下单时已存储)
pingtai_shouyi = Decimal('0.00')
dianpu_shouyi = Decimal('0.00')
if hasattr(order, 'pingtai_kuozhan'):
pingtai_shouyi = order.pingtai_kuozhan.pingtai_shouyi or Decimal('0.00')
dianpu_shouyi = order.pingtai_kuozhan.dianpu_shouyi or Decimal('0.00')
pingtai_shouyi = order.pingtai_kuozhan.PlatformIncome or Decimal('0.00')
dianpu_shouyi = order.pingtai_kuozhan.ShopIncome or Decimal('0.00')
update_shangpin_daily_stat(
shangpin_id=order.shangpin_id,
shangpin_id=order.ProductID,
caozuo_leixing=3, # 3 = 退款
dingdan_jiage=order.jine,
dingdan_jiage=order.Amount,
pingtai_shouyi=pingtai_shouyi,
dianpu_zongshouyi=dianpu_shouyi
)
@@ -2640,11 +2640,11 @@ class ShopRefundView(APIView):
if hasattr(order, 'pingtai_kuozhan'):
dianpu_id = order.pingtai_kuozhan.dianpu_id
if dianpu_id:
dianpu_shouyi = order.pingtai_kuozhan.dianpu_shouyi or Decimal('0.00')
dianpu_shouyi = order.pingtai_kuozhan.ShopIncome or Decimal('0.00')
update_dianpu_daily_stat(
dianpu_id=dianpu_id,
caozuo_leixing=3, # 3 = 退款
dingdan_jiage=order.jine,
dingdan_jiage=order.Amount,
dianpu_shouyi=dianpu_shouyi
)
logger.info(f"店铺统计更新完成店铺ID: {dianpu_id}")
@@ -2672,8 +2672,8 @@ class ShopRefundView(APIView):
if not all([appid, mch_id, key, cert_path, key_path]):
return {'code': 500, 'msg': '微信支付配置不完整'}
out_refund_no = self._generate_refund_no(order.dingdan_id)
total_fee = int(float(order.jine or 0) * 100)
out_refund_no = self._generate_refund_no(order.OrderID)
total_fee = int(float(order.Amount or 0) * 100)
refund_fee = total_fee
params = {
@@ -2685,10 +2685,10 @@ class ShopRefundView(APIView):
'refund_fee': refund_fee,
'refund_desc': '店铺退款',
}
if order.wechat_transaction_id:
params['transaction_id'] = order.wechat_transaction_id
if order.WechatTransactionID:
params['transaction_id'] = order.WechatTransactionID
else:
params['out_trade_no'] = order.dingdan_id
params['out_trade_no'] = order.OrderID
# 签名
sorted_keys = sorted(params.keys())
@@ -2718,26 +2718,26 @@ class ShopRefundView(APIView):
def _update_refund_record(self, order, dashou_id, chuli_id, reason):
"""更新退款记录表"""
try:
refund_record, created = Tuikuanjilu.query.get_or_create(
dingdan_id=order.dingdan_id,
refund_record, created = RefundRecord.query.get_or_create(
OrderID=order.OrderID,
defaults={
'dashouid': dashou_id or '',
'qingqiuid': '',
'chuliid': chuli_id,
'liyou': reason or '店铺退款',
'sqzhuangtai': 1,
'jine': order.jine or 0,
'dashou_fencheng': order.dashou_fencheng or 0,
'jieshao': order.jieshao or '',
'beizhu': '店铺退款',
'nicheng': order.nicheng or '',
'PlayerID': dashou_id or '',
'ApplicantID': '',
'ProcessorID': chuli_id,
'Reason': reason or '店铺退款',
'ApplyStatus': 1,
'Amount': order.Amount or 0,
'PlayerCommission': order.PlayerCommission or 0,
'Description': order.Description or '',
'Remark': '店铺退款',
'Nickname': order.Nickname or '',
}
)
if not created:
refund_record.sqzhuangtai = 1
refund_record.chuliid = chuli_id
refund_record.ApplyStatus = 1
refund_record.ProcessorID = chuli_id
if reason:
refund_record.liyou = reason
refund_record.Reason = reason
refund_record.save()
except Exception as e:
logger.error(f"更新退款记录异常: {e}")
@@ -2801,28 +2801,28 @@ class ShopForceCompleteView(APIView):
# ========== 3. 查询订单并验证归属 ==========
try:
# 通过平台扩展表确认订单属于本店铺
pingtai_ext = DingdanPingtai.query.select_related('dingdan').get(
pingtai_ext = PlatformOrderExt.query.select_related('Order').get(
dianpu_id=shop_id,
dingdan__dingdan_id=dingdan_id
Order__OrderID=dingdan_id
)
order = pingtai_ext.dingdan
except DingdanPingtai.DoesNotExist:
order = pingtai_ext.Order
except PlatformOrderExt.DoesNotExist:
logger.warning(f"订单 {dingdan_id} 不属于店铺 {shop_id} 或不存在")
return Response({'code': 404, 'msg': '订单不存在或不属于本店铺'})
# ========== 4. 校验订单状态必须为 8结算中 ==========
if order.zhuangtai != 8:
logger.warning(f"订单 {dingdan_id} 当前状态为 {order.zhuangtai},不是结算中")
return Response({'code': 400, 'msg': f'订单状态不是结算中,当前状态: {order.zhuangtai}'})
if order.Status != 8:
logger.warning(f"订单 {dingdan_id} 当前状态为 {order.Status},不是结算中")
return Response({'code': 400, 'msg': f'订单状态不是结算中,当前状态: {order.Status}'})
dashou_id = order.jiedan_dashou_id
dashou_fencheng = order.dashou_fencheng or Decimal('0.00')
jine = order.jine or Decimal('0.00')
dashou_id = order.PlayerID
dashou_fencheng = order.PlayerCommission or Decimal('0.00')
jine = order.Amount or Decimal('0.00')
try:
with transaction.atomic():
# 锁定订单行,防止并发
order = Dingdan.objects.select_for_update().get(dingdan_id=dingdan_id)
order = Order.objects.select_for_update().get(OrderID=dingdan_id)
if not dashou_id:
return Response({'code': 400, 'msg': '订单无接单打手,无法结算'})
@@ -2844,8 +2844,8 @@ class ShopForceCompleteView(APIView):
logger.warning(f"本地订单结算:打手 {dashou_id} 不存在,跳过打手更新")
# ---------- 更新订单状态 ----------
order.zhuangtai = 3
order.clkf = str(shop_id)
order.Status = 3
order.AssignedCS = str(shop_id)
order.save()
# ---------- 打手每日统计(成交) ----------
@@ -2859,21 +2859,21 @@ class ShopForceCompleteView(APIView):
logger.error(f"打手每日统计更新失败: {e}")
# ---------- 店铺收益统计(结算) ----------
if pingtai_ext.dianpu_shouyi:
if pingtai_ext.ShopIncome:
try:
# 商品每日统计只要有商品ID就执行
if order.shangpin_id:
if order.ProductID:
# 从扩展表获取已计算好的收益值(下单时已存储)
pingtai_shouyi = Decimal('0.00')
dianpu_shouyi = Decimal('0.00')
if hasattr(order, 'pingtai_kuozhan'):
pingtai_shouyi = order.pingtai_kuozhan.pingtai_shouyi or Decimal('0.00')
dianpu_shouyi = order.pingtai_kuozhan.dianpu_shouyi or Decimal('0.00')
pingtai_shouyi = order.pingtai_kuozhan.PlatformIncome or Decimal('0.00')
dianpu_shouyi = order.pingtai_kuozhan.ShopIncome or Decimal('0.00')
update_shangpin_daily_stat(
shangpin_id=order.shangpin_id,
shangpin_id=order.ProductID,
caozuo_leixing=2, # 3 = 退款
dingdan_jiage=order.jine,
dingdan_jiage=order.Amount,
pingtai_shouyi=pingtai_shouyi,
dianpu_zongshouyi=dianpu_shouyi
)
@@ -2884,7 +2884,7 @@ class ShopForceCompleteView(APIView):
dianpu_id=shop_id,
caozuo_leixing=2, # 结算操作
dingdan_jiage=jine,
dianpu_shouyi=pingtai_ext.dianpu_shouyi,
dianpu_shouyi=pingtai_ext.ShopIncome,
)
except Exception as e:
logger.error(f"店铺每日统计更新失败: {e}")
@@ -2894,7 +2894,7 @@ class ShopForceCompleteView(APIView):
return Response({'code': 200, 'msg': '强制结单成功'})
except Dingdan.DoesNotExist:
except Order.DoesNotExist:
logger.warning(f"订单不存在: {dingdan_id}")
return Response({'code': 404, 'msg': '订单不存在'})
except Exception as e:
@@ -2950,36 +2950,36 @@ class ShopTransferHallView(APIView):
# ---------- 3. 验证订单归属 ----------
try:
pingtai_ext = DingdanPingtai.query.select_related('dingdan').get(
pingtai_ext = PlatformOrderExt.query.select_related('Order').get(
dianpu_id=shop_id,
dingdan__dingdan_id=dingdan_id
Order__OrderID=dingdan_id
)
order = pingtai_ext.dingdan
except DingdanPingtai.DoesNotExist:
order = pingtai_ext.Order
except PlatformOrderExt.DoesNotExist:
logger.warning(f"订单 {dingdan_id} 不属于店铺 {shop_id} 或不存在")
return Response({'code': 404, 'msg': '订单不存在或不属于本店铺'})
# ---------- 4. 状态校验 ----------
if order.zhuangtai not in [2, 8, 4]:
return Response({'code': 400, 'msg': f'订单状态不允许转移大厅,当前状态: {order.zhuangtai}'})
if order.Status not in [2, 8, 4]:
return Response({'code': 400, 'msg': f'订单状态不允许转移大厅,当前状态: {order.Status}'})
# ---------- 5. 提取关键字段 ----------
current_dashou_id = order.jiedan_dashou_id
current_dashou_id = order.PlayerID
zhiding_id = order.zhiding_id
dashou_fencheng = order.dashou_fencheng or 0 # 用于退款统计
dashou_fencheng = order.PlayerCommission or 0 # 用于退款统计
try:
with transaction.atomic():
# 锁定订单行
order = Dingdan.objects.select_for_update().get(dingdan_id=dingdan_id)
order = Order.objects.select_for_update().get(OrderID=dingdan_id)
# ---------- 6. 记录打手历史(原接口保留逻辑) ----------
if current_dashou_id:
last_history = OrderDashouHistory.query.filter(
last_history = OrderPlayerHistory.query.filter(
dingdan_id=dingdan_id
).order_by('-times').first()
next_times = (last_history.times + 1) if last_history else 1
OrderDashouHistory.query.create(
OrderPlayerHistory.query.create(
dingdan_id=dingdan_id,
dashou_id=current_dashou_id,
times=next_times,
@@ -3017,7 +3017,7 @@ class ShopTransferHallView(APIView):
logger.info(f"转移大厅成功,订单 {dingdan_id}")
return Response({'code': 200, 'msg': '转移大厅成功'})
except Dingdan.DoesNotExist:
except Order.DoesNotExist:
return Response({'code': 404, 'msg': '订单不存在'})
except Exception as e:
logger.error(f"转移大厅接口异常: {str(e)}", exc_info=True)
@@ -3085,7 +3085,7 @@ class ShopFineApplyView(APIView):
return Response({'code': 404, 'msg': '订单不存在或不属于本店铺'})
# ---------- 4. 获取打手ID ----------
dashou_id = order.jiedan_dashou_id
dashou_id = order.PlayerID
if not dashou_id:
return Response({'code': 400, 'msg': '该订单无接单打手,无法罚款'})