后端接受支付结果
支付宝会返回的参数如下列表:
http://www.luffycity.cn:8080?
charset=utf-8&
out_trade_no=2019040217080000000010976&
method=alipay.trade.page.pay.return&
total_amount=1206.44&
sign=XKJG5826fH%2F9%2B3jCWw2ODjlc%2FuGLfqmr5RnimSAqrh%2B5bFkWcbLDh5V6VYtMqCpwnYp3FuGPqEeUeRO6WK62Qz0Q5nQGOA394IdxPfTOzry7PXuwYf41PCbDq53yg7vCYrobz4Tt8uajeADJLJwIsL%2F%2B88vbDEISUDUujL4442kl3oLh3EDD8DxZc2LLsv1Z%2FEFGJMfcTA47A4T7qmjB%2BbLKJetZZBISdt9RDL0q8A%2BAfb8B3Ux1nq%2F0EiNGiwIlWC1pvUCHK2UXMJW3kmgU9P9Zoujrj4ER28oieQt6Rt4gQXeah5uYtAMkftWfZpiyu%2FjUkr6iRx%2B4mP5IFz4Uew%3D%3D&
trade_no=2019040222001439881000005802&
auth_app_id=2016091600523592&
version=1.0&
app_id=2016091600523592&
sign_type=RSA2&
seller_id=2088102175868026&
timestamp=2019-04-02%2017%3A13%3A15
后端完成 支付宝支付结果的处理并更新订单和购买记录
users/models.py,模型代码:
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
"""用户模型类"""
mobile = models.CharField(max_length=11, unique=True, verbose_name='手机号')
class Meta:
db_table = 'ly_users'
verbose_name = '用户'
verbose_name_plural = verbose_name
from luffy.utils.models import BaseModel
from courses.models import Course
class UserCourse(BaseModel):
pay_choices = (
(0, '支付宝'),
(1, '微信支付'),
(2, '免费活动'),
(3, '活动赠品'),
(4, '系统赠送'),
)
user = models.ForeignKey(User, related_name='user_courses', on_delete=models.DO_NOTHING,verbose_name="用户")
course = models.ForeignKey(Course, related_name='course_users', on_delete=models.DO_NOTHING, verbose_name="课程")
buy_number = models.CharField(max_length=128, null=True, verbose_name="账单号")
buy_type = models.SmallIntegerField(choices=pay_choices, default=0, verbose_name="购买方式")
pay_time = models.DateTimeField(null=True, verbose_name="购买时间")
out_time = models.DateTimeField(null=True, verbose_name="过期时间")
class Meta:
db_table = 'ly_user_course'
verbose_name = '课程购买记录'
verbose_name_plural = verbose_name
payments/views.py,视图代码:
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework import status
from orders.models import Order
from coupon.models import UserCoupon
from alipay import AliPay
from django.conf import settings
import os
from django.db import transaction
from decimal import Decimal
import logging
log = logging.getLogger("django")
from datetime import datetime
from users.models import UserCourse
class AlipayAPIView(APIView):
# permission_classes = [IsAuthenticated]
def get(self,request):
"""生成支付宝支付地址"""
# 接受参数[优惠券,订单号]
coupon_id = request.query_params.get("coupon_id")
order_number = request.query_params.get("order_number")
try:
order = Order.objects.get(order_number=order_number)
except Order.DoesNotExist:
return Response({"message":"对不起,当前订单信息不存在!无法进行支付"},status=status.HTTP_400_BAD_REQUEST)
if coupon_id != None and coupon_id != "0":
with transaction.atomic():
save_id = transaction.savepoint()
# 重新计算订单实际支付价格
try:
user_coupon = UserCoupon.objects.get(pk=coupon_id)
except UserCoupon.DoesNotExist:
return Response({"message": "对不起,当前订单使用的优惠券不存在!无法进行支付"}, status=status.HTTP_400_BAD_REQUEST)
if user_coupon.coupon.coupon_type == 0:
"""折扣优惠"""
order.real_price = order.total_price * Decimal(user_coupon.coupon.sale[1:])
elif user_coupon.coupon.coupon_type == 1:
order.real_price = order.total_price - Decimal(user_coupon.coupon.sale[1:])
else:
return Response({"message": "当前优惠券无法使用!无法进行支付"}, status=status.HTTP_400_BAD_REQUEST)
try:
# 经过上面的计算,保存实付价格和使用的优惠券
order.use_coupon = True
order.coupon = user_coupon.id
order.save()
# 上面的优惠券已经被使用了,所以我们需要修改优惠券的状态
user_coupon.is_use = True
user_coupon.save()
except:
transaction.savepoint_rollback(save_id)
return Response({"message": "系统异常,无法进行支付"}, status=status.HTTP_400_BAD_REQUEST)
# 构造支付宝支付链接地址
alipay = AliPay(
appid=settings.ALIPAY_APPID,
app_notify_url=settings.APP_NOTIFY_URL, # 默认回调url
app_private_key_path=os.path.join(os.path.dirname(os.path.abspath(__file__)), "keys/app_private_key.pem"),
# 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,
alipay_public_key_path=os.path.join(os.path.dirname(os.path.abspath(__file__)), "keys/alipay_public_key.pem"),
sign_type="RSA2", # RSA 或者 RSA2
debug=settings.ALIPAY_DEBUG
)
order_string = alipay.api_alipay_trade_page_pay(
out_trade_no=order.order_number,
total_amount= "%.2f" % order.real_price,
subject=order.order_title,
return_url=settings.ALIPAY_RETURN_URL,
notify_url=settings.ALIPAY_NOTIFY_URL,
)
url = settings.APIPAY_GATEWAY + "?" + order_string
return Response({"message":"发起支付成功","url":url})
class AlipayResult(APIView):
def get(self,request):
# 获取支付结果的所有参数,并转换成字典
data = request.query_params.dict()
# 在字典中移除sign签名
signature = data.pop("sign")
alipay = AliPay(
appid=settings.ALIPAY_APPID,
app_notify_url=settings.APP_NOTIFY_URL, # 默认回调url
app_private_key_path=os.path.join(os.path.dirname(os.path.abspath(__file__)), "keys/app_private_key.pem"),
# 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,
alipay_public_key_path=os.path.join(os.path.dirname(os.path.abspath(__file__)), "keys/alipay_public_key.pem"),
sign_type="RSA2", # RSA 或者 RSA2
debug=settings.ALIPAY_DEBUG
)
success = alipay.verify(data, signature)
if success:
# 支付成功!
# 更新订单
order_number = data.get("out_trade_no")
try:
order = Order.objects.get( order_number=order_number )
except Order.DoesNotExist:
log.error("订单号:%s不存在!" % order_number )
return Response({"message": "无效的订单号"},status=status.HTTP_500_INTERNAL_SERVER_ERROR)
with transaction.atomic():
save_id = transaction.savepoint()
try:
order.order_status = 1
order.pay_time = datetime.now()
# order.pay_time = data.get("timestamp")
order.save()
# 课程与用户之间添加一条购买记录
detail_list = order.order_courses.all()
course_list = []
for detail in detail_list:
if detail.expire=='-1':
out_time = "2099-01-01 00:00:00"
else:
out_time = datetime.now().timestamp() + detail.expire * 86400
# 日期时间对象 = fromtimestamp(数值时间戳)
out_time = datetime.fromtimestamp(out_time)
out_time = out_time.strftime("%Y-%m-%d %H:%M:%S")
UserCourse.objects.create(
user=order.user,
course=detail.course,
buy_number=data.get("trade_no"),
buy_type=0,
pay_time=data.get("timestamp"),
out_time=out_time
)
course_list.append(detail.course.name)
return Response({"message":{
"pay_time": order.pay_time.strftime("%Y-%m-%d %H:%M:%S"),
"real_price": order.real_price,
"course_list":course_list,
}})
except:
log.error("修改订单和购买记录发生异常!")
transaction.savepoint_rollback(save_id)
return Response({"message":"系统异常!"},status=status.HTTP_500_INTERNAL_SERVER_ERROR)
payments/urls.py,路由代码:
from django.urls import path,re_path
from . import views
urlpatterns = [
path("alipay/url/",views.AlipayAPIView.as_view() ),
path("alipay/result/",views.AlipayResult.as_view() ),
]
前端把地址栏上面返回的同步支付结果转发给服务端
Success.vue
您已成功购买 {{order_info.course_list.length}} 门课程!
你还可以加入QQ群 747556033 学习交流
付款时间:{{order_info.pay_time}}
付款金额:¥{{order_info.real_price}}元
课程信息:{{order_info.course_list2}}
立即学习
修改订单结果[新增接口接受异步支付结果]
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework import status
from orders.models import Order
from coupon.models import UserCoupon
from alipay import AliPay
from django.conf import settings
import os
from django.db import transaction
from decimal import Decimal
import logging
log = logging.getLogger("django")
from datetime import datetime
from users.models import UserCourse
class AlipayAPIView(APIView):
......
class AlipayResult(APIView):
def get(self,request):
......
def post(self,request):
data = request.data.dict()
# 在字典中移除sign签名
signature = data.pop("sign")
alipay = AliPay(
appid=settings.ALIPAY_APPID,
app_notify_url=settings.APP_NOTIFY_URL, # 默认回调url
app_private_key_path=os.path.join(os.path.dirname(os.path.abspath(__file__)), "keys/app_private_key.pem"),
# 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,
alipay_public_key_path=os.path.join(os.path.dirname(os.path.abspath(__file__)), "keys/alipay_public_key.pem"),
sign_type="RSA2", # RSA 或者 RSA2
debug=settings.ALIPAY_DEBUG
)
success = alipay.verify(data, signature)
if success:
# 支付成功!
# 更新订单
order_number = data.get("out_trade_no")
try:
order = Order.objects.get( order_number=order_number )
except Order.DoesNotExist:
log.error("订单号:%s不存在!" % order_number )
return Response({"message": "无效的订单号"},status=status.HTTP_500_INTERNAL_SERVER_ERROR)
with transaction.atomic():
save_id = transaction.savepoint()
try:
order.order_status = 1
order.pay_time = datetime.now()
# order.pay_time = data.get("timestamp")
order.save()
# 课程与用户之间添加一条购买记录
detail_list = order.order_courses.all()
course_list = []
for detail in detail_list:
if detail.expire=='-1':
out_time = "2099-01-01 00:00:00"
else:
out_time = datetime.now().timestamp() + detail.expire * 86400
# 日期时间对象 = fromtimestamp(数值时间戳)
out_time = datetime.fromtimestamp(out_time)
out_time = out_time.strftime("%Y-%m-%d %H:%M:%S")
UserCourse.objects.create(
user=order.user,
course=detail.course,
buy_number=data.get("trade_no"),
buy_type=0,
pay_time=data.get("timestamp"),
out_time=out_time
)
course_list.append(detail.course.name)
return Response("success", content_type="text/html")
except:
log.error("修改订单和购买记录发生异常!")
transaction.savepoint_rollback(save_id)
return Response({"message":"系统异常!"},status=status.HTTP_500_INTERNAL_SERVER_ERROR)
我的订单
Mixtea
深圳市 | 程序员
- 我的账户
- 我的订单
- 个人资料
- 账号安全
2019-04-02 10:27:49
订单号:
20190402102749606
2019-04-02 10:27:49
订单号:
20190402102749606
2019-04-02 10:27:49
订单号:
20190402102749606
2019-04-02 10:27:49
订单号:
20190402102749606
2019-04-02 10:27:49
订单号:
20190402102749606
路由注册:
import Vue from "vue"
import Router from "vue-router"
// 导入页面组件
。。。
import User from "../components/User"
import UserOrder from "../components/UserOrder"
Vue.use(Router);
export default new Router({
// 设置路由模式为‘history’,去掉默认的#
mode: "history",
routes:[
....
{
name:"User",
path:"/my",
component: User,
// children:[ // 设置子路由,在父级路由对应的组件中如果存在父子公用部分页面,可以使用router-view来实现子路由
// {
// name:"UserOrder",
// path:"/order",
// component: UserOrder,
// }
// ]
},
{
name:"UserOrder",
path:"/my/order",
component: UserOrder,
},
]
})
后端提供查询当前登录用户的订单列表信息。
orders/models.py,模型新增返回订单状态的文本格式
class Order(BaseModel):
"""订单记录"""
。。。。
def order_status_text(self):
return self.status_choices[self.order_status][1]
users/serializers.py,序列化器,代码:
"""会员订单"""
from orders.models import Order,OrderDetail
class OrderDetailListModelSerializer(serializers.ModelSerializer):
class Meta:
model = OrderDetail
fields = ("price","real_price","discount_name","expire_text","course_img","course_name","course")
class OrderListModelSerializer(serializers.ModelSerializer):
order_courses = OrderDetailListModelSerializer(many=True)
class Meta:
model = Order
fields = ("order_courses","id","create_time","pay_time","order_number","real_price","total_price","order_status","order_status_text","pay_type")
class UserOrderModelSerializer(serializers.ModelSerializer):
user_orders = OrderListModelSerializer(many=True)
class Meta:
model = User
# fields = ("username","身份信息..")
fields = ("username","user_orders")
users/views.py,视图代码:
from .serializers import UserOrderModelSerializer
from rest_framework.generics import RetrieveAPIView
from rest_framework.permissions import IsAuthenticated
class UserOrderAPIView(RetrieveAPIView):
permission_classes = [IsAuthenticated]
serializer_class = UserOrderModelSerializer
queryset = User.objects.all()
users/urls.py,路由代码:
re_path(r'(?P\d+)/orders/',views.UserOrderAPIView.as_view()),
前端请求获取当前登录用户的订单信息
{{user_info.username}}
深圳市 | 程序员
- 我的账户
- 我的订单
- 个人资料
- 账号安全
下单时间: {{new Date(order.create_time).toLocaleString()}}
付款时间: {{new Date(order.pay_time).toLocaleString()}}
订单号:
{{order.order_number}}
订单状态显示分析
根据订单状态显示:
1. 如果未支付[order.order_stauts=0],则显示"去支付"按钮
2. 如果已支付[order.order_stauts=1],则显示"去学习"按钮
3. 如果未支付,并超过指定时间[12个小时],则显示"已取消" [celery+RabbitMQ / Django-crontab 定时任务 ]
用户下单在12小时以后自动判断订单状态如果是0,则直接改成3