This commit is contained in:
jeremygan2021
2026-02-11 04:06:51 +08:00
parent 96d5598fb5
commit 1100143a6e
36 changed files with 1223 additions and 401 deletions

View File

@@ -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)