先决条件
微信小程序的的开发文档,不仅不完善,而且零散在各个不同的页面之间,很多文档只有说明缺乏实例,而且坑众多,给开发者带了不少的麻烦,调试要花掉太多的时间。
本着别人造好了轮子,我们拿来就用的实用主义原则,这次我们找到了python的一个开源sdk:wechatpy. 使用别人的轮子也有风险,文档说明更少,摸索需要一段时间,如果最后没有调通,也是白白浪费时间,请自行评估。
这次我们的目的是使用sdk来完成微信支付的整个闭环逻辑,首选需要准备的数据如下:
微信公众号/小程序的APPID(密钥不需要)
开通了微信支付的商户号
微信支付商户号的密钥
微信支付的流程小程序/公众号端提交给后台订单信息,后台调用微信接口创建与预付单
后台将prepay_id返回给小程序,小程序端调起支付功能
用户支付完成,小程序完成支付
微信服务器推送用户支付的消息到后台,后台修改订单的状态为完成
wechatpy创建预付单1
2
3
4
5
6
7
8
9
10
11pay = WeChatPay(appid=CurrentConfig.WX_APPID, api_key=CurrentConfig.MNT_KEY,
sub_appid=CurrentConfig.WX_APPID, mch_id=CurrentConfig.MNT_ID)
res = pay.order.create(
trade_type="JSAPI",
body=coupons[0].coupon_code,
total_fee=pay_amount,
notify_url=CurrentConfig.NOTIFY_URL,
user_id=members[0].open_id,
out_trade_no=order_no
)
其中WX_APPID为小程序或公众号ID,MNT_KEY为商户号密钥,MNT_ID是商户ID
out_trade_no是后台生成商户订单,需要唯一,如果不传就是微信自动生成的单号,由于我们需要在后续的微信推送的消息中处理订单,所以这里一定要写我们自己生成的订单号。
创建预付订单以后,微信会把生成的prepay_id返回:
1prepay_id = res.get("prepay_id")
然后给小程序返回必须要的信息:
1
2
3
4
5
6
7
8
9
10params = {
"appId": CurrentConfig.WX_APPID,
"timeStamp": timestamp,
"nonceStr": nonce_str,
"package": package,
"signType": "MD5",
}
strs = "&".join(["{}={}".format(key, params.get(key))
for key in sorted(params.keys()) if params.get(key)]) + "&key={}".format(CurrentConfig.MNT_KEY)
paySign = md5(strs.encode("utf-8")).hexdigest().upper()
微信的签名逻辑需要注意:
商户密钥不参与字典序排序
md5后需要转大写
参与排序的字典名要与微信的文档严格保持一致
将timeStamp,package,nonceStr等返回给小程序,然后小程序调用wx.payment方法即可调起付款
微信消息推送
在统一下单的接口中有一个参数是notify_url,这个是微信支付完成后微信后台服务器给我们后台推送消息的URL接口地址,该URL不能带有参数,且必须是公网可以访问的地址。
微信推送消息是XML格式,使用wechatpy的parse_payment_result方法可以将结果转化成OrderedDict类型,且帮你做好了验签。
1
2
3pay = WeChatPay(appid=CurrentConfig.WX_APPID, api_key=CurrentConfig.MNT_KEY,
sub_appid=CurrentConfig.WX_APPID, mch_id=CurrentConfig.MNT_ID)
data = pay.parse_payment_result(request.data)
然后就可以根据返回的结果,处理之前的订单了。
唯一需要注意的一点,微信推送消息后,需要给微信服务器返回一个消息:
1return "SUCCESSOK"