finish
This commit is contained in:
@@ -5,8 +5,8 @@ from django.shortcuts import render
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.http import HttpResponse
|
||||
from drf_spectacular.utils import extend_schema, extend_schema_view, OpenApiParameter, OpenApiExample
|
||||
from .models import ESP32Config, Order, WeChatPayConfig, Service, VBCourse, ServiceOrder, Salesperson, CommissionLog, WeChatUser, Distributor, Withdrawal
|
||||
from .serializers import ESP32ConfigSerializer, OrderSerializer, ServiceSerializer, VBCourseSerializer, ServiceOrderSerializer, WeChatUserSerializer, DistributorSerializer, WithdrawalSerializer
|
||||
from .models import ESP32Config, Order, WeChatPayConfig, Service, VCCourse, ServiceOrder, Salesperson, CommissionLog, WeChatUser, Distributor, Withdrawal, CourseEnrollment
|
||||
from .serializers import ESP32ConfigSerializer, OrderSerializer, ServiceSerializer, VCCourseSerializer, ServiceOrderSerializer, WeChatUserSerializer, DistributorSerializer, WithdrawalSerializer, CommissionLogSerializer, CourseEnrollmentSerializer
|
||||
from django.core.signing import TimestampSigner, BadSignature, SignatureExpired
|
||||
from django.contrib.auth.models import User
|
||||
from wechatpayv3 import WeChatPay, WeChatPayType
|
||||
@@ -215,6 +215,7 @@ def pay(request):
|
||||
|
||||
# 1. 获取并验证请求参数
|
||||
good_id = request.data.get('goodid')
|
||||
order_type = request.data.get('type', 'config') # 默认为 config
|
||||
quantity = int(request.data.get('quantity', 1))
|
||||
customer_name = request.data.get('customer_name')
|
||||
phone_number = request.data.get('phone_number')
|
||||
@@ -237,15 +238,23 @@ def pay(request):
|
||||
return Response({'error': f'支付配置错误: {error_msg}'}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 3. 查找商品和销售员,创建订单
|
||||
try:
|
||||
product = ESP32Config.objects.get(id=good_id)
|
||||
except ESP32Config.DoesNotExist:
|
||||
print(f"商品不存在: {good_id}")
|
||||
return Response({'error': f'找不到 ID 为 {good_id} 的商品'}, status=status.HTTP_404_NOT_FOUND)
|
||||
product = None
|
||||
if order_type == 'course':
|
||||
try:
|
||||
product = VBCourse.objects.get(id=good_id)
|
||||
except VBCourse.DoesNotExist:
|
||||
print(f"课程不存在: {good_id}")
|
||||
return Response({'error': f'找不到 ID 为 {good_id} 的课程'}, status=status.HTTP_404_NOT_FOUND)
|
||||
else:
|
||||
try:
|
||||
product = ESP32Config.objects.get(id=good_id)
|
||||
except ESP32Config.DoesNotExist:
|
||||
print(f"商品不存在: {good_id}")
|
||||
return Response({'error': f'找不到 ID 为 {good_id} 的商品'}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
# 检查库存
|
||||
if product.stock < quantity:
|
||||
return Response({'error': f'库存不足,仅剩 {product.stock} 件'}, status=status.HTTP_400_BAD_REQUEST)
|
||||
# 检查库存 (仅针对硬件)
|
||||
if product.stock < quantity:
|
||||
return Response({'error': f'库存不足,仅剩 {product.stock} 件'}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
salesperson = None
|
||||
if ref_code:
|
||||
@@ -255,24 +264,34 @@ def pay(request):
|
||||
total_price = product.price * quantity
|
||||
amount_in_cents = int(total_price * 100)
|
||||
|
||||
order = Order.objects.create(
|
||||
config=product,
|
||||
quantity=quantity,
|
||||
total_price=total_price,
|
||||
customer_name=customer_name,
|
||||
phone_number=phone_number,
|
||||
shipping_address=shipping_address,
|
||||
salesperson=salesperson,
|
||||
status='pending'
|
||||
)
|
||||
order_kwargs = {
|
||||
'quantity': quantity,
|
||||
'total_price': total_price,
|
||||
'customer_name': customer_name,
|
||||
'phone_number': phone_number,
|
||||
'shipping_address': shipping_address,
|
||||
'salesperson': salesperson,
|
||||
'status': 'pending'
|
||||
}
|
||||
|
||||
if order_type == 'course':
|
||||
order_kwargs['course'] = product
|
||||
else:
|
||||
order_kwargs['config'] = product
|
||||
|
||||
# 扣减库存
|
||||
product.stock -= quantity
|
||||
product.save()
|
||||
order = Order.objects.create(**order_kwargs)
|
||||
|
||||
# 扣减库存 (仅针对硬件)
|
||||
if order_type != 'course':
|
||||
product.stock -= quantity
|
||||
product.save()
|
||||
|
||||
# 4. 调用微信支付接口
|
||||
out_trade_no = f"PAY{order.id}T{int(time.time())}"
|
||||
description = f"购买 {product.name} x {quantity}"
|
||||
if order_type == 'course':
|
||||
description = f"报名 {product.title}"
|
||||
else:
|
||||
description = f"购买 {product.name} x {quantity}"
|
||||
|
||||
# 保存商户订单号到数据库,方便后续查询
|
||||
order.out_trade_no = out_trade_no
|
||||
@@ -459,13 +478,19 @@ def payment_finish(request):
|
||||
order.save()
|
||||
print(f"订单 {order.id} 状态已更新")
|
||||
|
||||
# 计算佣金
|
||||
# 计算佣金 (旧版销售员系统)
|
||||
try:
|
||||
salesperson = order.salesperson
|
||||
if salesperson:
|
||||
# 1. 计算直接佣金 (一级)
|
||||
# 优先级: 产品独立分润比例 > 销售员个人分润比例
|
||||
rate_1 = order.config.commission_rate if order.config.commission_rate > 0 else salesperson.commission_rate
|
||||
rate_1 = 0
|
||||
if order.config:
|
||||
rate_1 = order.config.commission_rate if order.config.commission_rate > 0 else salesperson.commission_rate
|
||||
elif order.course:
|
||||
# 课程暂时使用销售员默认比例
|
||||
rate_1 = salesperson.commission_rate
|
||||
|
||||
amount_1 = order.total_price * rate_1
|
||||
|
||||
if amount_1 > 0:
|
||||
@@ -476,7 +501,7 @@ def payment_finish(request):
|
||||
level=1,
|
||||
status='pending'
|
||||
)
|
||||
print(f"生成一级佣金: {salesperson.name} - {amount_1}")
|
||||
print(f"生成一级佣金(Salesperson): {salesperson.name} - {amount_1}")
|
||||
|
||||
# 2. 计算上级佣金 (二级)
|
||||
parent = salesperson.parent
|
||||
@@ -492,9 +517,61 @@ def payment_finish(request):
|
||||
level=2,
|
||||
status='pending'
|
||||
)
|
||||
print(f"生成二级佣金: {parent.name} - {amount_2}")
|
||||
print(f"生成二级佣金(Salesperson): {parent.name} - {amount_2}")
|
||||
|
||||
# 计算佣金 (新版分销员系统)
|
||||
distributor = order.distributor
|
||||
if distributor:
|
||||
# 1. 计算直接佣金 (一级)
|
||||
# 优先级: 产品独立分润比例 > 分销员个人分润比例
|
||||
rate_1 = 0
|
||||
if order.config:
|
||||
rate_1 = order.config.commission_rate if order.config.commission_rate > 0 else distributor.commission_rate
|
||||
elif order.course:
|
||||
# 课程暂时使用分销员默认比例
|
||||
rate_1 = distributor.commission_rate
|
||||
|
||||
amount_1 = order.total_price * rate_1
|
||||
|
||||
if amount_1 > 0:
|
||||
CommissionLog.objects.create(
|
||||
order=order,
|
||||
distributor=distributor,
|
||||
amount=amount_1,
|
||||
level=1,
|
||||
status='settled' # 简化流程,直接结算到余额
|
||||
)
|
||||
# 更新余额
|
||||
distributor.total_earnings += amount_1
|
||||
distributor.withdrawable_balance += amount_1
|
||||
distributor.save()
|
||||
print(f"生成一级佣金(Distributor): {distributor.user.nickname} - {amount_1}")
|
||||
|
||||
# 2. 计算上级佣金 (二级)
|
||||
parent = distributor.parent
|
||||
if parent:
|
||||
# 二级固定比例 2% (0.02)
|
||||
rate_2 = 0.02
|
||||
amount_2 = order.total_price * models.DecimalField(max_digits=5, decimal_places=4).to_python(rate_2)
|
||||
|
||||
if amount_2 > 0:
|
||||
CommissionLog.objects.create(
|
||||
order=order,
|
||||
distributor=parent,
|
||||
amount=amount_2,
|
||||
level=2,
|
||||
status='settled'
|
||||
)
|
||||
# 更新余额
|
||||
parent.total_earnings += amount_2
|
||||
parent.withdrawable_balance += amount_2
|
||||
parent.save()
|
||||
print(f"生成二级佣金(Distributor): {parent.user.nickname} - {amount_2}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"佣金计算失败: {str(e)}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
except Exception as e:
|
||||
print(f"订单更新失败: {str(e)}")
|
||||
@@ -508,15 +585,22 @@ def payment_finish(request):
|
||||
return HttpResponse(str(e), status=500)
|
||||
|
||||
@extend_schema_view(
|
||||
list=extend_schema(summary="获取VB课程列表", description="获取所有可用的VB课程"),
|
||||
retrieve=extend_schema(summary="获取VB课程详情", description="获取指定VB课程的详细信息")
|
||||
list=extend_schema(summary="获取VC课程列表", description="获取所有可用的VC课程"),
|
||||
retrieve=extend_schema(summary="获取VC课程详情", description="获取指定VC课程的详细信息")
|
||||
)
|
||||
class VBCourseViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
class VCCourseViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""
|
||||
VB课程列表和详情
|
||||
VC课程列表和详情
|
||||
"""
|
||||
queryset = VBCourse.objects.all().order_by('-created_at')
|
||||
serializer_class = VBCourseSerializer
|
||||
queryset = VCCourse.objects.all().order_by('-created_at')
|
||||
serializer_class = VCCourseSerializer
|
||||
|
||||
class CourseEnrollmentViewSet(viewsets.ModelViewSet):
|
||||
"""
|
||||
课程报名管理
|
||||
"""
|
||||
queryset = CourseEnrollment.objects.all().order_by('-created_at')
|
||||
serializer_class = CourseEnrollmentSerializer
|
||||
|
||||
def order_check_view(request):
|
||||
"""
|
||||
@@ -989,3 +1073,64 @@ class DistributorViewSet(viewsets.GenericViewSet):
|
||||
|
||||
return Response({'message': 'Withdrawal request submitted'})
|
||||
|
||||
@action(detail=False, methods=['get'])
|
||||
def earnings(self, request):
|
||||
"""查看个人分销金额及明细"""
|
||||
user = get_current_wechat_user(request)
|
||||
if not user or not hasattr(user, 'distributor'):
|
||||
return Response({'error': 'Unauthorized'}, status=401)
|
||||
|
||||
distributor = user.distributor
|
||||
logs = CommissionLog.objects.filter(distributor=distributor).order_by('-created_at')
|
||||
|
||||
page = self.paginate_queryset(logs)
|
||||
if page is not None:
|
||||
serializer = CommissionLogSerializer(page, many=True)
|
||||
return self.get_paginated_response(serializer.data)
|
||||
|
||||
serializer = CommissionLogSerializer(logs, many=True)
|
||||
return Response(serializer.data)
|
||||
|
||||
@action(detail=False, methods=['get'])
|
||||
def team(self, request):
|
||||
"""查看团队(二级分销情况)"""
|
||||
user = get_current_wechat_user(request)
|
||||
if not user or not hasattr(user, 'distributor'):
|
||||
return Response({'error': 'Unauthorized'}, status=401)
|
||||
|
||||
distributor = user.distributor
|
||||
|
||||
# 直推下级
|
||||
children = Distributor.objects.filter(parent=distributor)
|
||||
children_data = DistributorSerializer(children, many=True).data
|
||||
|
||||
# 二级分销收益统计
|
||||
second_level_earnings = CommissionLog.objects.filter(distributor=distributor, level=2).aggregate(total=models.Sum('amount'))['total'] or 0
|
||||
|
||||
return Response({
|
||||
'children_count': children.count(),
|
||||
'children': children_data,
|
||||
'second_level_earnings': second_level_earnings
|
||||
})
|
||||
|
||||
@action(detail=False, methods=['get'])
|
||||
def orders(self, request):
|
||||
"""查看分销订单"""
|
||||
user = get_current_wechat_user(request)
|
||||
if not user or not hasattr(user, 'distributor'):
|
||||
return Response({'error': 'Unauthorized'}, status=401)
|
||||
|
||||
distributor = user.distributor
|
||||
# 查找我赚了钱的订单
|
||||
commission_logs = CommissionLog.objects.filter(distributor=distributor).select_related('order')
|
||||
order_ids = commission_logs.values_list('order_id', flat=True)
|
||||
orders = Order.objects.filter(id__in=order_ids).order_by('-created_at')
|
||||
|
||||
page = self.paginate_queryset(orders)
|
||||
if page is not None:
|
||||
serializer = OrderSerializer(page, many=True)
|
||||
return self.get_paginated_response(serializer.data)
|
||||
|
||||
serializer = OrderSerializer(orders, many=True)
|
||||
return Response(serializer.data)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user