电脑网站的支付流程以及支付宝沙箱环境使用前的配置
-
1、电脑网站的支付流程
-
2、支付宝沙箱环境的介绍以及使用前的配置
使用前的配置配置
-
1、打开网站,使用已有的支付宝账号登录
https://open.alipay.com/platform/home.htm
-
2、点击开发者中心 ---- 研发中心 -------- 沙箱应用 -------- 设置密钥
-
3、公钥和密钥的介绍
用户需要有自己的公钥和密钥,密钥由自己保持,作用是将发送给支付宝网站的数据进行加密,并且用户需要将自己的公钥告诉支付宝,支付宝可以用公钥进行解密。同样的,用户也需要拿到支付宝的公钥。
-
4、生成公钥和私钥
window系统可以使用支付宝提供的软件进行公钥和私钥的生成
复制公钥,粘贴在上面打开的沙箱应用 ----- RSA2密钥设置中
同时保存支付宝的公钥
在项目中创建文件夹key,专门存放用户私钥和支付宝公钥
在文件夹key中,创建两个文件 alipay_public_key.pem(存放支付宝公钥)和app_private_key.pem(存放用户私钥)
分别打开,将私钥和公钥复制进去,格式:
-----BEGIN RSA PRIVATE KEY-----
公钥或者私钥复制在这里
-----END RSA PRIVATE KEY-----
将两个文件的绝对路径加入到项目settings文件中
## 公钥和私钥的地址 APP_PRIVATE_KEY_PATH = os.path.join(BASE_DIR,'key/app_private_key.pem') ALIPAY_PUBLIC_KEY_PATH = os.path.join(BASE_DIR,'key/alipay_public_key.pem')
-
5、使用python-alipay-sdk
由于支付宝没有提供Python的alipay-SDK,所以需要借助第三方的非官方支付宝 Python SDK
相关网址:https://github.com/fzlee/alipay/blob/master/README.zh-hans.md#alipay.trade.page.pay
安装:
# 从 1.3.0升级上来的用户, 请先卸载pycrypto: pip uninstall pycrypto # 安装python-alipay-sdk pip install python-alipay-sdk --upgrade
天天生鲜项目的订单支付
-
1、订单支付的逻辑分析
当用户在前端点击订单支付时,需要将订单的id传递到后台,后台需要对数据进行校验,并连接支付宝沙箱,并传递支付链接,引导用户跳转到支付链接
-
2、订单支付的视图函数和模板文件
from alipay import AliPay ## 使用支付宝付款,接收的参数:订单id:order_id 参数校验之后引导用户跳转到支付页面 class OrderPayView(View): '''支付处理''' def post(self,request): '''支付处理''' order_id = request.POST.get('order_id') ## 1、 参数校验 user = request.user if not user.is_authenticated: return JsonResponse({'res':0,'errmsg':'用户未登录'}) if not order_id: return JsonResponse({'res':1,'errmsg':'参数不完整'}) try: order = OrderInfo.objects.get(order_id=order_id) ## 计算订单的总金额,转化成字符串格式 total_amount = order.total_price+order.transit_price total_amount = str(total_amount) except OrderInfo.DoesNoExist: return JsonResponse({'res':2,'errmsg':'订单不存在'}) ## 业务处理 ## 支付初始化 app_private_key_string = open(settings.APP_PRIVATE_KEY_PATH).read() alipay_public_key_string = open(settings.ALIPAY_PUBLIC_KEY_PATH).read() alipay = AliPay( appid='2016102400751639', app_notify_url=None, # 默认回调url app_private_key_string=app_private_key_string, # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥, alipay_public_key_string=alipay_public_key_string, sign_type="RSA2" , # RSA 或者 RSA2 debug = True # 默认False ) ## 接口调用 # 电脑网站支付,需要跳转到https://openapi.alipay.com/gateway.do? + order_string order_string = alipay.api_alipay_trade_page_pay( out_trade_no=order_id, ## 订单的编号 total_amount=total_amount, ## 订单的总金额 subject='天天生鲜%s'%order_id, ## 订单的名称 return_url=None, notify_url=None ) ## 3、返回应答 pay_url = 'https://openapi.alipaydev.com/gateway.do?' + order_string return JsonResponse({'res':3,'pay_url':pay_url})
{% extends 'base_user_center.html' %} {% load static %} {% block title %}天天生鲜-用户中心{% endblock title %} {% block right_content %} <div class="right_content clearfix"> {% csrf_token %} <h3 class="common_title2">全部订单</h3> {% for order in order_pages %} <ul class="order_list_th w978 clearfix"> <li class="col01">{{ order.create_time }}</li> <li class="col02">订单号:{{ order.order_id }}</li> <li class="col02 stress">{{ order.status }}</li> </ul> <table class="order_list_table w980"> <tbody> <tr> <td width="55%"> {% for order_sku in order.order_skus %} <ul class="order_goods_list clearfix"> <li class="col01"><a href="{% url 'goods:detail' order_sku.sku.id %}"><img src="{{ order_sku.sku.image.url }}" ></a></li> <li class="col02">{{ order_sku.sku.name }}<em>{{ order_sku.price }}元/{{ order_sku.sku.unite }}</em></li> <li class="col03">{{ order_sku.count }}</li> <li class="col04">{{ order_sku.amount }}元</li> </ul> {% endfor %} </td> <td width="15%">{{ order.total_price|add:order.transit_price }}(含运费:{{ order.transit_price }})元</td> <td width="15%">{{ order.status }}</td> <td width="15%"><a href="#" class="oper_btn" order_status="{{ order.order_status }}" order_id="{{ order.order_id }}">去付款</a></td> </tr> </tbody> </table> {% endfor %} <div class="pagenation"> {% if order_pages.has_previous %} <a href="{% url 'user:order' order_pages.previous_page_number %}"><上一页</a> {% endif %} {% for pindex in pages %} {% if pindex == order_pages.number %} <a href="{% url 'user:order' pindex %}" class="active">{{ pindex }}</a> {% else %} <a href="{% url 'user:order' pindex %}">{{ pindex }}</a> {% endif %} {% endfor %} {% if order_pages.has_next %} <a href="{% url 'user:order' order_pages.next_page_number %}">下一页></a> {% endif %} </div> </div> {% endblock right_content %} {% block bottomfiles %} <script src="{% static 'js/jquery-1.12.4.min.js' %}"></script> <script> // 给去付款增加点击事件,向后台传递参数,通过验证后引导用户跳转到支付页面 $('.oper_btn').click(function(){ // 判断订单的支付状态,只有待支付才能付款 var order_status = $(this).attr('order_status'); if (order_status == 1){ // 准备参数: 订单id:order_id var order_id = $(this).attr('order_id'); var csrf = $('input[name="csrfmiddlewaretoken"]').val(); // 组织参数 var context = {'order_id':order_id,'csrfmiddlewaretoken':csrf}; // ajax post请求,地址:/order/pay $.post('/order/pay',context,function(data){ if (data.res == 3){ // 通过验证,引导用户跳转到支付页面 window.open(data.pay_url); } else{ //通过失败 alert(data.errmsg); } }) } }) </script> {% endblock bottomfiles %}
-
3、订单支付结果的查询
当用户点击支付按钮的时候,前端不仅需要通过ajax post向后台申请支付页面,还要立即通过ajax post提交向后台请求支付结果的查询
后端查询支付结果的视图函数:
1 ## 接收的参数:订单id:order_id 2 class CheckPayView(View): 3 '''查询订单支付结果''' 4 def post(self,request): 5 '''查询订单支付结果''' 6 order_id = request.POST.get('order_id') 7 8 ## 1、 参数校验 9 user = request.user 10 if not user.is_authenticated: 11 return JsonResponse({'res': 0, 'errmsg': '用户未登录'}) 12 if not order_id: 13 return JsonResponse({'res': 1, 'errmsg': '参数不完整'}) 14 try: 15 order = OrderInfo.objects.get(order_id=order_id) 16 except OrderInfo.DoesNoExist: 17 return JsonResponse({'res': 2, 'errmsg': '订单不存在'}) 18 19 ## 业务处理 20 ## 支付初始化 21 22 app_private_key_string = open(settings.APP_PRIVATE_KEY_PATH).read() 23 alipay_public_key_string = open(settings.ALIPAY_PUBLIC_KEY_PATH).read() 24 25 alipay = AliPay( 26 appid='2016102400751639', 27 app_notify_url=None, # 默认回调url 28 app_private_key_string=app_private_key_string, 29 # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥, 30 alipay_public_key_string=alipay_public_key_string, 31 sign_type="RSA2", # RSA 或者 RSA2 32 debug=True # 默认False 33 ) 34 while 1: 35 ## 循环查询,直到查询到结果才跳出循环 36 ## 连接到支付宝的支付查询接口 37 response = alipay.api_alipay_trade_query(order_id) 38 39 # response = { 40 # "trade_no": "2017032121001004070200176844", # 支付宝交易号 41 # "code": "10000", # 接口调用是否成功 42 # "invoice_amount": "20.00", 43 # "open_id": "20880072506750308812798160715407", 44 # "fund_bill_list": [ 45 # { 46 # "amount": "20.00", 47 # "fund_channel": "ALIPAYACCOUNT" 48 # } 49 # ], 50 # "buyer_logon_id": "csq***@sandbox.com", 51 # "send_pay_date": "2017-03-21 13:29:17", 52 # "receipt_amount": "20.00", 53 # "out_trade_no": "out_trade_no15", 54 # "buyer_pay_amount": "20.00", 55 # "buyer_user_id": "2088102169481075", 56 # "msg": "Success", 57 # "point_amount": "0.00", 58 # "trade_status": "TRADE_SUCCESS", # 支付结果 59 # "total_amount": "20.00" 60 # } 61 62 63 ## 获取校验的结果并进行相应的处理 64 code = response.get('code') ## 接口调用 65 trade_status = response.get('trade_status') ## 支付结果 66 if code == '10000' and trade_status == 'TRADE_SUCCESS': 67 ## 支付成功 68 ## 更新订单状态,返回应答 69 order.order_status = 4 70 ## 添加支付编号 71 order.trade_no = response.get('trade_no') 72 order.save() 73 print(order.order_status) 74 print('支付成功') 75 ## 返回应答 76 return JsonResponse({'res':3,'message':'支付成功'}) 77 elif code == '40004' or (code == '10000' and response.get('trade_status') == 'WAIT_BUYER_PAY'): 78 # 等待买家付款 79 # 业务处理失败,可能一会就会成功 80 import time 81 time.sleep(5) 82 print('这里还在等待支付') 83 continue 84 else: 85 ## 支付失败 86 return JsonResponse({'res':4,'errmsg':'支付失败'})
模板文件:
{% extends 'base_user_center.html' %} {% load static %} {% block title %}天天生鲜-用户中心{% endblock title %} {% block right_content %} <div class="right_content clearfix"> {% csrf_token %} <h3 class="common_title2">全部订单</h3> {% for order in order_pages %} <ul class="order_list_th w978 clearfix"> <li class="col01">{{ order.create_time }}</li> <li class="col02">订单号:{{ order.order_id }}</li> <li class="col02 stress">{{ order.status }}</li> </ul> <table class="order_list_table w980"> <tbody> <tr> <td width="55%"> {% for order_sku in order.order_skus %} <ul class="order_goods_list clearfix"> <li class="col01"><a href="{% url 'goods:detail' order_sku.sku.id %}"><img src="{{ order_sku.sku.image.url }}" ></a></li> <li class="col02">{{ order_sku.sku.name }}<em>{{ order_sku.price }}元/{{ order_sku.sku.unite }}</em></li> <li class="col03">{{ order_sku.count }}</li> <li class="col04">{{ order_sku.amount }}元</li> </ul> {% endfor %} </td> <td width="15%">{{ order.total_price|add:order.transit_price }}(含运费:{{ order.transit_price }})元</td> <td width="15%">{{ order.status }}</td> <td width="15%"><a href="#" class="oper_btn" order_status="{{ order.order_status }}" order_id="{{ order.order_id }}">去付款</a></td> </tr> </tbody> </table> {% endfor %} <div class="pagenation"> {% if order_pages.has_previous %} <a href="{% url 'user:order' order_pages.previous_page_number %}"><上一页</a> {% endif %} {% for pindex in pages %} {% if pindex == order_pages.number %} <a href="{% url 'user:order' pindex %}" class="active">{{ pindex }}</a> {% else %} <a href="{% url 'user:order' pindex %}">{{ pindex }}</a> {% endif %} {% endfor %} {% if order_pages.has_next %} <a href="{% url 'user:order' order_pages.next_page_number %}">下一页></a> {% endif %} </div> </div> {% endblock right_content %} {% block bottomfiles %} <script src="{% static 'js/jquery-1.12.4.min.js' %}"></script> <script> // 给去付款增加点击事件,向后台传递参数,通过验证后引导用户跳转到支付页面 $('.oper_btn').click(function(){ // 判断订单的支付状态,只有待支付才能付款 var order_status = $(this).attr('order_status'); if (order_status == 1){ // 准备参数: 订单id:order_id var order_id = $(this).attr('order_id'); var csrf = $('input[name="csrfmiddlewaretoken"]').val(); // 组织参数 var context = {'order_id':order_id,'csrfmiddlewaretoken':csrf}; // ajax post请求,地址:/order/pay $.post('/order/pay',context,function(data){ if (data.res == 3){ // 通过验证,引导用户跳转到支付页面 window.open(data.pay_url); // 发起ajax post 请求 /order/check ,查询订单支付结果,传递的参数:order_id $.post('/order/check',context,function(data){ // 判断是否支付成功 if (data.res == 3){ // 支付成功,打印支付成功信息,并更新订单状态 alert(data.message); // 刷新页面 location.reload() } }) } else{ //通过失败 alert(data.errmsg); } }) } }) </script> {% endblock bottomfiles %}