QQ登录

只需一步,快速开始

微信支付 python版

凤梦洁 发表于 2018-5-19 15:29:09 | 显示全部楼层 |阅读模式

需求:

微信打开商品列表页面-> 点击商品后直接显示付款页面-> 点击付款调用微信支付

说明

微信支付需要你申请了公众号(appid, key - 用于签名), 商户号(mch_id, AppSecret - 用于获取openid, 获取code)

调起微信支付的页面需要配置授权

签名校验通过时还是提示签名错误, 可能时候商户号KEY配置的问题了, 重置一下KEY, 你可以继续使用原来的KEY来重置

公众号变更时记得修改后台和前台代码中的APPID

需要的ID和KEY

  1. # 微信配置基础数据
  2. WPC = {
  3.     'APPID': 'wx21e25187cb87c9f0',
  4.     'APPSECRET': 'fdd177a7xxxxxxxxxxxxx856eeeb187c',
  5.     'MCHID': '14222000000',
  6.     'KEY': 'd7810713e1exxxxxxxxxxadc9617d0a6',
  7.     'GOODDESC': '商户号中的公司简称或全称-无要求的商品名字',
  8.     'NOTIFY_URL': 'https://www.xxxx.com/service/applesson/wechatordernotice',
  9. }
复制代码

流程简介

网页内调起微信支付需要一个微信统一下单生成的订单号(prepay_id)

调用微信的统一下单接口需要一个用户在商户下的唯一标示(openid)

获取openid需要code参数加上AppID和AppSecret等,通过API换取access_token(openid)

其中code又需要通过页面跳转来获取, 需要appid和重定向url(可以带有你自己的参数, 会原样返回)

那么开发思路便是一步步回朔了.

1. 获取code

用户点击按钮跳转到微信授权页, 微信处理完后重定向到redirect_uri, 并给我们加上code=xxx的参数, 这个code就是我们需要的

  1. $('#buy').click(function() {
  2.         var param = {
  3.             appid: 'wx53c1xxxxad626eb8',
  4.             redirect_uri: 'https://www.xxxxx.com/wcpay/pay.html',
  5.             response_type: 'code',
  6.             scope: 'snsapi_base',
  7.             state: '1'
  8.         }
  9.         window.location.href = 'https://open.weixin.qq.com/connect/oauth2/authorize?' + $.param(param);
  10.     })
复制代码

2. 获取openid

这个在后台完成, WPC中配置了你的APPSECRET, 这个不能泄露, 接口调用成功会拿到一个openid, 这里都不会有什么问题

  1. @classmethod
  2.     def getOpenID(cls, kwargs):
  3.         param = {
  4.             'code': kwargs['code'],
  5.             'appid': WPC['APPID'],
  6.             'secret': WPC['APPSECRET'],
  7.             'grant_type': 'authorization_code',
  8.         }
  9.         # 通过code获取access_token
  10.         openIdUrl = 'https://api.weixin.qq.com/sns/oauth2/access_token'
  11.         resp = requests.get(openIdUrl, params=param)
  12.         # {openid, accss_token, refresh_token, openid, scope, expires_in}
  13.         # openId = json.loads(resp.text)['openid']
  14.         return resp.text
复制代码

3. 微信统一下单

统一下单 时参数传递需要签名(微信用我们设定的密匙对参数进行MD5加密, 通过双方的签名判断请求是否被篡改)

签名算法

  1. @classmethod
  2. def getSign(cls, kwargs):
  3.     # 计算签名
  4.     keys, paras = sorted(kwargs), []
  5.     paras = ['{}={}'.format(key, kwargs[key]) for key in keys if key != 'appkey']  # and kwargs[key] != '']
  6.     stringA = '&'.join(paras)
  7.     stringSignTemp = stringA + '&key=' + WPC['KEY']
  8.     sign = MD5(stringSignTemp).upper()
  9.     return sign
复制代码

MD5函数

  1. import hashlib
  2. # 获取MD5
  3. def MD5(str):
  4.     md5 = hashlib.md5()
  5.     md5.update(str.encode('utf-8'))
  6.     return md5.hexdigest()
复制代码

参数转xml

  1. @classmethod
  2. def getxml(cls, kwargs):
  3.    
  4.     kwargs['sign'] = Utility.getSign(kwargs)
  5.     # 生成xml
  6.     xml = ''
  7.     for key, value in kwargs.items():
  8.         xml += '<{0}>{1}</{0}>'.format(key, value)
  9.     xml = '<xml>{0}</xml>'.format(xml)
  10.     # print(xml)
  11.     return xml
复制代码

统一下单代码

  1. code = self.POST.get('code')
  2. openidresp = Utility.getOpenID({'code': code})
  3. openid = json.loads(openidresp).get('openid')
  4. UnifieOrderRequest = {
  5.     'appid': 'wxxxxxc18f32ad626eb8',  # 公众账号ID
  6.     'body': '公司名称-商品',  # 商品描述
  7.     'mch_id': '1397xxxxxx8',  # 商户号:深圳市泽慧文化传播有限公司
  8.     'nonce_str': '',  # 随机字符串
  9.     'notify_url': 'https://service.xxxx.com/service/applesson/wechatordernotice',  # 微信支付结果异步通知地址
  10.     'openid': '',  # trade_type为JSAPI时,openid为必填参数!此参数为微信用户在商户对应appid下的唯一标识, 统一支付接口中,缺少必填参数openid!
  11.     'out_trade_no': '',  # 商户订单号
  12.     'spbill_create_ip': '',  # 终端IP
  13.     'total_fee': '',  # 标价金额
  14.     'trade_type': 'JSAPI',  # 交易类型
  15. }
  16. UnifieOrderRequest['nonce_str'] = Utility.getnoncestr()
  17. UnifieOrderRequest['openid'] = openid
  18. UnifieOrderRequest['out_trade_no'] = UnifieOrderRequest['mch_id'] + str(order.id)  # 内部订单号码
  19. UnifieOrderRequest['spbill_create_ip'] = self.request.remote_ip
  20. UnifieOrderRequest['total_fee'] = int(lesson.price * 100)
  21. # 签名并生成xml
  22. xml = Utility.getxml(UnifieOrderRequest)
  23. resp = requests.post("https://api.mch.weixin.qq.com/pay/unifiedorder", data=xml.encode('utf-8'), headers={'Content-Type': 'text/xml'})
  24. msg = resp.text.encode('ISO-8859-1').decode('utf-8')
  25. xmlresp = xmltodict.parse(msg)
  26. prepay_id = ''
  27. if xmlresp['xml']['return_code'] == 'SUCCESS':
  28.     if xmlresp['xml']['result_code'] == 'SUCCESS':
  29.         prepay_id = xmlresp['xml']['prepay_id']
  30.         timestamp = str(int(time.time()))
  31.         data = {
  32.             "appId": xmlresp['xml']['appid'],
  33.             "nonceStr": Utility.getnoncestr(),
  34.             "package": "prepay_id=" + xmlresp['xml']['prepay_id'],
  35.             "signType": "MD5",
  36.             "timeStamp": timestamp
  37.         }
  38.         data['paySign'] = Utility.getSign(data)
  39.         data['orderid'] = order.id  # 付款后操作的订单
  40.         # 签名后返回给前端做支付参数
  41.         return JsonResponse(self, '000', data=data)
  42.     else:
  43.         msg = xmlresp['xml']['err_code_des']
  44.         return JsonResponse(self, '002', msg=msg)
  45. else:
  46.     msg = xmlresp['xml']['return_msg']
  47.     return JsonResponse(self, '002', msg=msg)
复制代码

统一下单成功返回后直接调用微信支付, 显示支付界面, 其中的paySign是我们自己的签名

  1. try {
  2.     // statements
  3.     // 微信统一订单, 返回预支付信息
  4.     var code = query('code'),
  5.         origin = query('groupid');
  6.         // alert(code);
  7.         $.post({
  8.             url: orderurl,
  9.             data: {
  10.                 origin: origin,
  11.                 mobile: phone,
  12.                 code: code
  13.             }
  14.         }).then(function(resp) {
  15.             if (resp.code && resp.code == "000") {
  16.                 // 后台返回订单信息
  17.                 var wepaydata = {
  18.                     appId: resp.data.appId,
  19.                     nonceStr: resp.data.nonceStr,
  20.                     package: resp.data.package,
  21.                     paySign: resp.data.paySign,
  22.                     signType: "MD5",
  23.                     timeStamp: resp.data.timeStamp
  24.                 };
  25.                 var orderid = resp.data.orderid || 0;
  26.                 window.jsApiCall = function() {
  27.                     WeixinJSBridge.invoke(
  28.                         'getBrandWCPayRequest',
  29.                         wepaydata,
  30.                         function(res) {
  31.                             WeixinJSBridge.log(res.err_msg);
  32.                             // alert(res.err_code + res.err_desc + res.err_msg);
  33.                             // alert(res.err_msg)
  34.                             if (res.err_msg == 'get_brand_wcpay_request:ok') {
  35.                                 $.get(orderurl, { orderid: orderid }, function(resp) {
  36.                                     if (resp.code == '000') {
  37.                                         window.location.href = window.location.href.replace('pay.html', 'success.html');
  38.                                     } else {
  39.                                         alert(resp.msg);
  40.                                         // 一个code只能请求一次, 重新进入index
  41.                                         if (resp.code == '002') {
  42.                                             window.location.href = window.location.href.replace('pay.html', 'index.html');
  43.                                         }
  44.                                     }
  45.                                 });
  46.                             } else {
  47.                                 // 其他支付异常微信有显示消息
  48.                                 // alert(res.err_msg);
  49.                             }
  50.                         }
  51.                     );
  52.                 }
  53.                 window.callpay = function() {
  54.                     if (typeof WeixinJSBridge == "undefined") {
  55.                         if (document.addEventListener) {
  56.                             document.addEventListener('WeixinJSBridgeReady', jsApiCall, false);
  57.                         } else if (document.attachEvent) {
  58.                             document.attachEvent('WeixinJSBridgeReady', jsApiCall);
  59.                             document.attachEvent('onWeixinJSBridgeReady', jsApiCall);
  60.                         }
  61.                     } else {
  62.                         jsApiCall();
  63.                     }
  64.                 }
  65.                 // 发起支付
  66.                 window.callpay();
  67.             } else {
  68.                 alert(resp.msg);
  69.                 // alert(JSON.stringify(resp) + resp.msg);
  70.             }
  71.         }, function(resp) {
  72.             alert(resp)
  73.             alert(JSON.stringify(resp))
  74.             // alert('请求失败, 请重试');
  75.         });
  76. } catch (e) {
  77.     // statements
  78.     alert(e)
  79. }
复制代码

4. 订单查询

订单查询 是为了确认我们的支付是成功的

  1. # 查询微信付款情况
  2. orderid = self.GET.get('orderid')
  3. orderquery = {
  4.     'appid': WPC['APPID'],
  5.     'mch_id': WPC['MCHID'],
  6.     'nonce_str': Utility.getnoncestr(),
  7.     'out_trade_no': WPC['MCHID'] + orderid
  8. }
  9. xml = Utility.getxml(orderquery)
  10. print(xml)
  11. resp = requests.post("https://api.mch.weixin.qq.com/pay/orderquery", data=xml.encode('utf-8'), headers={'Content-Type': 'text/xml'})
  12. msg = resp.text.encode('ISO-8859-1').decode('utf-8')
  13. xmlresp = xmltodict.parse(msg)
  14. print(xmlresp)
  15. orderPaid = 0
  16. if xmlresp['xml']['return_code'] == 'SUCCESS':
  17.     if xmlresp['xml']['result_code'] == 'SUCCESS':
  18.         if xmlresp['xml']['trade_state'] == 'SUCCESS':
  19.             orderPaid = 1
  20.         else:
  21.             msg = xmlresp['xml']['trade_state_desc']
  22.             return JsonResponse(self, '001', msg=smg)
  23.     else:
  24.         msg = xmlresp['xml']['err_code_des']
  25.         return JsonResponse(self, '001', msg=msg)
  26. else:
  27.     msg = xmlresp['xml']['return_msg']
  28.     return JsonResponse(self, '001', msg=msg)
复制代码

官方Demo

SDK与DEMO下载, 用python就需要自己码代码, 当时看的是PHP的

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

精华推荐
  • 探究!做设计之前的“构思”

    探究!做设计之前的“构思”

  • 汉字之美!中文字体设计原则

    汉字之美!中文字体设计原则

  • 一支互联网雪糕的诞生

    一支互联网雪糕的诞生

  • 设计灵感来自何处?

    设计灵感来自何处?

  • 自行车停靠架和旧自行车变废为宝家居创意作品大全

    自行车停靠架和旧自行车变废为宝家居创意作

  • 造车生死局:要么转型,要么死

    造车生死局:要么转型,要么死

  • 从欠8千万到年赚8亿

    从欠8千万到年赚8亿

  • 一座非典型五线小城的日常

    一座非典型五线小城的日常

QQ客服热线
QQ:1090281100 周一至周日:09:00 - 21:00
WeChat:duzhe1069
Email:kaixin1069@vip.qq.com

优创意logo

勿要吝啬你无形资产,请为创新续源,知识、点子、灵感、经验、需求等均是创新源泉,你不经意的一句话将是另一个人的灵感。明天的明天,还有明天,我们应该把握今天,每一个今天,都有一个新的事物在出现,今天的漠视明天的落后,不浪费每一个学习的时刻,学习助力非凡。

技术支持 Discuz! X3.4 - 3.5 beta © 2001-2019 Comsenz Inc.

小黑屋|手机版|优创意 ( 粤ICP备16085288号-1 )|申请友链

粤公网安备 44011102001144 号 GMT+8, 2020-10-26 09:29 , Processed in 0.086404 second(s), 25 queries , Gzip On.

快速回复 返回顶部 返回列表