python3.7+flask+alipay 支付宝付款功能

文档参考github:https://github.com/fzlee/alipay/blob/master/docs/init.md

沙箱环境配置:https://opendocs.alipay.com/open/200/105311

1、进入沙箱环境进行配置,有对应的APPID和支付宝网关

2、然后设置RSA2密钥,可下载支付宝开放平台开发助手进行生成,可查看 文档 ,然后记录好密钥的存放位置

回调地址是在支付过程中,后台会默认去调用的接口,以此接口去确认支付是否成功。所以回调地址根据自己本地接口进行填写,可参考后续的完整代码;

线上真实配置也与沙箱类似,需要开通自己的支付宝账号为商家才能进行配置。

进入非沙箱环境 ,然后选择你所需要开发的应用,创建应用后填写所需的信息以及需要开通的功能,然后提交审核即可。

比如选择开发网页付款,创建后进入配置信息,而相应的服务会提醒需要商家账号才能开通使用。审核通过即可正常使用

本地代码配置文件及完整代码:

APP_PRIVATE_KEY_PATH:存放 app_private_key.txt 的文件路径
ALIPAY_PUBLIC_KEY_PATH:存放alipay_public_key.txt的文件路径
比如本地路径: d:/keys/app_private_key.txt
或 服务器路径: /mnt/keys/app_private_key.txt 
项目中安装: pip install python-alipay-sdk 

file_system.py 文件
 1 # file_system.py
 2 import os
 3 
 4 
 5 env = "production"
 6 # env = ""
 7 if env == 'production':
 8     APP_PRIVATE_KEY_PATH = '/mnt/alipay_keys/app_private_key.txt'
 9     ALIPAY_PUBLIC_KEY_PATH = '/mnt/alipay_keys/alipay_public_key.txt'
10 else:
11     APP_PRIVATE_KEY_PATH = os.getcwd() + '/ipay/keys/app_private_key.txt'
12     ALIPAY_PUBLIC_KEY_PATH = os.getcwd() + '/ipay/keys/alipay_public_key.txt'
View Code

alipay_setting.py文件

 1 # alipay_setting.py
 2 from alipay import AliPay
 3 from config import APP_PRIVATE_KEY_PATH, ALIPAY_PUBLIC_KEY_PATH
 4 
 5 
 6 env == "production"
 7 if env == "production":
 8     # 支付宝应用APPID
 9     APP_ID = '20210021******'
10     # 支付连接(支付宝网关)
11     PAY_URL = 'https://openapi.alipay.com/gateway.do?'
12 else:
13     # 沙箱
14     APP_ID = '2016102******'
15     PAY_URL = 'https://openapi.alipaydev.com/gateway.do?'
16 
17 # 应用私钥文件路径
18 APP_PRIVATE_KEY = open(APP_PRIVATE_KEY_PATH).read()
19 
20 # 支付宝公钥文件路径
21 ALIPAY_PUBLIC_KEY = open(ALIPAY_PUBLIC_KEY_PATH).read()
22 # 签名方式
23 SIGN_TYPE = 'RSA2'
24 # 是否是测试环境 - 是否是支付宝沙箱,默认为 False
25 DEBUG = False
26 
27 
28 def alipay_trade_page_pay(pay_id, paid_price, item_name, return_url, notify_url):
29     alipay = AliPay(
30         appid=APP_ID,
31         app_notify_url=notify_url,
32         app_private_key_string=APP_PRIVATE_KEY,
33         alipay_public_key_string=ALIPAY_PUBLIC_KEY,
34         sign_type=SIGN_TYPE,
35         debug=DEBUG
36     )
37 
38     # 生成支付链接
39     order_string = alipay.api_alipay_trade_page_pay(
40         out_trade_no=pay_id,
41         total_amount=paid_price,
42         subject=item_name,
43         return_url=return_url,        # 支付成功后同步回调的项目前台页面
44         notify_url=notify_url   # 支付成功后异步回调的项目后台接口
45     )
46 
47     # 支付链接 = 支付宝网关 +  order_string
48     order_url = PAY_URL + order_string
49     return order_url
50 
51 
52 # 验证支付结果
53 def verify_payment_result(data, signature):
54     alipay = AliPay(
55         appid=APP_ID,
56         app_notify_url=None,
57         app_private_key_string=APP_PRIVATE_KEY,
58         alipay_public_key_string=ALIPAY_PUBLIC_KEY,
59         sign_type=SIGN_TYPE,
60         debug=DEBUG
61     )
62     success = alipay.verify(data, signature)
63     return success
View Code

数据库模版文件,主要清楚接口是如何去调用支付宝付款功能,以及会生成怎样的数据内容

resource:了解上面支付宝配置文件 alipay_setting.py 中的接口是如何被调用,这里是结合了数据库模版 AlipayModel 的代码

  1 import json
  2 from config import FILE_DOMAIN_PREFIX
  3 from model import AlipayOrderModel, UserModel
  4 from flask_cors import cross_origin
  5 from flask_restful import Resource
  6 from util import id_generator
  7 from flask_jwt_extended import jwt_required, get_jwt_identity
  8 from flask import request, jsonify
  9 import time
 10 from ipay.alipay_setting import alipay_trade_page_pay, verify_payment_result
 11 from wrapper import universal_resource_wrapper, root_role_required
 12 # 参考路径:https://github.com/fzlee/alipay
 13 
 14 
 15 # 创建支付宝订单接口
 16 class CreateAlipayOrder(Resource):
 17     """
 18     itemName,paidPrice,paymentMethod,itemDeadline,setMeal
 19     """
 20     @universal_resource_wrapper(required=['paymentMethod', 'itemName', 'paidPrice','itemDeadline', 'setMeal'])
 21     @jwt_required
 22     @cross_origin(allow_headers=['Content-Type'])
 23     def post(self):
 24         data = request.get_json()
 25         uid = get_jwt_identity()
 26         item_name = data['itemName']
 27         paid_price = data['paidPrice']
 28         payment_method = data['paymentMethod']
 29         pay_id = id_generator(template='uuid')
 30         notify_url = FILE_DOMAIN_PREFIX + '/api/check_payment_success'
 31         return_url = FILE_DOMAIN_PREFIX + '/chooseProductking/cpkRenewalInstructions'
 32         # 生成支付宝付款链接
 33         order_url = alipay_trade_page_pay(pay_id=pay_id, paid_price=paid_price, item_name=item_name,
 34                                           return_url=return_url, notify_url=notify_url)
 35         # 保存到数据库中;
 36         ao = AlipayOrderModel(
 37             alipayId=pay_id,     # 订单编号
 38             itemName=item_name,     # 项目名称
 39             paymentMethod=payment_method,
 40             paidPrice=paid_price,   # 付费价格
 41             paymentStatus=False,
 42             paidAt=time.time(),
 43             paymentUrl=order_url,
 44             uid=uid,
 45             setMeal=data['setMeal'],
 46             itemDeadline=data['itemDeadline']   # 项目截止日期
 47         )
 48         ao.save()
 49         resp = jsonify({
 50             'msg': '成功创建订单数据,返回支付宝订单ID',
 51             'status': True,
 52             'alipayId': pay_id
 53         })
 54         return resp
 55 
 56 
 57 class GetAlipayPaymentUrl(Resource):
 58     """alipayId"""
 59     @universal_resource_wrapper(required=['alipayId'])
 60     @cross_origin(allow_headers=['Content-Type'])
 61     def post(self):
 62         """
 63         alipayId
 64         :return:
 65         """
 66         data = request.get_json()
 67         url = AlipayOrderModel.get_payment_url(data['alipayId'])
 68         resp = jsonify({
 69             'msg': '获取支付宝付款链接',
 70             'status': True,
 71             'data': {
 72                 'url': url
 73             }
 74         })
 75         return resp
 76 
 77 
 78 # 验证是否支付成功,作为回调接口notify_url使用
 79 class CheckPaymentSuccess(Resource):
 80     @universal_resource_wrapper(required=[])
 81     @cross_origin(allow_headers=['Content-Type'])
 82     def post(self):
 83         data = request.form.to_dict()
 84         # sign must be poped out
 85         signature = data.pop("sign")
 86         print(json.dumps(data))
 87         print(signature)
 88         # verify
 89         success = verify_payment_result(data, signature)
 90         # 交易结果判断
 91         if success and data["trade_status"] in ("TRADE_SUCCESS", "TRADE_FINISHED"):
 92             ao = AlipayOrderModel.find_by_alipay_id(data['out_trade_no'])
 93             ao.paymentStatus = True
 94             ao.save()
 95             usr = UserModel.find_by_uid(ao.uid)
 96             usr.update_expire_time(ao.setMeal, ao.itemDeadline)
 97             print("trade succeed")
 98             resp = jsonify({
 99                 'msg': '支付成功',
100                 'status': True
101             })
102         else:
103             resp = jsonify({
104                 'msg': '支付失败',
105                 'status': False
106             })
107         return resp
108 
109 
110 class CheckPaymentStatus(Resource):
111     """
112     alipayId
113     """
114     @universal_resource_wrapper(required=['alipayId'])
115     @jwt_required
116     @cross_origin(allow_headers=['Content-Type'])
117     def post(self):
118         uid = get_jwt_identity()
119         data = request.get_json()
120         ao = AlipayOrderModel.get_payment_status(uid=uid, pay_id=data['alipayId'])
121         if ao is None:
122             resp = jsonify({
123                 'msg': '支付失败,无法找到已付款订单',
124                 'status': False
125             })
126         else:
127             resp = jsonify({
128                 'msg': '支付成功',
129                 'status': True,
130                 'data': ao
131             })
132         return resp
133 
134 
135 class UpdatePaymentStatusForLocal(Resource):
136     """alipayId"""
137     @universal_resource_wrapper(required=['alipayId'])
138     @jwt_required
139     @root_role_required
140     @cross_origin(allow_headers=['Content-Type'])
141     def post(self):
142         data = request.get_json()
143         ao = AlipayOrderModel.find_by_alipay_id(data['alipayId'])
144         ao.paymentStatus = True
145         ao.save()
146         usr = UserModel.find_by_uid(ao.uid)
147         usr.update_expire_time(ao.setMeal, ao.itemDeadline)
148         print("trade succeed")
149         resp = jsonify({
150             'msg': '支付成功',
151             'status': True
152         })
153         return resp

model:根据自己的需求自定义的数据库模版,只为跟上面的接口代码结合使用而已。

 1 from model import Collection
 2 import custom_field as cf
 3 
 4 
 5 MODIFIABLE = [
 6     'paymentMethod',
 7     'itemName',
 8     'paidPrice',
 9     'paymentStatus',
10     'paidAt',
11     'paymentUrl',
12     'uid',
13     'itemDeadline',
14     'setMeal'
15 ]
16 UNMODIFIABLE = []
17 
18 ID_KEY = 'alipayId'
19 ID_KEY_TEMPLATE = 'uuid'
20 
21 
22 class AlipayOrderModel(Collection):
23     alipayId = cf.Uuid()
24     paymentMethod = cf.String(default='alipay')
25     itemName = cf.String()
26     paidPrice = cf.Float()
27     paymentStatus = cf.Bool()
28     paidAt = cf.Time(required=False)
29     paymentUrl = cf.String()
30     uid = cf.Uuid()
31     setMeal = cf.String(required='free', choices=['lowLevel', 'highLevel'])
32     itemDeadline = cf.String(required=False, choices=['oneMonth', 'halfYear', 'oneYear'])
33 
34     meta = {"db_alias": "MAILDB", "collection": "alipay_order"}
35 
36     @classmethod
37     def create_new(cls, data_, created_by):
38         return super()._create_new(data_, id_key=ID_KEY,
39                                    id_template=ID_KEY_TEMPLATE,
40                                    created_by=created_by,
41                                    strict_fields=MODIFIABLE + UNMODIFIABLE
42                                    )
43 
44     def do_update(self, keys_values, update_by):
45         return super()._do_update(keys_values, update_by,
46                                   MODIFIABLE)
47 
48     @classmethod
49     def find_by_alipay_id(cls, obj_id):
50         return cls._find_by({'alipayId': obj_id})
51 
52     @classmethod
53     def get_payment_url(cls, pay_id):
54         obj = AlipayOrderModel._find_by(query={'alipayId': pay_id, 'paymentStatus': False})
55         return obj.paymentUrl
56 
57     @classmethod
58     def get_payment_status(cls, uid, pay_id):
59         obj = AlipayOrderModel._find_by(query={'alipayId': pay_id, 'paymentStatus': True, 'uid': uid})
60         return obj
原文地址:https://www.cnblogs.com/liqiongming/p/14581255.html