加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Python > 正文

day88:luffy:支付宝同步结果通知&接收异步支付结果&用户

发布时间:2020-12-20 09:59:13 所属栏目:Python 来源:网络整理
导读:目录 1.支付宝同步结果通知 2.用户购买记录表 3.接受异步支付结果 4.善后事宜 5.我的订单 1.支付宝同步结果通知 1.get请求支付宝,支付宝返回给你的参数 当用户输入用户名和密码确认支付的时候,支付宝会给vue前端回复一个url,这个url很长,后面包含了很多

目录

1.支付宝同步结果通知

2.用户购买记录表

3.接受异步支付结果

4.善后事宜

5.我的订单

1.支付宝同步结果通知

1.get请求支付宝,支付宝返回给你的参数

当用户输入用户名和密码确认支付的时候,支付宝会给vue前端回复一个url,这个url很长,后面包含了很多参数,参数如下所示:

http://www.luffycity.cn:8080/payments/result?
charset=utf8&
out_trade_no=20190929151453000001000020&
method=alipay.trade.page.pay.return&
total_amount=310.00&
sign=kebIZBI%2FpCNXmCivfJPPw21gcobulPZoSh%2BXiHR8l6cgexQi2STG4AZgr%2FEUhvc5kEMacJLvCmBaw1Wqo4WK3sPzbUaPmzq3NshUNzYK2lWTsmOauidNxlk1bK0Q%2FANBfQUkmj6TQjyB5T9QqEnS80KFsDrGrasU%2B%2Fz9W%2FjOCLrSji6TnKhRkI9pqBMdw823ABU75b7zOtXzcXKduO%2B6vsXVvluMzedss9dHs1celxPAWQV9jcKjzq%2F1bPbZcmgAGNQQecoJ%2BFSc3uTmTk24uV39PM54LIlg8aeRlkPNjvhBkJh%2FG0%2BURNDdG2593IFIF%2BUqoU%2F7ixm19dX222GCWg%3D%3D&
trade_no=2019092922001439881000120282&
auth_app_id=2016091600523592&
version=1.0&
app_id=
sign_type=RSA2&
seller_id=2088102175868026&
timestamp=2019-09-29%2015%3A15%3A53

这些参数的含义:https://opendocs.alipay.com/apis/api_1/alipay.trade.page.pay

2.后端实现处理支付宝同步通知结果的视图

支付宝将参数传递给了vue前端,vue前端要这些参数发送给后端,让后端去对这些参数做一个校验。判断这个url是不是支付宝发过来的

后端校验支付宝返回给你的那些参数

payment/urls.py

from django.urls import path,re_path
from .  views

urlpatterns = [
    path('result/',views.AlipayResultView.as_view(),)
]

payment/view.py

class AlipayResultView(APIView):
    permission_classes = [IsAuthenticated,]
    def get(self,request):
        
        # 1.创建alipay对象
        alipay = AliPay(
            appid=settings.ALIAPY_CONFIG[appid],app_notify_url=None, 默认回调url
            app_private_key_string=open(settings.ALIAPY_CONFIG[app_private_key_path]).read(), 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,
            alipay_public_key_string=open(settings.ALIAPY_CONFIG[alipay_public_key_pathsign_type'],1)"> RSA 或者 RSA2
            debug=settings.ALIAPY_CONFIG[debug 默认False
        )
         2.校验支付宝响应数据
        data = request.query_params.dict()  获取那一大堆的参数
        
        out_trade_no = data.get(out_trade_no')  获取商户订单号
        sign = data.pop(sign 获取签名
        success = alipay.verify(data,sign)  通过参数和签名来验证那一堆参数是不是支付宝发过来的
        if not success:
            logger.error(%s,支付宝响应数据校验失败' % out_trade_no)
            return Response(支付宝响应数据校验失败',status=status.HTTP_400_BAD_REQUEST)

          响应结果
        return Response({msg':okdata:res_data})



 

3.vue前端发送请求验证get参数

前端发送请求 将支付宝发给vue前端的一大堆参数传递到后端,后端做完校验返回一个成功与否的结果

如果校验没有问题 就可以显示购买成功了。

Success.vue

created(){
      // 把地址栏上面的支付结果,转发给后端
      this.send_alipay_params();

methods:{
      send_alipay_params(){
        let token = localStorage.token || sessionStorage.token;
        this.$axios.get(`${this.$settings.Host}/payment/result/${location.search}`,{
          headers:{
              'Authorization':'jwt ' + token
            }
        }).then((res)=>{  如果后端验证这些参数没有问题 购买成功页面需要的参数就可以传递过来了
          this.pay_time = res.data.data.pay_time;  支付时间
          this.course_list = res.data.data.course_list;  购买课程列表
          this.total_real_price = res.data.data.total_real_price;  课程总真实价格
        }).catch((error)=>{
          .$message.error(error.response.data.msg);
        })
      },

2.用户购买记录表

当用户购买成功之后,应该生成用户记录,主要用来存支付平台的流水号,有了这个流水号就可以去支付宝查账单了。以及课程的购买时间和过期时间。

users/models.py

 UserCourse(BaseModel):
    """用户的课程购买记录"""
    pay_choices = (
        (1,1)">用户购买),(2,1)">免费活动活动赠品系统赠送user_courses"用户")
    course = models.ForeignKey(Course,1)">course_users课程)
    trade_no = models.CharField(max_length=128,null=True,blank=True,1)">支付平台的流水号",help_text=将来依靠流水号到支付平台查账单)
    buy_type = models.SmallIntegerField(choices=pay_choices,default=1,1)">购买方式)
    pay_time = models.DateTimeField(null=True,1)">购买时间)
    out_time = models.DateTimeField(null=True,1)">过期时间")  null表示永不过期

     Meta:
        db_table = ly_user_course
        verbose_name = 课程购买记录
        verbose_name_plural = verbose_name

3.接受异步支付结果

payment/views.py

 post(self,1)"> 创建alipay对象
        alipay =        )
        
         校验支付宝响应数据
        data = request.data.dict()
        sign = data.pop()
        success = alipay.verify(data,sign)
        if success and data[trade_status"] in (TRADE_SUCCESSTRADE_FINISHED):

            self.change_order_status(data)

            success')

4.善后事宜

当一切都完成后,还有几件事情要做:

1.修改订单状态

2.扣除优惠劵 积分

3.清空购物车数据和结算页面全部数据

4.将相关信息存到用户购买记录表中

AlipayResultView(APIView): def change_order_status(self,data): 修改订单状态 with transaction.atomic(): out_trade_no = data.get() trade_no = data.get(trade_no) A.修改订单状态 1.获取当前订单号的订单对象 order_obj = Order.objects.get(order_number=out_trade_no) 2.将当前订单的订单状态改为1:已支付 order_obj.order_status = 1 3.保存订单信息 order_obj.save() B.修改优惠券的使用状态 if order_obj.coupon > 0: 如果用户使用了优惠劵 1.获取用户使用的那张优惠劵对象 user_coupon_obj = UserCoupon.objects.get(is_use=False,id=order_obj.coupon) 2.将用户使用的那张优惠劵的状态由未使用改为已使用 user_coupon_obj.is_use = True 3.保存用户的优惠劵的信息 user_coupon_obj.save() C.支付成功,用户积分应该对应的扣除 1.查询当前订单使用了多少积分 use_credit = order_obj.credit 2.查询到用户的总积分数减去使用的积分数得到用户的剩余积分数 self.request.user.credit -= use_credit 3.保存用户的积分信息 self.request.user.save() D.保存支付宝的交易流水号(购买记录表) 1.通过订单对象反向查询到所有的订单详情对象 order_detail_objs = order_obj.order_courses.all() 2.获取当前时间 now = datetime.datetime.now() 购买成功 从redis中将课程的选中状态删除掉 conn = get_redis_connection(cart) pipe = conn.pipeline() pipe.delete(selected_cart_%s self.request.user.id) 需要给购买成功页面(Success.vue返回的数据) res_data = { pay_time: now,course_list: [],1)">total_real_price: order_obj.real_price,} for order_detail in order_detail_objs: 购买成功 课程学习的学生数+1 course = order_detail.course course.students += 1 course.save() 购买成功的课程应该显示课程列表的每个课程 res_data[].append(course.name) 从课程详情页获取当前课程的有效期数值 expire_id = order_detail.expire if expire_id > 0: 如果不是永久有效 根据expire_id查询到课程有效期model对象 expire_obj = CourseExpire.objects.get(id=expire_id) 查询到课程的有效期(天数) expire_time = expire_obj.expire_time 计算课程的过期时间 out_time = now + datetime.timedelta(days=expire_time) else: 如果是永久有效,就没有过期时间 out_time = None 一切处理完毕,将相关信息存到用户购买记录表中 UserCourse.objects.create(**{ user:self.request.user,1)">course:course,1)">:trade_no,1)">buy_type':1:now,1)">out_time:out_time,})  购物车redis数据删除 pipe.hdel(cart_%s self.request.user.id,course.id) pipe.execute() return res_data

order/serializers.py

 create:
    order_obj.coupon = coupon_id
    order_obj.credit = credit
    order_obj.save()

5.我的订单

1.我的订单界面-初始化

Myorder.vue

<template>
  <div class=user-order">
    <Vheader/>
    <div main">
        <div banner"></div>
          <div profile">
              <div profile-info">
                  <div avatar"><img newImg" width=100%" alt="" src=../../static/img/logo@2x.png"></div>
                  <span user-name">吴某某</span>
                  <span user-job">北京市 | 程序员</span>
              </div>
              <ul my-item">
                  <li>我的账户</li>
                  <li active">我的订单</li>
                  <li>个人资料</li>
                  <li>账号安全</li>
              </ul>
            </div>
            <div user-data">
              <ul nav">
                <li order-info">订单</li>
                <li course-expire">有效期</li>
                <li course-price">课程价格</li>
                <li real-price">实付金额</li>
                <li order-status">交易状态</li>
                <li order-do">交易操作</li>
              </ul>
              <div my-order-item" v-for=(order_obj,index) in order_list" :key=indexuser-data-header">
                    <span order-time">xxxx</span>
                    <span order-num">订单号:
                        <span my-older-number">xxxx</span>
                    </span>
                  </div>
                  <ul nav user-data-list(course_obj,course_index) in order_obj.order_detail_data">
                  <li ">
                      <img :src=course_obj.course_img"">
                      <div order-info-title">
                        <p course-title">xxxx</p>
                        <p price-service">xxxx</p>
                      </div>
                  </li>
                  <li ">xxxx</li>
                  <li btn btn2if=order_obj.get_order_status_display==='已支付'">去学习</span>
                    <span else-order_obj.get_order_status_display==='未支付'" @click=go_pay(order_obj.order_number)">去付款</span>
                    <span order_obj.get_order_status_display==='超时取消'">超时取消</span>
                    <span else>已取消</span>
                  </li>
                </ul>
              </div>
          </div>
    </div>
    <Footer/>
  </div>
</template>

<script>
  import Vheader from ./common/Vheader"
  import Footer ./common/Footer
  export default{
    name:Myorderreturn {
       

      };
    },created(){
  

    },methods:{

     
    },components:{
      Vheader,Footer,}
  }
</script>

<style scoped>
.main .banner{
    width: 100%;
    height: 324px;
    background: url(../../static/img/my_bkging.0648ebe.png) no-repeat;
    background-size: cover;
    z-index: 1;
}
.profile{
    width: 1200px;
    margin: 0 auto;
}
.profile-info{
    text-align: center;
    margin-top: -80px;
}
.avatar{
    width: 120px;
    height: 120px;
    border-radius: 60px;
    overflow: hidden;
    margin: 0 auto;
}
.user-name{
    display: block;
    font-size: 24px;
    color: 4a4a4a;
    margin-top: 14px;
}
.user-job{
    display: block;
    font-size: 11px;
    color: 9b9b9b;
 }
.my-item{
    list-style: none;
    line-height: 1.42857143;
    color: 333;
    width: 474px;
    height: 31px;
    display: -ms-flexbox;
    display: flex;
    cursor: pointer;
    margin: 41px auto 0;
    -ms-flex-pack: justify;
    justify-content: space-between;
}
.my-item .active{
    border-bottom: 1px solid 000;
}
.user-data{
    width: 1200px;
    height: auto;
    margin: 0 auto;
    padding-top: 30px;
    border-top: 1px solid e8e8e8;
    margin-bottom: 63px;
}
.nav{
    width: 100%;
    height: 60px;
    background: e9e9e9;
    display: -ms-flexbox;
    display: flex;
    -ms-flex-align: center;
    align-items: center;
}
.nav li{
    margin-left: 20px;
    margin-right: 28px;
    height: 60px;
    line-height: 60px;
    list-style: none;
    font-size: 13px;
    color: 333;
    border-bottom: 1px solid e9e9e9;
  width: 160px;
}
.nav .order-info{ width: 325px; }
.nav .course-expire{ width: 60px; }
.nav .course-price{ width: 130px; }
.user-data-header{
    display: flex;
    height: 44px;
    color: 4a4a4a;
    font-size: 14px;
    background: f3f3f3;
    -ms-flex-items: center;
}
.order-time{
    font-size: 12px;
    display: inline-block;
    margin-left: 20px;
}
.order-num{
    font-left: 29px;
}
.user-data-list{
    height: 100%;
    display: flex;
}
.user-data-list{
  background: none;
}
.user-data-list li{
    height: 60px;
    line-height: 60px;
}
.user-data-list .order-info{
    display: flex;
    align-items: center;
    margin-right: 28px;
}
.user-data-list .order-info img{
    max-width: 100px;
    max-height: 75px;
    margin-right: 22px;
}
.course-title{
    width: 203px;
    font-333;
    line-height: 5px;
    margin-top: -10px;
}
.order-info-title .price-service{
    line-height: 18px;
}
.price-service{
    font-size: 12px;
    color: fa6240;
    padding: 0 5px;
    border: 1px solid fa6240;
    border-radius: 4px;
    margin-top: 4px;
    position: absolute;
}
.order-info-title{
    margin-top: -10px;
}
.user-data-list .course-expire{
    font-ff5502;
    width: 60px;
    text-align: center;
}
.btn {
  width: 100px;
  height: 32px;
  font-size: 14px;
  color: fff;
  background: ffc210;
  border-radius: 4px;
  border: none;
  outline: none;
  transition: all .25s ease;
  display: inline-block;
  line-height: 32px;
  text-align: center;
  cursor: pointer;
}
</style>
我的订单页面-初始化

index.js

{
      path: '/myorder/'2.我的订单页面-后端接口

users/urls.py

urlpatterns = [
    path(rmyorder/users/views.py

 MyOrderView(ListAPIView):
    permission_classes = MyOrderModelSerializer

     get_queryset(self):
        return Order.objects.filter(user=self.request.user)

user/serializers.py

 MyOrderModelSerializer(serializers.ModelSerializer):
     Meta:
        model = Order
        fields = [idorder_numberget_order_status_displayorder_detail_data']

order/models.py

在我的订单页面中,需要展示一些数据

 Order(BaseModel):
     order_detail_data(self):
         获取所有课程详情对象
        order_detail_objs = self.order_courses.all()
        data_list = []

         order_detail_objs:
            expire_id = order_detail.expire
            
             根据有效期来决定expire_text返回什么
            if expire_id > 0:
                expire_obj = CourseExpire.objects.get(id=expire_id)
                expire_text = expire_obj.expire_text
            else:
                expire_text = 永久有效'
        
             每个课程应该包含的字段
            order_dict = {
                course_img':contains.SERVER_ADDR + order_detail.course.course_img.url,1)">course_name:order_detail.course.name,1)">expire_text:expire_text,1)">price:order_detail.price,1)">real_price: self.real_price,1)">discount_name:order_detail.discount_name,}
             将每个课程的详情信息添加到一个列表里返回给前端
            data_list.append(order_dict)

         data_list
    

3.我的订单页面-前端

1.获取后端的订单数据

Myorder.vue

 js
get_order_data(){
         检查当前访问者是否登录了!
        let token = localStorage.token ||this.$settings.Host}/users/myorder/`,1)"> token
            }
        }).then((res)=>this.order_list = res.data;
        }).{

        })
<!-- html -->
<div ="my-order-item" v-for="(order_obj,index) in order_list" :key="index">
    ="user-data-header">
        span ="order-time">{{order_obj.pay_time.replace('T',' ')}}</span="order-num">订单号:
            ="my-older-number">{{order_obj.order_number}}divul ="nav user-data-list"="(course_obj,course_index) in order_obj.order_detail_data"li ="order-info">
            img :src="course_obj.course_img" alt=""="order-info-title">
                p ="course-title">{{course_obj.course_name}}p="price-service">{{course_obj.discount_name}}li="course-expire">{{course_obj.expire_text}}="course-price">{{course_obj.price}}="real-price">{{course_obj.real_price}}="order-status">{{order_obj.get_order_status_display}}="order-do"="btn btn2" v-if="order_obj.get_order_status_display==='已支付'">去学习 v-else-if="order_obj.get_order_status_display==='未支付'" @click="go_pay(order_obj.order_number)">去付款="order_obj.get_order_status_display==='超时取消'">超时取消 v-else>已取消ul>
>
         

2.我的订单页面点击去付款

>

go_pay(order_number){
        let token = localStorage.token ||this.$settings.Host}/payment/alipay/?order_number=${order_number}`,1)">              headers:{
              'Authorization':'jwt ' + token
            }

        }).then((res)=>{
          location.href = res.data.url;

        })..$message.error(error.response.data.msg);
        })

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读