826 lines
34 KiB
Python
826 lines
34 KiB
Python
"""orders.views.boss_orders - auto-generated by split script."""
|
||
# ==================== 标准库 ====================
|
||
import hmac
|
||
import os
|
||
import json
|
||
import time
|
||
import random
|
||
import string
|
||
import traceback
|
||
import threading
|
||
import requests
|
||
import hashlib
|
||
import xml.etree.ElementTree as ET
|
||
import xmltodict
|
||
import logging
|
||
from decimal import Decimal
|
||
|
||
from django.conf import settings
|
||
from django.db import models, transaction
|
||
from gvsdsdk.fluent import db, func, FQ
|
||
from django.db.models import F, Q, OuterRef, Subquery
|
||
from django.core.cache import cache
|
||
from django.core.exceptions import ObjectDoesNotExist
|
||
from django.http import HttpResponse
|
||
from django.utils import timezone
|
||
|
||
from rest_framework.views import APIView
|
||
from rest_framework.response import Response
|
||
from rest_framework import permissions, status
|
||
from rest_framework.permissions import AllowAny, IsAuthenticated
|
||
from rest_framework.parsers import JSONParser
|
||
from rest_framework.throttling import AnonRateThrottle
|
||
from rest_framework_simplejwt.authentication import JWTAuthentication
|
||
|
||
from tencentcloud.common import credential
|
||
from tencentcloud.common.profile.client_profile import ClientProfile
|
||
from tencentcloud.common.profile.http_profile import HttpProfile
|
||
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
|
||
from tencentcloud.sts.v20180813 import sts_client, models
|
||
|
||
from utils.weixin_broadcast import WeixinBroadcastSender
|
||
from utils.money import yuan_to_fen
|
||
from utils.chat_utils import (
|
||
_send_group_message, _subscribe_users_to_group, establish_order_chat,
|
||
prepare_order_group_chat, resolve_pair_group_id,
|
||
parse_pair_from_group_id, resolve_pair_from_order, check_pair_chat_permission,
|
||
query_pair_orders, order_to_chat_dict,
|
||
)
|
||
from utils.fadan_utils import check_fadan_qiangdan_eligible
|
||
|
||
from orders.utils import (
|
||
calc_shangjia_order_fencheng,
|
||
update_daily_payout,
|
||
settle_shangjia_order_guanshi_fenhong
|
||
)
|
||
from shop.utils import calculate_pingtai_and_dianpu_shouyi, validate_shangpin_and_dianpu, update_dianpu_daily_stat
|
||
from products.utils import update_shangpin_daily_stat
|
||
from backend.utils import update_shangjia_daily, update_dashou_daily_by_action, pick_leixing_id, datetime_aliases, fmt_datetime
|
||
from rank.services import record_dashou_biaoxian
|
||
from rank.utils import check_dashou_biaoqian_required
|
||
|
||
from orders.notice_tasks import dingdan_guangbo
|
||
|
||
from ..models import (
|
||
Order, MerchantOrderExt, PlatformOrderExt, PlayerDeliveryImage,
|
||
PenaltyRecord, PenaltyEvidenceImage, Penalty, PenaltyAppealImage, PenaltyBonus, PenaltyBonusRate,
|
||
CommissionRate, PlayerRating, RefundRecord,
|
||
)
|
||
from jituan.services.club_config import get_commission_rate, get_commission_rate_object
|
||
from jituan.services.club_context import resolve_club_id_from_request
|
||
from jituan.services.club_user import get_payment_openid
|
||
from jituan.services.club_penalty import resolve_penalty_club_id, resolve_penalty_record_club_id
|
||
from users.fadan_fenhong_utils import lock_penalty_bonus
|
||
from users.fadan_fenhong_utils import lock_penalty_bonus
|
||
from products.models import Shangpin, ShangpinLeixing, Huiyuangoumai
|
||
from users.models import UserDashou, UserShangjia, UserBoss
|
||
from users.business_models import User
|
||
from rank.models import DashouBiaoxian, Chenghao, DingdanBiaoqian, YonghuChenghao
|
||
from config.models import (
|
||
ShangjiaLianjie
|
||
)
|
||
|
||
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
class DingdanHuoquView(APIView):
|
||
"""订单获取接口"""
|
||
permission_classes = [IsAuthenticated]
|
||
|
||
def post(self, request):
|
||
# 获取当前登录用户
|
||
try:
|
||
current_user = request.user
|
||
yonghuid = current_user.UserUID
|
||
except Exception as e:
|
||
return Response({
|
||
'code': 1,
|
||
'msg': '用户认证失败',
|
||
'data': None
|
||
})
|
||
|
||
# 获取前端参数
|
||
try:
|
||
data = request.data
|
||
zhuangtai_list = data.get('zhuangtai_list', [])
|
||
page = int(data.get('page', 1))
|
||
page_size = int(data.get('page_size', 10))
|
||
except Exception as e:
|
||
return Response({
|
||
'code': 2,
|
||
'msg': '参数格式错误',
|
||
'data': None
|
||
})
|
||
|
||
# 参数验证
|
||
if not isinstance(zhuangtai_list, list) or len(zhuangtai_list) == 0:
|
||
return Response({
|
||
'code': 3,
|
||
'msg': '状态列表不能为空',
|
||
'data': None
|
||
})
|
||
|
||
if page < 1:
|
||
page = 1
|
||
if page_size <= 0:
|
||
page_size = 10
|
||
|
||
try:
|
||
# 查询扩展表,获取用户的所有订单ID
|
||
pingtai_orders = PlatformOrderExt.query.filter(BossID=yonghuid)
|
||
pingtai_order_ids = list(pingtai_orders.values_list('Order__OrderID', flat=True))
|
||
|
||
if not pingtai_order_ids:
|
||
return Response({
|
||
'code': 0,
|
||
'msg': '成功',
|
||
'data': {
|
||
'list': [],
|
||
'has_more': False,
|
||
'total': 0
|
||
}
|
||
})
|
||
|
||
# 查询主表
|
||
status_query = Q()
|
||
if zhuangtai_list != [1, 2, 3, 4, 5, 6, 7, 8]:
|
||
status_query = Q(Status__in=zhuangtai_list)
|
||
|
||
query = Q(OrderID__in=pingtai_order_ids) & status_query
|
||
orders = Order.query.filter(query).order_by('-CreateTime')
|
||
#total_orders = orders.count()
|
||
|
||
# 手动分页逻辑
|
||
start_index = (page - 1) * page_size
|
||
end_index = start_index + page_size
|
||
|
||
# 获取当前页的数据
|
||
current_page_orders = orders[start_index:end_index]
|
||
|
||
# 构建返回数据
|
||
order_list = []
|
||
for order in current_page_orders:
|
||
order_data = {
|
||
'dingdanId': order.OrderID,
|
||
'zhuangtai': order.Status,
|
||
'jine': float(order.Amount) if order.Amount else 0.0,
|
||
'tupian': order.ImageURL or '',
|
||
'jieshao': order.Description or '',
|
||
'beizhu': order.Remark or '',
|
||
'nicheng': order.Nickname or '',
|
||
'chuangjianshijian': fmt_datetime(order.CreateTime),
|
||
'create_time': fmt_datetime(order.CreateTime),
|
||
}
|
||
order_list.append(order_data)
|
||
|
||
|
||
# 判断是否还有更多数据
|
||
current_page_count = len(current_page_orders)
|
||
has_more = current_page_count == page_size
|
||
|
||
return Response({
|
||
'code': 0,
|
||
'msg': '成功',
|
||
'data': {
|
||
'list': order_list,
|
||
'has_more': has_more,
|
||
#'total': total_orders
|
||
}
|
||
})
|
||
|
||
except Exception as e:
|
||
return Response({
|
||
'code': 4,
|
||
'msg': '服务器内部错误',
|
||
'data': None
|
||
})
|
||
|
||
|
||
|
||
|
||
|
||
class DingdanXiangqingView(APIView):
|
||
"""订单详情接口"""
|
||
permission_classes = [IsAuthenticated]
|
||
|
||
def post(self, request):
|
||
# 获取当前登录用户
|
||
try:
|
||
current_user = request.user
|
||
yonghuid = current_user.UserUID
|
||
except Exception as e:
|
||
return Response({
|
||
'code': 1,
|
||
'msg': '用户认证失败',
|
||
'data': None
|
||
})
|
||
|
||
# 获取前端参数
|
||
try:
|
||
data = request.data
|
||
dingdan_id = data.get('dingdanId', '')
|
||
except Exception as e:
|
||
return Response({
|
||
'code': 2,
|
||
'msg': '参数格式错误',
|
||
'data': None
|
||
})
|
||
|
||
# 参数验证
|
||
if not dingdan_id:
|
||
return Response({
|
||
'code': 3,
|
||
'msg': '订单ID不能为空',
|
||
'data': None
|
||
})
|
||
|
||
try:
|
||
# 1. 验证订单是否属于当前用户
|
||
# 查询平台订单扩展表,检查laoban_id是否等于当前用户
|
||
pingtai_kuozhan = PlatformOrderExt.query.filter(
|
||
BossID=yonghuid,
|
||
Order__OrderID=dingdan_id
|
||
).first()
|
||
|
||
if not pingtai_kuozhan:
|
||
# 如果不是平台订单,检查商家订单
|
||
shangjia_kuozhan = MerchantOrderExt.query.filter(
|
||
MerchantID=yonghuid,
|
||
Order__OrderID=dingdan_id
|
||
).first()
|
||
|
||
if not shangjia_kuozhan:
|
||
return Response({
|
||
'code': 4,
|
||
'msg': '订单不存在或无权限查看',
|
||
'data': None
|
||
})
|
||
|
||
# 2. 查询订单主表
|
||
dingdan = Order.query.filter(OrderID=dingdan_id).first()
|
||
|
||
if not dingdan:
|
||
return Response({
|
||
'code': 5,
|
||
'msg': '订单不存在',
|
||
'data': None
|
||
})
|
||
|
||
# 3. 获取订单信息
|
||
zhuangtai = dingdan.Status or 0
|
||
zhiding_id = dingdan.AssignedID or ''
|
||
jiedan_dashou_id = dingdan.PlayerID or ''
|
||
dashou_liuyan = dingdan.PlayerRemark or ''
|
||
|
||
# 4. 查询打手交付图片
|
||
dashoutupian_records = PlayerDeliveryImage.query.filter(
|
||
OrderID=dingdan_id
|
||
).order_by('CreateTime')[:9] # 最多取9条
|
||
|
||
dashoujiaofu_list = []
|
||
for record in dashoutupian_records:
|
||
if record.ImageURL:
|
||
dashoujiaofu_list.append(record.ImageURL)
|
||
|
||
# 5. 构建返回数据(字段名与前端对应)
|
||
response_data = {
|
||
'zhuangtai': zhuangtai, # 订单状态
|
||
'zhiding': zhiding_id, # 指定打手ID
|
||
'jiedan_dashou_id': jiedan_dashou_id, # 服务打手ID
|
||
'dashouliuyan': dashou_liuyan, # 打手留言
|
||
'dashoujiaofu': dashoujiaofu_list # 打手交付图片列表
|
||
}
|
||
|
||
# 6. 返回成功响应
|
||
return Response({
|
||
'code': 0,
|
||
'msg': '成功',
|
||
'data': response_data
|
||
})
|
||
|
||
except Exception as e:
|
||
print(f"订单详情查询失败: {str(e)}")
|
||
return Response({
|
||
'code': 6,
|
||
'msg': '服务器内部错误',
|
||
'data': None
|
||
})
|
||
|
||
|
||
class JiedanView(APIView):
|
||
"""结单接口"""
|
||
permission_classes = [IsAuthenticated]
|
||
|
||
def post(self, request):
|
||
# 获取当前登录用户
|
||
try:
|
||
current_user = request.user
|
||
yonghuid = current_user.UserUID
|
||
except Exception as e:
|
||
return Response({
|
||
'code': 1,
|
||
'msg': '用户认证失败',
|
||
'data': None
|
||
})
|
||
|
||
# 获取前端参数
|
||
try:
|
||
data = request.data
|
||
dingdan_id = data.get('dingdanId', '')
|
||
pingfen = int(data.get('pingfen', 0)) # 评分,默认0
|
||
liuyan = data.get('liuyan', '') # 留言,默认空
|
||
except Exception as e:
|
||
return Response({
|
||
'code': 2,
|
||
'msg': '参数格式错误',
|
||
'data': None
|
||
})
|
||
|
||
# 参数验证
|
||
if not dingdan_id:
|
||
return Response({
|
||
'code': 3,
|
||
'msg': '订单ID不能为空',
|
||
'data': None
|
||
})
|
||
|
||
# 验证评分范围
|
||
if pingfen < 0 or pingfen > 5:
|
||
return Response({
|
||
'code': 4,
|
||
'msg': '评分必须在0-5分之间',
|
||
'data': None
|
||
})
|
||
|
||
# 使用事务确保数据一致性
|
||
try:
|
||
with transaction.atomic():
|
||
# 1. 验证订单是否存在且属于当前用户
|
||
pingtai_kuozhan = PlatformOrderExt.query.filter(
|
||
BossID=yonghuid,
|
||
Order__OrderID=dingdan_id
|
||
).select_related('Order').first()
|
||
|
||
if not pingtai_kuozhan:
|
||
return Response({
|
||
'code': 5,
|
||
'msg': '订单不存在或无权限操作',
|
||
'data': None
|
||
})
|
||
|
||
dingdan = pingtai_kuozhan.Order
|
||
|
||
# 2. 验证订单状态(必须是结算中 - 状态8)
|
||
if dingdan.Status != 8:
|
||
return Response({
|
||
'code': 6,
|
||
'msg': '订单不在结算状态,无法结单',
|
||
'data': None
|
||
})
|
||
|
||
# 3. 获取订单相关数据
|
||
dashou_fencheng = dingdan.PlayerCommission or Decimal('0.00') # 打手分成
|
||
jiedan_dashou_id = dingdan.PlayerID or '' # 接单打手ID
|
||
shangpin_id = dingdan.ProductID # 商品ID
|
||
|
||
# 4. 更新平台扩展表的老板评价(如果有留言)
|
||
if liuyan:
|
||
pingtai_kuozhan.BossReview = liuyan
|
||
pingtai_kuozhan.save()
|
||
|
||
# 5. 如果有评分,更新评分表
|
||
if pingfen > 0 and jiedan_dashou_id:
|
||
# 使用filter查询,更健壮
|
||
pingfen_records = PlayerRating.query.filter(PlayerID=jiedan_dashou_id)
|
||
|
||
if pingfen_records.exists():
|
||
# 已有记录,更新
|
||
pingfen_record = pingfen_records.first()
|
||
pingfen_record.TotalScore += Decimal(str(pingfen))
|
||
pingfen_record.RatingCount += 1
|
||
pingfen_record.save()
|
||
else:
|
||
# 新记录,创建
|
||
PlayerRating.query.create(
|
||
PlayerID=jiedan_dashou_id,
|
||
TotalScore=Decimal(str(pingfen)),
|
||
RatingCount=1
|
||
)
|
||
|
||
# 6. 更新商品真实销量(如果有商品ID)
|
||
if shangpin_id:
|
||
shangpin_records = Shangpin.query.filter(id=shangpin_id)
|
||
|
||
if shangpin_records.exists():
|
||
shangpin = shangpin_records.first()
|
||
# 检查字段是否存在
|
||
if hasattr(shangpin, 'zhenshi_xiaoliang'):
|
||
shangpin.zhenshi_xiaoliang = (shangpin.zhenshi_xiaoliang or 0) + 1
|
||
shangpin.save()
|
||
|
||
# 7. 更新打手扩展表(如果有打手ID和分成)
|
||
if jiedan_dashou_id and dashou_fencheng > 0:
|
||
# 查询打手用户
|
||
dashou_user = User.query.filter(UserUID=jiedan_dashou_id).select_related('DashouProfile').first()
|
||
|
||
if dashou_user:
|
||
# 查询打手扩展表
|
||
try:
|
||
dashou_kuozhan = dashou_user.DashouProfile
|
||
except UserDashou.DoesNotExist:
|
||
dashou_kuozhan = None
|
||
|
||
if dashou_kuozhan:
|
||
from jituan.services.fund_freeze import credit_dashou_order_settle
|
||
credit_dashou_order_settle(
|
||
order=dingdan,
|
||
dashou_profile=dashou_kuozhan,
|
||
user_id=jiedan_dashou_id,
|
||
amount=dashou_fencheng,
|
||
set_idle_status=True,
|
||
)
|
||
|
||
# 8. 更新订单状态为已完成(状态3)
|
||
dingdan.Status = 3
|
||
dingdan.save()
|
||
|
||
# 🔥 新增:调用打手每日统计(成交)
|
||
try:
|
||
update_dashou_daily_by_action(
|
||
yonghuid=jiedan_dashou_id,
|
||
amount=dashou_fencheng,
|
||
action=2 # 2 表示成交(结算)
|
||
)
|
||
logger.info(f"打手 {jiedan_dashou_id} 每日统计更新成功")
|
||
except Exception as e:
|
||
logger.error(f"打手每日统计更新失败: {e}")
|
||
# 不影响主流程
|
||
|
||
|
||
# ========== 新增:商品和店铺每日统计 ==========
|
||
try:
|
||
# 商品每日统计(只要有商品ID就执行)
|
||
if dingdan.ProductID:
|
||
# 从扩展表获取已计算好的收益值(下单时已存储)
|
||
pingtai_shouyi = Decimal('0.00')
|
||
dianpu_shouyi = Decimal('0.00')
|
||
if hasattr(dingdan, 'pingtai_kuozhan'):
|
||
pingtai_shouyi = dingdan.pingtai_kuozhan.PlatformIncome or Decimal('0.00')
|
||
dianpu_shouyi = dingdan.pingtai_kuozhan.ShopIncome or Decimal('0.00')
|
||
|
||
update_shangpin_daily_stat(
|
||
ProductID=dingdan.ProductID,
|
||
caozuo_leixing=2, # 2 = 结单
|
||
dingdan_jiage=dingdan.Amount,
|
||
PlatformIncome=pingtai_shouyi,
|
||
dianpu_zongshouyi=dianpu_shouyi
|
||
)
|
||
logger.info(f"商品统计更新完成,商品ID: {dingdan.ProductID}")
|
||
|
||
# 店铺每日统计(仅当存在店铺ID时执行)
|
||
|
||
|
||
# ========== 修改为 ==========
|
||
# 店铺每日统计(包含上级分红)
|
||
dianpu_id = None
|
||
shangji_id = None
|
||
shangji_fen = Decimal('0.00')
|
||
if hasattr(dingdan, 'pingtai_kuozhan'):
|
||
dianpu_id = dingdan.pingtai_kuozhan.ShopID
|
||
shangji_id = dingdan.pingtai_kuozhan.ParentShopID
|
||
shangji_fen = dingdan.pingtai_kuozhan.ParentBonus or Decimal('0.00')
|
||
if dianpu_id:
|
||
dianpu_shouyi = dingdan.pingtai_kuozhan.ShopIncome or Decimal('0.00')
|
||
update_dianpu_daily_stat(
|
||
ShopID=dianpu_id,
|
||
caozuo_leixing=2, # 结算
|
||
dingdan_jiage=dingdan.Amount,
|
||
ShopIncome=dianpu_shouyi,
|
||
shangji_ShopID=shangji_id, # 新增:上级店铺ID
|
||
ParentBonus=shangji_fen # 新增:该单给上级的分红
|
||
)
|
||
logger.info(f"店铺统计更新完成,店铺ID: {dianpu_id}, 上级ID: {shangji_id}, 上级分红: {shangji_fen}")
|
||
|
||
|
||
'''dianpu_id = None
|
||
if hasattr(dingdan, 'pingtai_kuozhan'):
|
||
dianpu_id = dingdan.pingtai_kuozhan.ShopID
|
||
if dianpu_id:
|
||
dianpu_shouyi = dingdan.pingtai_kuozhan.ShopIncome or Decimal('0.00')
|
||
update_dianpu_daily_stat(
|
||
ShopID=dianpu_id,
|
||
caozuo_leixing=2, # 2 = 结单
|
||
dingdan_jiage=dingdan.Amount,
|
||
ShopIncome=dianpu_shouyi
|
||
)
|
||
logger.info(f"店铺统计更新完成,店铺ID: {dianpu_id}")'''
|
||
except Exception as e:
|
||
logger.error(f"商品/店铺统计更新失败: {e}")
|
||
logger.error(traceback.format_exc())
|
||
# 统计失败不影响主流程
|
||
# =============================================
|
||
|
||
# 9. 返回成功响应
|
||
return Response({
|
||
'code': 0,
|
||
'msg': '结单成功',
|
||
'data': None
|
||
})
|
||
|
||
except Exception as e:
|
||
|
||
# 事务会自动回滚
|
||
return Response({
|
||
'code': 7,
|
||
'msg': '结单失败,服务器内部错误',
|
||
'data': None
|
||
})
|
||
|
||
|
||
class DingdanXiangqingView2(APIView):
|
||
"""订单详情接口(老板端)- 返回完整评价信息"""
|
||
permission_classes = [IsAuthenticated]
|
||
|
||
def post(self, request):
|
||
try:
|
||
yonghuid = request.user.UserUID
|
||
except Exception:
|
||
return Response({'code': 1, 'msg': '用户认证失败', 'data': None})
|
||
|
||
dingdan_id = request.data.get('dingdanId', '')
|
||
if not dingdan_id:
|
||
return Response({'code': 2, 'msg': '订单ID不能为空', 'data': None})
|
||
|
||
try:
|
||
# 权限验证
|
||
pingtai_ext = PlatformOrderExt.query.filter(
|
||
BossID=yonghuid,
|
||
Order__OrderID=dingdan_id
|
||
).select_related('Order').first()
|
||
|
||
if not pingtai_ext:
|
||
return Response({'code': 3, 'msg': '订单不存在或无权限查看', 'data': None})
|
||
|
||
order = pingtai_ext.Order
|
||
zhuangtai = order.Status or 0
|
||
jiedan_dashou_id = order.PlayerID or ''
|
||
dashou_liuyan = order.PlayerRemark or ''
|
||
UpdateTime = order.UpdateTime.strftime('%Y-%m-%d %H:%M:%S') if order.UpdateTime else ''
|
||
|
||
# 交付图片
|
||
dashoujiaofu_list = list(
|
||
PlayerDeliveryImage.query.filter(OrderID=dingdan_id)
|
||
.order_by('CreateTime')[:9]
|
||
.values_list('ImageURL', flat=True)
|
||
)
|
||
|
||
# 打手信息
|
||
dashou_nicheng = ''
|
||
dashou_touxiang = ''
|
||
jiedan_time = ''
|
||
tijiao_time = ''
|
||
if jiedan_dashou_id:
|
||
dashou_user = User.query.filter(UserUID=jiedan_dashou_id).select_related('DashouProfile').first()
|
||
if dashou_user:
|
||
dashou_touxiang = dashou_user.Avatar or ''
|
||
try:
|
||
dashou_nicheng = dashou_user.DashouProfile.nicheng or ''
|
||
except Exception:
|
||
# 无打手扩展档案时仍返回打手 UID / 头像
|
||
pass
|
||
# DashouBiaoxian 外键字段是 dingdan(列 dingdan_id),勿用 OrderID(会 FieldError → 整单详情 500)
|
||
try:
|
||
biaoxian = DashouBiaoxian.query.filter(
|
||
dingdan_id=dingdan_id,
|
||
dashou_id=jiedan_dashou_id
|
||
).first()
|
||
if biaoxian:
|
||
if biaoxian.jiedan_time:
|
||
jiedan_time = biaoxian.jiedan_time.strftime('%Y-%m-%d %H:%M:%S')
|
||
if biaoxian.tijiao_time:
|
||
tijiao_time = biaoxian.tijiao_time.strftime('%Y-%m-%d %H:%M:%S')
|
||
except Exception as e:
|
||
logger.warning(f"读取打手表现失败 dingdan={dingdan_id}: {e}")
|
||
|
||
# 老板自己的评价(如果已经结算过,可能已有评价)
|
||
laoban_pingjia = pingtai_ext.BossReview or ''
|
||
shangxian_sudu = None
|
||
fuwu_taidu = None
|
||
fanche_cishu = None
|
||
if jiedan_dashou_id and zhuangtai in [3, 4, 5, 6]: # 已完成或退款相关状态才可能有评价
|
||
try:
|
||
biaoxian = DashouBiaoxian.query.filter(
|
||
dingdan_id=dingdan_id,
|
||
dashou_id=jiedan_dashou_id
|
||
).first()
|
||
if biaoxian:
|
||
shangxian_sudu = biaoxian.shangxian_sudu
|
||
fuwu_taidu = biaoxian.fuwu_taidu
|
||
fanche_cishu = biaoxian.fanche_cishu
|
||
except Exception as e:
|
||
logger.warning(f"读取结算评价失败 dingdan={dingdan_id}: {e}")
|
||
|
||
data = {
|
||
'zhuangtai': zhuangtai,
|
||
'dashou': jiedan_dashou_id,
|
||
'dashou_nicheng': dashou_nicheng,
|
||
'dashou_touxiang': dashou_touxiang,
|
||
'dashouliuyan': dashou_liuyan,
|
||
'dashoujiaofu': dashoujiaofu_list,
|
||
'UpdateTime': UpdateTime,
|
||
'jiedan_time': jiedan_time,
|
||
'tijiao_time': tijiao_time,
|
||
'laoban_pingjia': laoban_pingjia,
|
||
'shangxian_sudu': shangxian_sudu, # 1-5 或 null
|
||
'fuwu_taidu': fuwu_taidu, # 1-5 或 null
|
||
'fanche_cishu': fanche_cishu # int 或 null
|
||
}
|
||
|
||
return Response({'code': 0, 'msg': '成功', 'data': data})
|
||
|
||
except Exception as e:
|
||
logger.error(f"订单详情查询异常: {e}", exc_info=True)
|
||
return Response({'code': 4, 'msg': '服务器内部错误', 'data': None})
|
||
|
||
|
||
class JiedanView2(APIView):
|
||
"""结单接口(老板端)- 接收全新评价字段并写入表现表"""
|
||
permission_classes = [IsAuthenticated]
|
||
|
||
def post(self, request):
|
||
# 1. 用户认证
|
||
try:
|
||
current_user = request.user
|
||
yonghuid = current_user.UserUID
|
||
except Exception:
|
||
return Response({'code': 1, 'msg': '用户认证失败', 'data': None})
|
||
|
||
# 2. 获取参数(字段名与前端完全一致)
|
||
try:
|
||
data = request.data
|
||
dingdan_id = data.get('dingdanId', '')
|
||
fanche_cishu = data.get('fanche_cishu') # 前端传的字符串或数字,后端转为整数
|
||
shangxian_sudu = data.get('shangxian_sudu')
|
||
fuwu_taidu = data.get('fuwu_taidu')
|
||
liuyan = data.get('liuyan', '')
|
||
except Exception:
|
||
return Response({'code': 2, 'msg': '参数格式错误', 'data': None})
|
||
|
||
# 参数校验
|
||
if not dingdan_id:
|
||
return Response({'code': 3, 'msg': '订单ID不能为空', 'data': None})
|
||
|
||
# 转换并校验必填评价字段
|
||
try:
|
||
fanche_cishu = int(fanche_cishu) if fanche_cishu is not None else None
|
||
shangxian_sudu = int(shangxian_sudu) if shangxian_sudu is not None else None
|
||
fuwu_taidu = int(fuwu_taidu) if fuwu_taidu is not None else None
|
||
except (ValueError, TypeError):
|
||
return Response({'code': 4, 'msg': '评价参数必须为整数', 'data': None})
|
||
|
||
if fanche_cishu is None:
|
||
return Response({'code': 5, 'msg': '翻车次数不能为空', 'data': None})
|
||
if not (1 <= shangxian_sudu <= 5 and 1 <= fuwu_taidu <= 5):
|
||
return Response({'code': 6, 'msg': '评价分数必须在1-5之间', 'data': None})
|
||
|
||
# 使用事务保证数据一致性
|
||
try:
|
||
with transaction.atomic():
|
||
# 3. 权限验证:订单属于当前老板
|
||
pingtai_ext = PlatformOrderExt.query.filter(
|
||
BossID=yonghuid,
|
||
Order__OrderID=dingdan_id
|
||
).select_related('Order').first()
|
||
|
||
if not pingtai_ext:
|
||
return Response({'code': 7, 'msg': '订单不存在或无权限操作', 'data': None})
|
||
|
||
order = pingtai_ext.Order
|
||
|
||
# 4. 状态校验:必须是结算中(状态8)
|
||
if order.Status != 8:
|
||
return Response({'code': 8, 'msg': '订单不在结算状态', 'data': None})
|
||
|
||
# 5. 提取订单关键数据
|
||
dashou_fencheng = order.PlayerCommission or Decimal('0.00')
|
||
jiedan_dashou_id = order.PlayerID or ''
|
||
shangpin_id = order.ProductID
|
||
|
||
# 6. 保存老板评价(兼容旧逻辑)
|
||
if liuyan:
|
||
pingtai_ext.BossReview = liuyan
|
||
pingtai_ext.save()
|
||
|
||
# 7. 更新评分表(用服务态度分作为综合评分,保留原有统计)
|
||
if jiedan_dashou_id and fuwu_taidu:
|
||
pingfen_records = PlayerRating.query.filter(PlayerID=jiedan_dashou_id)
|
||
if pingfen_records.exists():
|
||
pf = pingfen_records.first()
|
||
pf.TotalScore = int(pf.TotalScore or 0) + int(fuwu_taidu)
|
||
pf.RatingCount = int(pf.RatingCount or 0) + 1
|
||
pf.save()
|
||
else:
|
||
PlayerRating.query.create(
|
||
PlayerID=jiedan_dashou_id,
|
||
TotalScore=int(fuwu_taidu),
|
||
RatingCount=1
|
||
)
|
||
|
||
# 8. 更新商品真实销量
|
||
if shangpin_id:
|
||
shangpin_qs = Shangpin.query.filter(id=shangpin_id)
|
||
if shangpin_qs.exists():
|
||
sp = shangpin_qs.first()
|
||
if hasattr(sp, 'zhenshi_xiaoliang'):
|
||
sp.zhenshi_xiaoliang = (sp.zhenshi_xiaoliang or 0) + 1
|
||
sp.save()
|
||
|
||
# 9. 更新打手收益与状态
|
||
if jiedan_dashou_id and dashou_fencheng > 0:
|
||
dashou_user = User.query.filter(UserUID=jiedan_dashou_id).select_related('DashouProfile').first()
|
||
if dashou_user:
|
||
try:
|
||
dashou_ext = dashou_user.DashouProfile
|
||
from jituan.services.fund_freeze import credit_dashou_order_settle
|
||
credit_dashou_order_settle(
|
||
order=order,
|
||
dashou_profile=dashou_ext,
|
||
user_id=jiedan_dashou_id,
|
||
amount=dashou_fencheng,
|
||
set_idle_status=True,
|
||
)
|
||
except UserDashou.DoesNotExist:
|
||
pass
|
||
|
||
# 10. 更新订单状态为已完成
|
||
order.Status = 3
|
||
order.save()
|
||
|
||
# 11. 打手每日统计(成交)
|
||
try:
|
||
update_dashou_daily_by_action(
|
||
UserID=jiedan_dashou_id,
|
||
amount=dashou_fencheng,
|
||
action=2 # 2=结算/成交
|
||
)
|
||
except Exception as e:
|
||
logger.error(f"打手每日统计失败: {e}")
|
||
|
||
# 12. 商品/店铺每日统计
|
||
try:
|
||
if shangpin_id:
|
||
# 从扩展表取已计算收益
|
||
pingtai_shouyi = Decimal('0.00')
|
||
dianpu_shouyi = Decimal('0.00')
|
||
if hasattr(order, 'pingtai_kuozhan'):
|
||
pingtai_shouyi = order.pingtai_kuozhan.PlatformIncome or Decimal('0.00')
|
||
dianpu_shouyi = order.pingtai_kuozhan.ShopIncome or Decimal('0.00')
|
||
|
||
update_shangpin_daily_stat(
|
||
ProductID=shangpin_id,
|
||
caozuo_leixing=2,
|
||
dingdan_jiage=order.Amount,
|
||
PlatformIncome=pingtai_shouyi,
|
||
dianpu_zongshouyi=dianpu_shouyi
|
||
)
|
||
|
||
# 店铺统计(含上级分红)
|
||
if hasattr(order, 'pingtai_kuozhan'):
|
||
dianpu_id = order.pingtai_kuozhan.ShopID
|
||
shangji_id = order.pingtai_kuozhan.ParentShopID
|
||
shangji_fen = order.pingtai_kuozhan.ParentBonus or Decimal('0.00')
|
||
if dianpu_id:
|
||
update_dianpu_daily_stat(
|
||
ShopID=dianpu_id,
|
||
caozuo_leixing=2,
|
||
dingdan_jiage=order.Amount,
|
||
ShopIncome=dianpu_shouyi,
|
||
shangji_ShopID=shangji_id,
|
||
ParentBonus=shangji_fen
|
||
)
|
||
except Exception as e:
|
||
logger.error(f"商品/店铺统计失败: {e}")
|
||
|
||
# 14. 写入打手表现表(结算评价);字段名须与 record_dashou_biaoxian 一致
|
||
if jiedan_dashou_id:
|
||
record_dashou_biaoxian(
|
||
dingdan_id=dingdan_id,
|
||
dashou_id=jiedan_dashou_id,
|
||
xingwei=3, # 3=结算
|
||
fanche_cishu=fanche_cishu,
|
||
shangxian_sudu=shangxian_sudu,
|
||
fuwu_taidu=fuwu_taidu
|
||
)
|
||
|
||
# 15. 返回成功
|
||
return Response({'code': 0, 'msg': '结单成功', 'data': None})
|
||
|
||
except Exception as e:
|
||
logger.error(f"结单事务异常: {e}", exc_info=True)
|
||
return Response({'code': 9, 'msg': '服务器内部错误,结单失败', 'data': None})
|
||
|
||
|
||
|
||
|