DJANGO-天天生鲜项目从0到1-013-订单-支付宝支付

本项目基于B站UP主‘神奇的老黄’的教学视频‘天天生鲜Django项目’,视频讲的非常好,推荐新手观看学习

https://www.bilibili.com/video/BV1vt41147K8?p=1

订单页面支付JS

1. 点击‘去支付’按钮,发送ajax请求,后台视图调用支付宝支付接口时,返回的是一个支付界面的url,需要通过window.open(data.pay_url),引导用户浏览器打开支付宝返回的支付url

2. 引导完url之后,继续发送查询ajax请求,后台视图调用支付宝查询接口,若查到支付成功,则alert(‘支付成功’)并刷新界面 location.reload()

{% block endfiles %}
<script type="text/javascript" src="{% static 'js/jquery-1.12.4.min.js'%}"></script>
<script type="text/javascript">
    //根据订单状态显示下一步操作
    $('.oper_btn').each(function(){
        status = $(this).attr('order_status')
        if (status == '1'){
            oper_show = '去支付'
        }
        else if (status =='4'){
            oper_show = '去评价'
        }
        else{
            oper_show = $(this).attr('status_name')
        }
        $(this).text(oper_show)
    })
    //去支付按钮
    $('.oper_btn').click(function(){
        //获取订单ID
        order_id = $(this).attr('order_id')
        //若状态为待支付,则发送ajax支付请求
        if ($(this).attr('order_status') =='1'){
            pay_method = $(this).attr('pay_method')
            send_pay_ajax(order_id, pay_method)
        }
        //若状态为待评价,则跳转到评价界面
        else if($(this).attr('order_status') == '4'){
            //跳转到评价页面
            location.href = '/order/comment/'+order_id
        }
    })
    //支付发送ajax请求
    function send_pay_ajax(order_id, pay_method){
        csrf = $('input[name="csrfmiddlewaretoken"]').val()
        parameter = {
            'order_id': order_id,
            'csrfmiddlewaretoken': csrf,
        }
        if (pay_method == '3'){
            //支付宝支付
            $.post('/order/alipay/', parameter, function(data){
                //回调函数
                if (data.status == 'S'){
                    //引导用户到支付界面
                    window.open(data.pay_url)
                    //发送ajax请求查询订单支付情况
                    $.post('/order/check/', parameter, function(data){
                        if (data.status == 'S'){
                            alert('支付成功')
                            location.reload()
                        }
                        else{
                            alert(data.errmsg)
                        }
                    })
                }
                else{
                    alert(data.errmsg)
                }
            })
        }
        else{
            //其他支付方式
            alert('其他支付方式暂不支持!')
        }
    }
</script>
{% endblock endfiles %}

 调用支付宝接口

创建支付宝应用

登录支付宝开放平台,进入沙箱环境,沙箱环境即为支付宝给外接系统提供的虚拟开发环境,并默认分配了一个应用,因此不需要再创建应用,而正是支付宝环境需要创建应用并审核。

设置应用密钥

支付需要有三个密钥:

  应用的私钥:将发送给支付宝的数据用自己的私钥加密。

  应用的公钥:与应用的私钥配对使用,将加密后的数据发送给支付宝时,同时将公钥也发送给支付宝,让支付宝使用该公钥进行解密。

  支付宝的公钥:支付宝解密后,再用支付宝自己的私钥进行加密并发送给接口调用方(应用),应用再使用支付宝公钥进行解密。

生成密钥和私钥,可以使用‘支付宝开放平台开发助手’生成,下载路径为:https://opendocs.alipay.com/open/291/105971

密钥格式选择“PKCS1(非Java适用)”,点击生成密钥后,点击‘打开密钥文件路径’,可以查看到生成的公钥和私钥,保存好这两个文件。

进入沙箱环境,设置应用的密钥,将应用公钥添加进去,同时会返回一个支付宝公钥

 沙箱账号

沙箱环境也提供了两个账号,分别是买方和卖方的账号,后续进行支付交易时可以使用买方账号

 安装官方SDK

支付宝SDK路径:https://opendocs.alipay.com/open/54/103419#Alipay%20SDK, 支付宝官方也提供了支持python的SDK(alipay-sdk-python):https://pypi.org/project/alipay-sdk-python/3.3.398/,安装命令为

pip install alipay-sdk-python==3.3.398

编写调用代码

支付宝接口所有API文档地址:https://opendocs.alipay.com/apis/api_1/alipay.trade.pay,这里我们使用"alipay.trade.page.pay(统一收单下单并支付页面接口)",这个接口会返回一个支付界面的URL,引导用户进入该URL,并登录支付宝账号完成支付,注意不是"alipay.trade.page.pay(统一收单下单并支付页面接口)",这个下单并支付接口是直接将买方账户信息也放入发送数据中,返回的是支付的结果,而不是返回支付页面的链接让用户自己登陆。

编辑order/views.py文件,支付宝所有接口调用代码都分为4个部分:

1. 导入相关包

客户端相关包、模型相关包、请求相关包

import logging
from alipay.aop.api.AlipayClientConfig import AlipayClientConfig
from alipay.aop.api.DefaultAlipayClient import DefaultAlipayClient
from alipay.aop.api.domain.AlipayTradePagePayModel import AlipayTradePagePayModel
from alipay.aop.api.request.AlipayTradePagePayRequest import AlipayTradePagePayRequest

2. 创建(实例化)客户端

 这里将创建客户端需要的一些参数配置在了settings.py文件中

# 记录日志
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s %(levelname)s %(message)s',
filemode='a',)
logger = logging.getLogger('')
# 实例化客户端
alipay_client_config = AlipayClientConfig()
alipay_client_config.server_url = settings.ALIPAY_SERVER_URL
alipay_client_config.app_id = settings.ALIPAY_APP_ID
alipay_client_config.app_private_key = settings.ALIPAY_PRIVATE_KEY
alipay_client_config.alipay_public_key = settings.ALIPAY_PUBLIC_KEY
client = DefaultAlipayClient(alipay_client_config, logger)

settings.py配置

# 支付宝支付设置-沙箱环境
# 支付宝网关,正式环境网关去掉dev三个字母
ALIPAY_SERVER_URL = 'https://openapi.alipaydev.com/gateway.do'
# 应用ID
ALIPAY_APP_ID = '2016102200739747'
# 应用私钥
ALIPAY_PRIVATE_KEY = 'XXXXXX'
# 支付宝公钥
ALIPAY_PUBLIC_KEY = 'XXXXXXX'
# 订单超时时间:如果买家超过这个时间不付款,会关闭交易(最小1m分钟)
ALIPAY_EXPRESS = '10m'

3. 创建支付模型

# 构造请求参数对象
model = AlipayTradePagePayModel()
# 调用方系统生成的订单编号
model.out_trade_no = order.order_num;
# 支付金额
model.total_amount = str(order.total_amount);
# 支付标题
model.subject = "天天生鲜";
#与支付宝签约的产品码名称,目前只支持这一种。 model.product_code = 'FAST_INSTANT_TRADE_PAY' # 订单过期关闭时长(分钟) model.timeout_express = settings.ALIPAY_EXPRESS

4. 调用业务API

# 创建请求对象
request = AlipayTradePagePayRequest(biz_model=model)
# 设置回调通知地址(GET)
request.return_url = settings.ALIPAY_RETURN_URL
# 设置回调通知地址(POST)
request.notify_url = settings.ALIPAY_NOTIFY_URL
# 执行API调用,获取支付连接
pay_url = client.page_execute(request, http_method='GET')
return pay_url

完整支付类视图(OrderAlipayView)代码为:

# 支付宝支付 start
import logging
from alipay.aop.api.AlipayClientConfig import AlipayClientConfig
from alipay.aop.api.DefaultAlipayClient import DefaultAlipayClient
from alipay.aop.api.domain.AlipayTradePagePayModel import AlipayTradePagePayModel
from alipay.aop.api.request.AlipayTradePagePayRequest import AlipayTradePagePayRequest


def alipay_init():
    '''支付宝初始化'''
    # 记录日志
    logging.basicConfig(
        level=logging.INFO,
        format='%(asctime)s %(levelname)s %(message)s',
        filemode='a',)
    logger = logging.getLogger('')
    # 实例化客户端
    alipay_client_config = AlipayClientConfig()
    alipay_client_config.server_url = settings.ALIPAY_SERVER_URL
    alipay_client_config.app_id = settings.ALIPAY_APP_ID
    alipay_client_config.app_private_key = settings.ALIPAY_PRIVATE_KEY
    alipay_client_config.alipay_public_key = settings.ALIPAY_PUBLIC_KEY
    client = DefaultAlipayClient(alipay_client_config, logger)
    return client

def alipay_pay(order):
    '''支付宝支付'''
    client = alipay_init()
    # 构造请求参数对象
    model = AlipayTradePagePayModel()
    # 调用方系统生成的订单编号
    model.out_trade_no = order.order_num;
    # 支付金额
    model.total_amount = str(order.total_amount);
    # 支付标题
    model.subject = "天天生鲜";
    #与支付宝签约的产品码名称,目前只支持这一种。
    model.product_code = 'FAST_INSTANT_TRADE_PAY'
    # 订单过期关闭时长(分钟)
    model.timeout_express = settings.ALIPAY_EXPRESS
    # 创建请求对象
    request = AlipayTradePagePayRequest(biz_model=model)
    # 设置回调通知地址(GET)
    request.return_url = settings.ALIPAY_RETURN_URL
    # 设置回调通知地址(POST)
    request.notify_url = settings.ALIPAY_NOTIFY_URL
    # 执行API调用,获取支付连接
    pay_url = client.page_execute(request, http_method='GET')
    return pay_url


class OrderAlipayView(View):
    '''支付视图'''
    def post(self, request):
        '''支付处理'''
        context = {
            'status': 'E',
            'errmsg': '',
        }
        user = request.user
        if not user.is_authenticated:
            context['errmsg'] = '用户未登录!'
            return JsonResponse(context)
        # 接收数据
        order_id = int(request.POST.get('order_id'))

        # 校验数据
        try:
            order = OrderInfo.objects.get(id=order_id)
        except OrderInfo.DoesNotExist:
            context['errmsg'] = '订单不存在!'
            return JsonResponse(context)

        # 业务处理
        pay_url = alipay_pay(order)

        # 返回应答
        context['status'] = 'S'
        context['pay_url'] = pay_url
        return JsonResponse(context)

以上代码完成之后即可将返回的pay_url传递给前端,前端通过window.open(data.pay_url),引导用户浏览器打开支付宝返回的支付url,让用户进行登录支付。同时发送查询支付结果的请求,若监控到支付成功,则刷新订单页面

编写查询支付宝支付结果代码

完整查询类视图(OrderCheckView)代码为:

from alipay.aop.api.domain.AlipayTradeQueryModel import AlipayTradeQueryModel
from alipay.aop.api.request.AlipayTradeQueryRequest import AlipayTradeQueryRequest

def alipay_query(order, context):
    '''支付宝支付'''
    client = alipay_init()
    # 构造请求参数对象
    model = AlipayTradeQueryModel()
    model.out_trade_no = order.order_num;
    model.timeout_express = settings.ALIPAY_EXPRESS
    #与支付宝签约的产品码名称,目前只支持这一种。
    model.product_code = 'FAST_INSTANT_TRADE_PAY'
    request = AlipayTradeQueryRequest(biz_model=model)

    while True:
        # 执行API调用
        response = client.execute(request)
        # str转换为字典
        response = eval(response)
        code = response.get('code')
        sub_code = response.get('sub_code')
        sub_msg = response.get('sub_msg')
        trade_status = response.get('trade_status')
        if sub_code == 'ACQ.TRADE_NOT_EXIST' or (code == '10000' and
                                                 trade_status ==
                                                 'WAIT_BUYER_PAY'):
            # 交易不存在,或状态为等待买家付款则继续等待用户付款
            time.sleep(5)
            continue
        elif code == '10000' and trade_status == 'TRADE_SUCCESS':
            # 支付成功
            context['status'] = 'S'
            trade_no = response.get('trade_no')
            # 回写订单支付号
            order.trade_no = trade_no
            order.order_status = 4 # 待评价
            order.save()
            break
        else:
            context['errmsg'] = '支付失败:%s-%s' % (sub_code, sub_msg)
            break


class OrderCheckView(View):
    '''查询支付宝支付情况'''
    def post(self, request):
        context = {
            'status': 'E',
            'errmsg': ''
        }
        user = request.user
        if not user.is_authenticated:
            context['errmsg'] = '用户未登录!'
            return JsonResponse(context)
        # 接收数据
        order_id = int(request.POST.get('order_id'))
        try:
            order = OrderInfo.objects.get(id=order_id)
        except Exception as e:
            context['errmsg'] = '订单不存在!'
            return JsonResponse(context)

        # 执行查询
        alipay_query(order, context)
        return JsonResponse(context)

1. 查询时,因为用户付款需要一定的时间,所以使用循环,每5秒查询一次

2. 查询换回的结果字符串‘str’,因此需要将其转换为字典

3. 返回的主要字段包括:code(返回码,如10000) 、sub_code(子返回码,如ACQ.TRADE_NOT_EXIST)、trade_status(交易状态,如:'WAIT_BUYER_PAY')

4. 当用户还未登陆支付宝时,code为40004、sub_code为ACQ.TRADE_NOT_EXIST(交易不存在),当用户登录后,code为10000,trade_status为WAIT_BUYER_PAY(等待用户付款),当付款成功后,trade_status为TRADE_SUCCESS

https://www.bilibili.com/video/BV1vt41147K8?p=1

订单页面支付JS

1. 点击‘去支付’按钮,发送ajax请求,后台视图调用支付宝支付接口时,返回的是一个支付界面的url,需要通过window.open(data.pay_url),引导用户浏览器打开支付宝返回的支付url

2. 引导完url之后,继续发送查询ajax请求,后台视图调用支付宝查询接口,若查到支付成功,则alert(‘支付成功’)并刷新界面 location.reload()

{% block endfiles %}
<script type="text/javascript" src="{% static 'js/jquery-1.12.4.min.js'%}"></script>
<script type="text/javascript">
    //根据订单状态显示下一步操作
    $('.oper_btn').each(function(){
        status = $(this).attr('order_status')
        if (status == '1'){
            oper_show = '去支付'
        }
        else if (status =='4'){
            oper_show = '去评价'
        }
        else{
            oper_show = $(this).attr('status_name')
        }
        $(this).text(oper_show)
    })
    //去支付按钮
    $('.oper_btn').click(function(){
        //获取订单ID
        order_id = $(this).attr('order_id')
        //若状态为待支付,则发送ajax支付请求
        if ($(this).attr('order_status') =='1'){
            pay_method = $(this).attr('pay_method')
            send_pay_ajax(order_id, pay_method)
        }
        //若状态为待评价,则跳转到评价界面
        else if($(this).attr('order_status') == '4'){
            //跳转到评价页面
            location.href = '/order/comment/'+order_id
        }
    })
    //支付发送ajax请求
    function send_pay_ajax(order_id, pay_method){
        csrf = $('input[name="csrfmiddlewaretoken"]').val()
        parameter = {
            'order_id': order_id,
            'csrfmiddlewaretoken': csrf,
        }
        if (pay_method == '3'){
            //支付宝支付
            $.post('/order/alipay/', parameter, function(data){
                //回调函数
                if (data.status == 'S'){
                    //引导用户到支付界面
                    window.open(data.pay_url)
                    //发送ajax请求查询订单支付情况
                    $.post('/order/check/', parameter, function(data){
                        if (data.status == 'S'){
                            alert('支付成功')
                            location.reload()
                        }
                        else{
                            alert(data.errmsg)
                        }
                    })
                }
                else{
                    alert(data.errmsg)
                }
            })
        }
        else{
            //其他支付方式
            alert('其他支付方式暂不支持!')
        }
    }
</script>
{% endblock endfiles %}

 调用支付宝接口

创建支付宝应用

登录支付宝开放平台,进入沙箱环境,沙箱环境即为支付宝给外接系统提供的虚拟开发环境,并默认分配了一个应用,因此不需要再创建应用,而正是支付宝环境需要创建应用并审核。

设置应用密钥

支付需要有三个密钥:

  应用的私钥:将发送给支付宝的数据用自己的私钥加密。

  应用的公钥:与应用的私钥配对使用,将加密后的数据发送给支付宝时,同时将公钥也发送给支付宝,让支付宝使用该公钥进行解密。

  支付宝的公钥:支付宝解密后,再用支付宝自己的私钥进行加密并发送给接口调用方(应用),应用再使用支付宝公钥进行解密。

生成密钥和私钥,可以使用‘支付宝开放平台开发助手’生成,下载路径为:https://opendocs.alipay.com/open/291/105971

密钥格式选择“PKCS1(非Java适用)”,点击生成密钥后,点击‘打开密钥文件路径’,可以查看到生成的公钥和私钥,保存好这两个文件。

进入沙箱环境,设置应用的密钥,将应用公钥添加进去,同时会返回一个支付宝公钥

 沙箱账号

沙箱环境也提供了两个账号,分别是买方和卖方的账号,后续进行支付交易时可以使用买方账号

 安装官方SDK

支付宝SDK路径:https://opendocs.alipay.com/open/54/103419#Alipay%20SDK, 支付宝官方也提供了支持python的SDK(alipay-sdk-python):https://pypi.org/project/alipay-sdk-python/3.3.398/,安装命令为

pip install alipay-sdk-python==3.3.398

编写调用代码

支付宝接口所有API文档地址:https://opendocs.alipay.com/apis/api_1/alipay.trade.pay,这里我们使用"alipay.trade.page.pay(统一收单下单并支付页面接口)",这个接口会返回一个支付界面的URL,引导用户进入该URL,并登录支付宝账号完成支付,注意不是"alipay.trade.page.pay(统一收单下单并支付页面接口)",这个下单并支付接口是直接将买方账户信息也放入发送数据中,返回的是支付的结果,而不是返回支付页面的链接让用户自己登陆。

编辑order/views.py文件,支付宝所有接口调用代码都分为4个部分:

1. 导入相关包

客户端相关包、模型相关包、请求相关包

import logging
from alipay.aop.api.AlipayClientConfig import AlipayClientConfig
from alipay.aop.api.DefaultAlipayClient import DefaultAlipayClient
from alipay.aop.api.domain.AlipayTradePagePayModel import AlipayTradePagePayModel
from alipay.aop.api.request.AlipayTradePagePayRequest import AlipayTradePagePayRequest

2. 创建(实例化)客户端

 这里将创建客户端需要的一些参数配置在了settings.py文件中

# 记录日志
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s %(levelname)s %(message)s',
filemode='a',)
logger = logging.getLogger('')
# 实例化客户端
alipay_client_config = AlipayClientConfig()
alipay_client_config.server_url = settings.ALIPAY_SERVER_URL
alipay_client_config.app_id = settings.ALIPAY_APP_ID
alipay_client_config.app_private_key = settings.ALIPAY_PRIVATE_KEY
alipay_client_config.alipay_public_key = settings.ALIPAY_PUBLIC_KEY
client = DefaultAlipayClient(alipay_client_config, logger)

settings.py配置

# 支付宝支付设置-沙箱环境
# 支付宝网关,正式环境网关去掉dev三个字母
ALIPAY_SERVER_URL = 'https://openapi.alipaydev.com/gateway.do'
# 应用ID
ALIPAY_APP_ID = '2016102200739747'
# 应用私钥
ALIPAY_PRIVATE_KEY = 'XXXXXX'
# 支付宝公钥
ALIPAY_PUBLIC_KEY = 'XXXXXXX'
# 订单超时时间:如果买家超过这个时间不付款,会关闭交易(最小1m分钟)
ALIPAY_EXPRESS = '10m'

3. 创建支付模型

# 构造请求参数对象
model = AlipayTradePagePayModel()
# 调用方系统生成的订单编号
model.out_trade_no = order.order_num;
# 支付金额
model.total_amount = str(order.total_amount);
# 支付标题
model.subject = "天天生鲜";
#与支付宝签约的产品码名称,目前只支持这一种。 model.product_code = 'FAST_INSTANT_TRADE_PAY' # 订单过期关闭时长(分钟) model.timeout_express = settings.ALIPAY_EXPRESS

4. 调用业务API

# 创建请求对象
request = AlipayTradePagePayRequest(biz_model=model)
# 设置回调通知地址(GET)
request.return_url = settings.ALIPAY_RETURN_URL
# 设置回调通知地址(POST)
request.notify_url = settings.ALIPAY_NOTIFY_URL
# 执行API调用,获取支付连接
pay_url = client.page_execute(request, http_method='GET')
return pay_url

完整支付类视图(OrderAlipayView)代码为:

# 支付宝支付 start
import logging
from alipay.aop.api.AlipayClientConfig import AlipayClientConfig
from alipay.aop.api.DefaultAlipayClient import DefaultAlipayClient
from alipay.aop.api.domain.AlipayTradePagePayModel import AlipayTradePagePayModel
from alipay.aop.api.request.AlipayTradePagePayRequest import AlipayTradePagePayRequest


def alipay_init():
    '''支付宝初始化'''
    # 记录日志
    logging.basicConfig(
        level=logging.INFO,
        format='%(asctime)s %(levelname)s %(message)s',
        filemode='a',)
    logger = logging.getLogger('')
    # 实例化客户端
    alipay_client_config = AlipayClientConfig()
    alipay_client_config.server_url = settings.ALIPAY_SERVER_URL
    alipay_client_config.app_id = settings.ALIPAY_APP_ID
    alipay_client_config.app_private_key = settings.ALIPAY_PRIVATE_KEY
    alipay_client_config.alipay_public_key = settings.ALIPAY_PUBLIC_KEY
    client = DefaultAlipayClient(alipay_client_config, logger)
    return client

def alipay_pay(order):
    '''支付宝支付'''
    client = alipay_init()
    # 构造请求参数对象
    model = AlipayTradePagePayModel()
    # 调用方系统生成的订单编号
    model.out_trade_no = order.order_num;
    # 支付金额
    model.total_amount = str(order.total_amount);
    # 支付标题
    model.subject = "天天生鲜";
    #与支付宝签约的产品码名称,目前只支持这一种。
    model.product_code = 'FAST_INSTANT_TRADE_PAY'
    # 订单过期关闭时长(分钟)
    model.timeout_express = settings.ALIPAY_EXPRESS
    # 创建请求对象
    request = AlipayTradePagePayRequest(biz_model=model)
    # 设置回调通知地址(GET)
    request.return_url = settings.ALIPAY_RETURN_URL
    # 设置回调通知地址(POST)
    request.notify_url = settings.ALIPAY_NOTIFY_URL
    # 执行API调用,获取支付连接
    pay_url = client.page_execute(request, http_method='GET')
    return pay_url


class OrderAlipayView(View):
    '''支付视图'''
    def post(self, request):
        '''支付处理'''
        context = {
            'status': 'E',
            'errmsg': '',
        }
        user = request.user
        if not user.is_authenticated:
            context['errmsg'] = '用户未登录!'
            return JsonResponse(context)
        # 接收数据
        order_id = int(request.POST.get('order_id'))

        # 校验数据
        try:
            order = OrderInfo.objects.get(id=order_id)
        except OrderInfo.DoesNotExist:
            context['errmsg'] = '订单不存在!'
            return JsonResponse(context)

        # 业务处理
        pay_url = alipay_pay(order)

        # 返回应答
        context['status'] = 'S'
        context['pay_url'] = pay_url
        return JsonResponse(context)

以上代码完成之后即可将返回的pay_url传递给前端,前端通过window.open(data.pay_url),引导用户浏览器打开支付宝返回的支付url,让用户进行登录支付。同时发送查询支付结果的请求,若监控到支付成功,则刷新订单页面

编写查询支付宝支付结果代码

完整查询类视图(OrderCheckView)代码为:

from alipay.aop.api.domain.AlipayTradeQueryModel import AlipayTradeQueryModel
from alipay.aop.api.request.AlipayTradeQueryRequest import AlipayTradeQueryRequest

def alipay_query(order, context):
    '''支付宝支付'''
    client = alipay_init()
    # 构造请求参数对象
    model = AlipayTradeQueryModel()
    model.out_trade_no = order.order_num;
    model.timeout_express = settings.ALIPAY_EXPRESS
    #与支付宝签约的产品码名称,目前只支持这一种。
    model.product_code = 'FAST_INSTANT_TRADE_PAY'
    request = AlipayTradeQueryRequest(biz_model=model)

    while True:
        # 执行API调用
        response = client.execute(request)
        # str转换为字典
        response = eval(response)
        code = response.get('code')
        sub_code = response.get('sub_code')
        sub_msg = response.get('sub_msg')
        trade_status = response.get('trade_status')
        if sub_code == 'ACQ.TRADE_NOT_EXIST' or (code == '10000' and
                                                 trade_status ==
                                                 'WAIT_BUYER_PAY'):
            # 交易不存在,或状态为等待买家付款则继续等待用户付款
            time.sleep(5)
            continue
        elif code == '10000' and trade_status == 'TRADE_SUCCESS':
            # 支付成功
            context['status'] = 'S'
            trade_no = response.get('trade_no')
            # 回写订单支付号
            order.trade_no = trade_no
            order.order_status = 4 # 待评价
            order.save()
            break
        else:
            context['errmsg'] = '支付失败:%s-%s' % (sub_code, sub_msg)
            break


class OrderCheckView(View):
    '''查询支付宝支付情况'''
    def post(self, request):
        context = {
            'status': 'E',
            'errmsg': ''
        }
        user = request.user
        if not user.is_authenticated:
            context['errmsg'] = '用户未登录!'
            return JsonResponse(context)
        # 接收数据
        order_id = int(request.POST.get('order_id'))
        try:
            order = OrderInfo.objects.get(id=order_id)
        except Exception as e:
            context['errmsg'] = '订单不存在!'
            return JsonResponse(context)

        # 执行查询
        alipay_query(order, context)
        return JsonResponse(context)

1. 查询时,因为用户付款需要一定的时间,所以使用循环,每5秒查询一次

2. 查询换回的结果字符串‘str’,因此需要将其转换为字典

3. 返回的主要字段包括:code(返回码,如10000) 、sub_code(子返回码,如ACQ.TRADE_NOT_EXIST)、trade_status(交易状态,如:'WAIT_BUYER_PAY')

4. 当用户还未登陆支付宝时,code为40004、sub_code为ACQ.TRADE_NOT_EXIST(交易不存在),当用户登录后,code为10000,trade_status为WAIT_BUYER_PAY(等待用户付款),当付款成功后,trade_status为TRADE_SUCCESS

https://www.bilibili.com/video/BV1vt41147K8?p=1

订单页面支付JS

1. 点击‘去支付’按钮,发送ajax请求,后台视图调用支付宝支付接口时,返回的是一个支付界面的url,需要通过window.open(data.pay_url),引导用户浏览器打开支付宝返回的支付url

2. 引导完url之后,继续发送查询ajax请求,后台视图调用支付宝查询接口,若查到支付成功,则alert(‘支付成功’)并刷新界面 location.reload()

{% block endfiles %}
<script type="text/javascript" src="{% static 'js/jquery-1.12.4.min.js'%}"></script>
<script type="text/javascript">
    //根据订单状态显示下一步操作
    $('.oper_btn').each(function(){
        status = $(this).attr('order_status')
        if (status == '1'){
            oper_show = '去支付'
        }
        else if (status =='4'){
            oper_show = '去评价'
        }
        else{
            oper_show = $(this).attr('status_name')
        }
        $(this).text(oper_show)
    })
    //去支付按钮
    $('.oper_btn').click(function(){
        //获取订单ID
        order_id = $(this).attr('order_id')
        //若状态为待支付,则发送ajax支付请求
        if ($(this).attr('order_status') =='1'){
            pay_method = $(this).attr('pay_method')
            send_pay_ajax(order_id, pay_method)
        }
        //若状态为待评价,则跳转到评价界面
        else if($(this).attr('order_status') == '4'){
            //跳转到评价页面
            location.href = '/order/comment/'+order_id
        }
    })
    //支付发送ajax请求
    function send_pay_ajax(order_id, pay_method){
        csrf = $('input[name="csrfmiddlewaretoken"]').val()
        parameter = {
            'order_id': order_id,
            'csrfmiddlewaretoken': csrf,
        }
        if (pay_method == '3'){
            //支付宝支付
            $.post('/order/alipay/', parameter, function(data){
                //回调函数
                if (data.status == 'S'){
                    //引导用户到支付界面
                    window.open(data.pay_url)
                    //发送ajax请求查询订单支付情况
                    $.post('/order/check/', parameter, function(data){
                        if (data.status == 'S'){
                            alert('支付成功')
                            location.reload()
                        }
                        else{
                            alert(data.errmsg)
                        }
                    })
                }
                else{
                    alert(data.errmsg)
                }
            })
        }
        else{
            //其他支付方式
            alert('其他支付方式暂不支持!')
        }
    }
</script>
{% endblock endfiles %}

 调用支付宝接口

创建支付宝应用

登录支付宝开放平台,进入沙箱环境,沙箱环境即为支付宝给外接系统提供的虚拟开发环境,并默认分配了一个应用,因此不需要再创建应用,而正是支付宝环境需要创建应用并审核。

设置应用密钥

支付需要有三个密钥:

  应用的私钥:将发送给支付宝的数据用自己的私钥加密。

  应用的公钥:与应用的私钥配对使用,将加密后的数据发送给支付宝时,同时将公钥也发送给支付宝,让支付宝使用该公钥进行解密。

  支付宝的公钥:支付宝解密后,再用支付宝自己的私钥进行加密并发送给接口调用方(应用),应用再使用支付宝公钥进行解密。

生成密钥和私钥,可以使用‘支付宝开放平台开发助手’生成,下载路径为:https://opendocs.alipay.com/open/291/105971

密钥格式选择“PKCS1(非Java适用)”,点击生成密钥后,点击‘打开密钥文件路径’,可以查看到生成的公钥和私钥,保存好这两个文件。

进入沙箱环境,设置应用的密钥,将应用公钥添加进去,同时会返回一个支付宝公钥

 沙箱账号

沙箱环境也提供了两个账号,分别是买方和卖方的账号,后续进行支付交易时可以使用买方账号

 安装官方SDK

支付宝SDK路径:https://opendocs.alipay.com/open/54/103419#Alipay%20SDK, 支付宝官方也提供了支持python的SDK(alipay-sdk-python):https://pypi.org/project/alipay-sdk-python/3.3.398/,安装命令为

pip install alipay-sdk-python==3.3.398

编写调用代码

支付宝接口所有API文档地址:https://opendocs.alipay.com/apis/api_1/alipay.trade.pay,这里我们使用"alipay.trade.page.pay(统一收单下单并支付页面接口)",这个接口会返回一个支付界面的URL,引导用户进入该URL,并登录支付宝账号完成支付,注意不是"alipay.trade.page.pay(统一收单下单并支付页面接口)",这个下单并支付接口是直接将买方账户信息也放入发送数据中,返回的是支付的结果,而不是返回支付页面的链接让用户自己登陆。

编辑order/views.py文件,支付宝所有接口调用代码都分为4个部分:

1. 导入相关包

客户端相关包、模型相关包、请求相关包

import logging
from alipay.aop.api.AlipayClientConfig import AlipayClientConfig
from alipay.aop.api.DefaultAlipayClient import DefaultAlipayClient
from alipay.aop.api.domain.AlipayTradePagePayModel import AlipayTradePagePayModel
from alipay.aop.api.request.AlipayTradePagePayRequest import AlipayTradePagePayRequest

2. 创建(实例化)客户端

 这里将创建客户端需要的一些参数配置在了settings.py文件中

# 记录日志
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s %(levelname)s %(message)s',
filemode='a',)
logger = logging.getLogger('')
# 实例化客户端
alipay_client_config = AlipayClientConfig()
alipay_client_config.server_url = settings.ALIPAY_SERVER_URL
alipay_client_config.app_id = settings.ALIPAY_APP_ID
alipay_client_config.app_private_key = settings.ALIPAY_PRIVATE_KEY
alipay_client_config.alipay_public_key = settings.ALIPAY_PUBLIC_KEY
client = DefaultAlipayClient(alipay_client_config, logger)

settings.py配置

# 支付宝支付设置-沙箱环境
# 支付宝网关,正式环境网关去掉dev三个字母
ALIPAY_SERVER_URL = 'https://openapi.alipaydev.com/gateway.do'
# 应用ID
ALIPAY_APP_ID = '2016102200739747'
# 应用私钥
ALIPAY_PRIVATE_KEY = 'XXXXXX'
# 支付宝公钥
ALIPAY_PUBLIC_KEY = 'XXXXXXX'
# 订单超时时间:如果买家超过这个时间不付款,会关闭交易(最小1m分钟)
ALIPAY_EXPRESS = '10m'

3. 创建支付模型

# 构造请求参数对象
model = AlipayTradePagePayModel()
# 调用方系统生成的订单编号
model.out_trade_no = order.order_num;
# 支付金额
model.total_amount = str(order.total_amount);
# 支付标题
model.subject = "天天生鲜";
#与支付宝签约的产品码名称,目前只支持这一种。 model.product_code = 'FAST_INSTANT_TRADE_PAY' # 订单过期关闭时长(分钟) model.timeout_express = settings.ALIPAY_EXPRESS

4. 调用业务API

# 创建请求对象
request = AlipayTradePagePayRequest(biz_model=model)
# 设置回调通知地址(GET)
request.return_url = settings.ALIPAY_RETURN_URL
# 设置回调通知地址(POST)
request.notify_url = settings.ALIPAY_NOTIFY_URL
# 执行API调用,获取支付连接
pay_url = client.page_execute(request, http_method='GET')
return pay_url

完整支付类视图(OrderAlipayView)代码为:

# 支付宝支付 start
import logging
from alipay.aop.api.AlipayClientConfig import AlipayClientConfig
from alipay.aop.api.DefaultAlipayClient import DefaultAlipayClient
from alipay.aop.api.domain.AlipayTradePagePayModel import AlipayTradePagePayModel
from alipay.aop.api.request.AlipayTradePagePayRequest import AlipayTradePagePayRequest


def alipay_init():
    '''支付宝初始化'''
    # 记录日志
    logging.basicConfig(
        level=logging.INFO,
        format='%(asctime)s %(levelname)s %(message)s',
        filemode='a',)
    logger = logging.getLogger('')
    # 实例化客户端
    alipay_client_config = AlipayClientConfig()
    alipay_client_config.server_url = settings.ALIPAY_SERVER_URL
    alipay_client_config.app_id = settings.ALIPAY_APP_ID
    alipay_client_config.app_private_key = settings.ALIPAY_PRIVATE_KEY
    alipay_client_config.alipay_public_key = settings.ALIPAY_PUBLIC_KEY
    client = DefaultAlipayClient(alipay_client_config, logger)
    return client

def alipay_pay(order):
    '''支付宝支付'''
    client = alipay_init()
    # 构造请求参数对象
    model = AlipayTradePagePayModel()
    # 调用方系统生成的订单编号
    model.out_trade_no = order.order_num;
    # 支付金额
    model.total_amount = str(order.total_amount);
    # 支付标题
    model.subject = "天天生鲜";
    #与支付宝签约的产品码名称,目前只支持这一种。
    model.product_code = 'FAST_INSTANT_TRADE_PAY'
    # 订单过期关闭时长(分钟)
    model.timeout_express = settings.ALIPAY_EXPRESS
    # 创建请求对象
    request = AlipayTradePagePayRequest(biz_model=model)
    # 设置回调通知地址(GET)
    request.return_url = settings.ALIPAY_RETURN_URL
    # 设置回调通知地址(POST)
    request.notify_url = settings.ALIPAY_NOTIFY_URL
    # 执行API调用,获取支付连接
    pay_url = client.page_execute(request, http_method='GET')
    return pay_url


class OrderAlipayView(View):
    '''支付视图'''
    def post(self, request):
        '''支付处理'''
        context = {
            'status': 'E',
            'errmsg': '',
        }
        user = request.user
        if not user.is_authenticated:
            context['errmsg'] = '用户未登录!'
            return JsonResponse(context)
        # 接收数据
        order_id = int(request.POST.get('order_id'))

        # 校验数据
        try:
            order = OrderInfo.objects.get(id=order_id)
        except OrderInfo.DoesNotExist:
            context['errmsg'] = '订单不存在!'
            return JsonResponse(context)

        # 业务处理
        pay_url = alipay_pay(order)

        # 返回应答
        context['status'] = 'S'
        context['pay_url'] = pay_url
        return JsonResponse(context)

以上代码完成之后即可将返回的pay_url传递给前端,前端通过window.open(data.pay_url),引导用户浏览器打开支付宝返回的支付url,让用户进行登录支付。同时发送查询支付结果的请求,若监控到支付成功,则刷新订单页面

编写查询支付宝支付结果代码

完整查询类视图(OrderCheckView)代码为:

from alipay.aop.api.domain.AlipayTradeQueryModel import AlipayTradeQueryModel
from alipay.aop.api.request.AlipayTradeQueryRequest import AlipayTradeQueryRequest

def alipay_query(order, context):
    '''支付宝支付'''
    client = alipay_init()
    # 构造请求参数对象
    model = AlipayTradeQueryModel()
    model.out_trade_no = order.order_num;
    model.timeout_express = settings.ALIPAY_EXPRESS
    #与支付宝签约的产品码名称,目前只支持这一种。
    model.product_code = 'FAST_INSTANT_TRADE_PAY'
    request = AlipayTradeQueryRequest(biz_model=model)

    while True:
        # 执行API调用
        response = client.execute(request)
        # str转换为字典
        response = eval(response)
        code = response.get('code')
        sub_code = response.get('sub_code')
        sub_msg = response.get('sub_msg')
        trade_status = response.get('trade_status')
        if sub_code == 'ACQ.TRADE_NOT_EXIST' or (code == '10000' and
                                                 trade_status ==
                                                 'WAIT_BUYER_PAY'):
            # 交易不存在,或状态为等待买家付款则继续等待用户付款
            time.sleep(5)
            continue
        elif code == '10000' and trade_status == 'TRADE_SUCCESS':
            # 支付成功
            context['status'] = 'S'
            trade_no = response.get('trade_no')
            # 回写订单支付号
            order.trade_no = trade_no
            order.order_status = 4 # 待评价
            order.save()
            break
        else:
            context['errmsg'] = '支付失败:%s-%s' % (sub_code, sub_msg)
            break


class OrderCheckView(View):
    '''查询支付宝支付情况'''
    def post(self, request):
        context = {
            'status': 'E',
            'errmsg': ''
        }
        user = request.user
        if not user.is_authenticated:
            context['errmsg'] = '用户未登录!'
            return JsonResponse(context)
        # 接收数据
        order_id = int(request.POST.get('order_id'))
        try:
            order = OrderInfo.objects.get(id=order_id)
        except Exception as e:
            context['errmsg'] = '订单不存在!'
            return JsonResponse(context)

        # 执行查询
        alipay_query(order, context)
        return JsonResponse(context)

1. 查询时,因为用户付款需要一定的时间,所以使用循环,每5秒查询一次

2. 查询换回的结果字符串‘str’,因此需要将其转换为字典

3. 返回的主要字段包括:code(返回码,如10000) 、sub_code(子返回码,如ACQ.TRADE_NOT_EXIST)、trade_status(交易状态,如:'WAIT_BUYER_PAY')

4. 当用户还未登陆支付宝时,code为40004、sub_code为ACQ.TRADE_NOT_EXIST(交易不存在),当用户登录后,code为10000,trade_status为WAIT_BUYER_PAY(等待用户付款),当付款成功后,trade_status为TRADE_SUCCESS

https://www.bilibili.com/video/BV1vt41147K8?p=1

订单页面支付JS

1. 点击‘去支付’按钮,发送ajax请求,后台视图调用支付宝支付接口时,返回的是一个支付界面的url,需要通过window.open(data.pay_url),引导用户浏览器打开支付宝返回的支付url

2. 引导完url之后,继续发送查询ajax请求,后台视图调用支付宝查询接口,若查到支付成功,则alert(‘支付成功’)并刷新界面 location.reload()

{% block endfiles %}
<script type="text/javascript" src="{% static 'js/jquery-1.12.4.min.js'%}"></script>
<script type="text/javascript">
    //根据订单状态显示下一步操作
    $('.oper_btn').each(function(){
        status = $(this).attr('order_status')
        if (status == '1'){
            oper_show = '去支付'
        }
        else if (status =='4'){
            oper_show = '去评价'
        }
        else{
            oper_show = $(this).attr('status_name')
        }
        $(this).text(oper_show)
    })
    //去支付按钮
    $('.oper_btn').click(function(){
        //获取订单ID
        order_id = $(this).attr('order_id')
        //若状态为待支付,则发送ajax支付请求
        if ($(this).attr('order_status') =='1'){
            pay_method = $(this).attr('pay_method')
            send_pay_ajax(order_id, pay_method)
        }
        //若状态为待评价,则跳转到评价界面
        else if($(this).attr('order_status') == '4'){
            //跳转到评价页面
            location.href = '/order/comment/'+order_id
        }
    })
    //支付发送ajax请求
    function send_pay_ajax(order_id, pay_method){
        csrf = $('input[name="csrfmiddlewaretoken"]').val()
        parameter = {
            'order_id': order_id,
            'csrfmiddlewaretoken': csrf,
        }
        if (pay_method == '3'){
            //支付宝支付
            $.post('/order/alipay/', parameter, function(data){
                //回调函数
                if (data.status == 'S'){
                    //引导用户到支付界面
                    window.open(data.pay_url)
                    //发送ajax请求查询订单支付情况
                    $.post('/order/check/', parameter, function(data){
                        if (data.status == 'S'){
                            alert('支付成功')
                            location.reload()
                        }
                        else{
                            alert(data.errmsg)
                        }
                    })
                }
                else{
                    alert(data.errmsg)
                }
            })
        }
        else{
            //其他支付方式
            alert('其他支付方式暂不支持!')
        }
    }
</script>
{% endblock endfiles %}

 调用支付宝接口

创建支付宝应用

登录支付宝开放平台,进入沙箱环境,沙箱环境即为支付宝给外接系统提供的虚拟开发环境,并默认分配了一个应用,因此不需要再创建应用,而正是支付宝环境需要创建应用并审核。

设置应用密钥

支付需要有三个密钥:

  应用的私钥:将发送给支付宝的数据用自己的私钥加密。

  应用的公钥:与应用的私钥配对使用,将加密后的数据发送给支付宝时,同时将公钥也发送给支付宝,让支付宝使用该公钥进行解密。

  支付宝的公钥:支付宝解密后,再用支付宝自己的私钥进行加密并发送给接口调用方(应用),应用再使用支付宝公钥进行解密。

生成密钥和私钥,可以使用‘支付宝开放平台开发助手’生成,下载路径为:https://opendocs.alipay.com/open/291/105971

密钥格式选择“PKCS1(非Java适用)”,点击生成密钥后,点击‘打开密钥文件路径’,可以查看到生成的公钥和私钥,保存好这两个文件。

进入沙箱环境,设置应用的密钥,将应用公钥添加进去,同时会返回一个支付宝公钥

 沙箱账号

沙箱环境也提供了两个账号,分别是买方和卖方的账号,后续进行支付交易时可以使用买方账号

 安装官方SDK

支付宝SDK路径:https://opendocs.alipay.com/open/54/103419#Alipay%20SDK, 支付宝官方也提供了支持python的SDK(alipay-sdk-python):https://pypi.org/project/alipay-sdk-python/3.3.398/,安装命令为

pip install alipay-sdk-python==3.3.398

编写调用代码

支付宝接口所有API文档地址:https://opendocs.alipay.com/apis/api_1/alipay.trade.pay,这里我们使用"alipay.trade.page.pay(统一收单下单并支付页面接口)",这个接口会返回一个支付界面的URL,引导用户进入该URL,并登录支付宝账号完成支付,注意不是"alipay.trade.page.pay(统一收单下单并支付页面接口)",这个下单并支付接口是直接将买方账户信息也放入发送数据中,返回的是支付的结果,而不是返回支付页面的链接让用户自己登陆。

编辑order/views.py文件,支付宝所有接口调用代码都分为4个部分:

1. 导入相关包

客户端相关包、模型相关包、请求相关包

import logging
from alipay.aop.api.AlipayClientConfig import AlipayClientConfig
from alipay.aop.api.DefaultAlipayClient import DefaultAlipayClient
from alipay.aop.api.domain.AlipayTradePagePayModel import AlipayTradePagePayModel
from alipay.aop.api.request.AlipayTradePagePayRequest import AlipayTradePagePayRequest

2. 创建(实例化)客户端

 这里将创建客户端需要的一些参数配置在了settings.py文件中

# 记录日志
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s %(levelname)s %(message)s',
filemode='a',)
logger = logging.getLogger('')
# 实例化客户端
alipay_client_config = AlipayClientConfig()
alipay_client_config.server_url = settings.ALIPAY_SERVER_URL
alipay_client_config.app_id = settings.ALIPAY_APP_ID
alipay_client_config.app_private_key = settings.ALIPAY_PRIVATE_KEY
alipay_client_config.alipay_public_key = settings.ALIPAY_PUBLIC_KEY
client = DefaultAlipayClient(alipay_client_config, logger)

settings.py配置

# 支付宝支付设置-沙箱环境
# 支付宝网关,正式环境网关去掉dev三个字母
ALIPAY_SERVER_URL = 'https://openapi.alipaydev.com/gateway.do'
# 应用ID
ALIPAY_APP_ID = '2016102200739747'
# 应用私钥
ALIPAY_PRIVATE_KEY = 'XXXXXX'
# 支付宝公钥
ALIPAY_PUBLIC_KEY = 'XXXXXXX'
# 订单超时时间:如果买家超过这个时间不付款,会关闭交易(最小1m分钟)
ALIPAY_EXPRESS = '10m'

3. 创建支付模型

# 构造请求参数对象
model = AlipayTradePagePayModel()
# 调用方系统生成的订单编号
model.out_trade_no = order.order_num;
# 支付金额
model.total_amount = str(order.total_amount);
# 支付标题
model.subject = "天天生鲜";
#与支付宝签约的产品码名称,目前只支持这一种。 model.product_code = 'FAST_INSTANT_TRADE_PAY' # 订单过期关闭时长(分钟) model.timeout_express = settings.ALIPAY_EXPRESS

4. 调用业务API

# 创建请求对象
request = AlipayTradePagePayRequest(biz_model=model)
# 设置回调通知地址(GET)
request.return_url = settings.ALIPAY_RETURN_URL
# 设置回调通知地址(POST)
request.notify_url = settings.ALIPAY_NOTIFY_URL
# 执行API调用,获取支付连接
pay_url = client.page_execute(request, http_method='GET')
return pay_url

完整支付类视图(OrderAlipayView)代码为:

# 支付宝支付 start
import logging
from alipay.aop.api.AlipayClientConfig import AlipayClientConfig
from alipay.aop.api.DefaultAlipayClient import DefaultAlipayClient
from alipay.aop.api.domain.AlipayTradePagePayModel import AlipayTradePagePayModel
from alipay.aop.api.request.AlipayTradePagePayRequest import AlipayTradePagePayRequest


def alipay_init():
    '''支付宝初始化'''
    # 记录日志
    logging.basicConfig(
        level=logging.INFO,
        format='%(asctime)s %(levelname)s %(message)s',
        filemode='a',)
    logger = logging.getLogger('')
    # 实例化客户端
    alipay_client_config = AlipayClientConfig()
    alipay_client_config.server_url = settings.ALIPAY_SERVER_URL
    alipay_client_config.app_id = settings.ALIPAY_APP_ID
    alipay_client_config.app_private_key = settings.ALIPAY_PRIVATE_KEY
    alipay_client_config.alipay_public_key = settings.ALIPAY_PUBLIC_KEY
    client = DefaultAlipayClient(alipay_client_config, logger)
    return client

def alipay_pay(order):
    '''支付宝支付'''
    client = alipay_init()
    # 构造请求参数对象
    model = AlipayTradePagePayModel()
    # 调用方系统生成的订单编号
    model.out_trade_no = order.order_num;
    # 支付金额
    model.total_amount = str(order.total_amount);
    # 支付标题
    model.subject = "天天生鲜";
    #与支付宝签约的产品码名称,目前只支持这一种。
    model.product_code = 'FAST_INSTANT_TRADE_PAY'
    # 订单过期关闭时长(分钟)
    model.timeout_express = settings.ALIPAY_EXPRESS
    # 创建请求对象
    request = AlipayTradePagePayRequest(biz_model=model)
    # 设置回调通知地址(GET)
    request.return_url = settings.ALIPAY_RETURN_URL
    # 设置回调通知地址(POST)
    request.notify_url = settings.ALIPAY_NOTIFY_URL
    # 执行API调用,获取支付连接
    pay_url = client.page_execute(request, http_method='GET')
    return pay_url


class OrderAlipayView(View):
    '''支付视图'''
    def post(self, request):
        '''支付处理'''
        context = {
            'status': 'E',
            'errmsg': '',
        }
        user = request.user
        if not user.is_authenticated:
            context['errmsg'] = '用户未登录!'
            return JsonResponse(context)
        # 接收数据
        order_id = int(request.POST.get('order_id'))

        # 校验数据
        try:
            order = OrderInfo.objects.get(id=order_id)
        except OrderInfo.DoesNotExist:
            context['errmsg'] = '订单不存在!'
            return JsonResponse(context)

        # 业务处理
        pay_url = alipay_pay(order)

        # 返回应答
        context['status'] = 'S'
        context['pay_url'] = pay_url
        return JsonResponse(context)

以上代码完成之后即可将返回的pay_url传递给前端,前端通过window.open(data.pay_url),引导用户浏览器打开支付宝返回的支付url,让用户进行登录支付。同时发送查询支付结果的请求,若监控到支付成功,则刷新订单页面

编写查询支付宝支付结果代码

完整查询类视图(OrderCheckView)代码为:

from alipay.aop.api.domain.AlipayTradeQueryModel import AlipayTradeQueryModel
from alipay.aop.api.request.AlipayTradeQueryRequest import AlipayTradeQueryRequest

def alipay_query(order, context):
    '''支付宝支付'''
    client = alipay_init()
    # 构造请求参数对象
    model = AlipayTradeQueryModel()
    model.out_trade_no = order.order_num;
    model.timeout_express = settings.ALIPAY_EXPRESS
    #与支付宝签约的产品码名称,目前只支持这一种。
    model.product_code = 'FAST_INSTANT_TRADE_PAY'
    request = AlipayTradeQueryRequest(biz_model=model)

    while True:
        # 执行API调用
        response = client.execute(request)
        # str转换为字典
        response = eval(response)
        code = response.get('code')
        sub_code = response.get('sub_code')
        sub_msg = response.get('sub_msg')
        trade_status = response.get('trade_status')
        if sub_code == 'ACQ.TRADE_NOT_EXIST' or (code == '10000' and
                                                 trade_status ==
                                                 'WAIT_BUYER_PAY'):
            # 交易不存在,或状态为等待买家付款则继续等待用户付款
            time.sleep(5)
            continue
        elif code == '10000' and trade_status == 'TRADE_SUCCESS':
            # 支付成功
            context['status'] = 'S'
            trade_no = response.get('trade_no')
            # 回写订单支付号
            order.trade_no = trade_no
            order.order_status = 4 # 待评价
            order.save()
            break
        else:
            context['errmsg'] = '支付失败:%s-%s' % (sub_code, sub_msg)
            break


class OrderCheckView(View):
    '''查询支付宝支付情况'''
    def post(self, request):
        context = {
            'status': 'E',
            'errmsg': ''
        }
        user = request.user
        if not user.is_authenticated:
            context['errmsg'] = '用户未登录!'
            return JsonResponse(context)
        # 接收数据
        order_id = int(request.POST.get('order_id'))
        try:
            order = OrderInfo.objects.get(id=order_id)
        except Exception as e:
            context['errmsg'] = '订单不存在!'
            return JsonResponse(context)

        # 执行查询
        alipay_query(order, context)
        return JsonResponse(context)

1. 查询时,因为用户付款需要一定的时间,所以使用循环,每5秒查询一次

2. 查询换回的结果字符串‘str’,因此需要将其转换为字典

3. 返回的主要字段包括:code(返回码,如10000) 、sub_code(子返回码,如ACQ.TRADE_NOT_EXIST)、trade_status(交易状态,如:'WAIT_BUYER_PAY')

4. 当用户还未登陆支付宝时,code为40004、sub_code为ACQ.TRADE_NOT_EXIST(交易不存在),当用户登录后,code为10000,trade_status为WAIT_BUYER_PAY(等待用户付款),当付款成功后,trade_status为TRADE_SUCCESS

猜你喜欢

转载自www.cnblogs.com/gcxblogs/p/12895891.html