order
This commit is contained in:
@@ -18,6 +18,9 @@ import os
|
||||
import base64
|
||||
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
|
||||
from django.conf import settings
|
||||
import requests
|
||||
import random
|
||||
from django.core.cache import cache
|
||||
|
||||
# 猴子补丁:绕过微信支付响应签名验证
|
||||
# 原因是:在开发环境或证书未能正确下载时,SDK 会因为无法验证微信返回的签名而抛出异常。
|
||||
@@ -108,6 +111,70 @@ def get_wechat_pay_client():
|
||||
except Exception as e:
|
||||
return None, str(e)
|
||||
|
||||
@extend_schema(
|
||||
summary="发送短信验证码",
|
||||
description="发送6位数字验证码到指定手机号",
|
||||
request={
|
||||
'application/json': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'phone_number': {'type': 'string', 'description': '手机号码'},
|
||||
},
|
||||
'required': ['phone_number']
|
||||
}
|
||||
},
|
||||
responses={
|
||||
200: OpenApiExample('成功', value={'message': '验证码已发送'}),
|
||||
400: OpenApiExample('失败', value={'error': '手机号不能为空'})
|
||||
}
|
||||
)
|
||||
@api_view(['POST'])
|
||||
def send_sms_code(request):
|
||||
phone = request.data.get('phone_number')
|
||||
if not phone:
|
||||
return Response({'error': '手机号不能为空'}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 生成6位验证码
|
||||
code = ''.join([str(random.randint(0, 9)) for _ in range(6)])
|
||||
|
||||
# 缓存验证码 (5分钟有效)
|
||||
cache_key = f"sms_code_{phone}"
|
||||
cache.set(cache_key, code, timeout=300)
|
||||
|
||||
# 调用外部短信API
|
||||
try:
|
||||
api_url = "https://data.tangledup-ai.com/api/send-sms"
|
||||
payload = {
|
||||
"phone_number": phone,
|
||||
"code": code,
|
||||
"template_code": "SMS_493295002",
|
||||
"sign_name": "叠加态科技云南"
|
||||
}
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"accept": "application/json"
|
||||
}
|
||||
|
||||
response = requests.post(api_url, json=payload, headers=headers, timeout=15)
|
||||
|
||||
if response.status_code == 200:
|
||||
print(f"短信发送成功: {phone} -> {code}")
|
||||
return Response({'message': '验证码已发送'})
|
||||
else:
|
||||
print(f"短信发送失败: {response.text}")
|
||||
return Response({'error': '短信发送失败,请稍后重试'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
|
||||
except requests.exceptions.Timeout:
|
||||
print(f"短信发送超时: {phone}")
|
||||
# 超时并不一定代表失败,可能是对方响应慢。但为了安全起见,提示用户稍后重试或检查手机。
|
||||
# 考虑到用户反馈短信实际已收到,这里返回一个较为温和的错误或成功提示(视业务逻辑而定)。
|
||||
# 这里我们选择返回一个特定的错误,前端可以据此提示用户。
|
||||
return Response({'message': '短信请求已发送,请留意查收(如未收到请重试)'}, status=status.HTTP_200_OK)
|
||||
|
||||
except Exception as e:
|
||||
print(f"发送短信异常: {str(e)}")
|
||||
return Response({'error': '短信服务异常'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
|
||||
@extend_schema(
|
||||
summary="微信支付 V3 Native 下单",
|
||||
description="创建订单并获取微信支付二维码链接(code_url)。参数包括商品ID、数量、客户信息等。",
|
||||
@@ -181,6 +248,10 @@ def pay(request):
|
||||
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)
|
||||
|
||||
salesperson = None
|
||||
if ref_code:
|
||||
from .models import Salesperson
|
||||
@@ -200,6 +271,10 @@ def pay(request):
|
||||
status='pending'
|
||||
)
|
||||
|
||||
# 扣减库存
|
||||
product.stock -= quantity
|
||||
product.save()
|
||||
|
||||
# 4. 调用微信支付接口
|
||||
out_trade_no = f"PAY{order.id}T{int(time.time())}"
|
||||
description = f"购买 {product.name} x {quantity}"
|
||||
@@ -469,6 +544,37 @@ class OrderViewSet(viewsets.ModelViewSet):
|
||||
serializer = self.get_serializer(orders, many=True)
|
||||
return Response(serializer.data)
|
||||
|
||||
@action(detail=False, methods=['post'], authentication_classes=[], permission_classes=[])
|
||||
def my_orders(self, request):
|
||||
"""
|
||||
查询我的订单
|
||||
需要提供手机号和验证码
|
||||
"""
|
||||
phone = request.data.get('phone_number')
|
||||
code = request.data.get('code')
|
||||
|
||||
if not phone or not code:
|
||||
return Response({'error': '请提供手机号和验证码'}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 验证验证码
|
||||
cache_key = f"sms_code_{phone}"
|
||||
cached_code = cache.get(cache_key)
|
||||
|
||||
# 开发/测试方便,如果验证码是 888888 且没有缓存,允许通过(可选,但为了演示方便)
|
||||
# if code == '888888': pass
|
||||
|
||||
if not cached_code or cached_code != code:
|
||||
return Response({'error': '验证码错误或已过期'}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 查询订单
|
||||
orders = Order.objects.filter(phone_number=phone).order_by('-created_at')
|
||||
serializer = self.get_serializer(orders, many=True)
|
||||
|
||||
# 验证通过后清除验证码 (防止重放)
|
||||
cache.delete(cache_key)
|
||||
|
||||
return Response(serializer.data)
|
||||
|
||||
@action(detail=True, methods=['post'])
|
||||
def initiate_payment(self, request, pk=None):
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user