小程序支付

业务流程时序图 官方文档

 步骤:

1. Openid 

在小程序初次加载的时候就已经获取(详情见 小程序登录)

2. 生成商户订单

1.商品信息由小程序端提供
2.提供支付统一下单接口所需参数

3. 调用支付统一下单API

官方文档

4. 拿到返回预付单信息并处理

5. 再次签名

官方文档

案例:

小程序端

test.wxml
<button bind:tap="pay">支付</button>
test.js
Page({
pay:function(){
    wx.request({
      url: "http://127.0.0.1:8000/pay/",
      method: "POST",
      data:{"login_key":wx.getStorageSync("login_key")},
      header: { "content-type": "application/json" },
      success: function (e) {
        console.log(e)
        // 签权调起支付
        wx.requestPayment({
          'timeStamp': e.data.data.timeStamp,
          'nonceStr': e.data.data.nonceStr,
          'package': e.data.data.package,
          'signType': e.data.data.signType,
          'paySign': e.data.data.paySign,
          'success': function (res)
           {
             console.log(res,"成功")
            },
          'fail': function (res)
          {
            console.log("支付失败",res)
           },
        })
      }
    })
  },
})

后端 django

wx
    ├── settings.py     # 小程序id,code2Session等配置
    ├── wx_login.py     # 用于调用code2Session拿到openid等
    └── WXBizDataCrypt.py   # 获取用户授权信息的解密算法,官方下载
wx/settings.py
AppId="..."

AppSecret="..."

code2Session="https://api.weixin.qq.com/sns/jscode2session?appid=&secret=&js_code=&grant_type=authorization_code" pay_mchid ='...' pay_apikey = '...'

项目/views.py
from rest_framework.views import  APIView
from  rest_framework.response import  Response
from django.core.cache import cache
import hashlib,time
import random
from app01.wx import settings
import requests
class Pay(APIView):
    def post(self,request):
        param=request.data
        if param.get("login_key"):
#从redis中拿到小程序端login_key所对应得opendi&session_key值 openid,session_key
=cache.get(param.get("login_key")).split("&") self.openid=openid # 获取用户IP # 1.如果是Nginx做的负载就要HTTP_X_FORWARDED_FOR if request.META.get('HTTP_X_FORWARDED_FOR'): self.ip =request.META['HTTP_X_FORWARDED_FOR'] else: # 2.如果没有用Nginx就用REMOTE_ADDR self.ip = request.META['REMOTE_ADDR'] # 调用 生成商户订单 方法 data = self.pay() return Response({"code":200,"msg":"ok","data":data}) else: return Response({"code":200,"msg":"缺少参数"})
</span><span style="color: #0000ff;">def</span><span style="color: #000000;"> get_str(self):
    str_all</span>=<span style="color: #800000;">"</span><span style="color: #800000;">1234567890abcdefghjklmasdwery</span><span style="color: #800000;">"  # 注意 开发活动功能时, 去掉1,i,0,o</span><span style="color: #000000;">
    nonce_str</span>=<span style="color: #800000;">""</span>.join(random.sample(str_all,20<span style="color: #000000;">))
    </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> nonce_str

</span><span style="color: #0000ff;">def</span><span style="color: #000000;"> get_order(self):
    order_id</span>=str(time.strftime(<span style="color: #800000;">"</span><span style="color: #800000;">%Y%m%d%H%M%S</span><span style="color: #800000;">"</span><span style="color: #000000;">))
    </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> order_id

</span><span style="color: #008000;">#</span><span style="color: #008000;"> 处理返回预付单方法</span>
<span style="color: #0000ff;">def</span><span style="color: #000000;"> xml_to_dict(self,data):
    </span><span style="color: #0000ff;">import</span><span style="color: #000000;"> xml.etree.ElementTree as ET
    xml_dict</span>=<span style="color: #000000;">{}
    data_dic</span>=<span style="color: #000000;">ET.fromstring(data)
    </span><span style="color: #0000ff;">for</span> item <span style="color: #0000ff;">in</span><span style="color: #000000;"> data_dic:
        xml_dict[item.tag]</span>=<span style="color: #000000;">item.text
    </span><span style="color: #0000ff;">return</span><span style="color: #000000;">  xml_dict

</span><span style="color: #008000;">#</span><span style="color: #008000;"> 获取sign签名方法</span>
<span style="color: #0000ff;">def</span><span style="color: #000000;"> get_sign(self):
    data_dic </span>=<span style="color: #000000;"> {
        </span><span style="color: #800000;">"</span><span style="color: #800000;">nonce_str</span><span style="color: #800000;">"</span><span style="color: #000000;">: self.nonce_str,
        </span><span style="color: #800000;">"</span><span style="color: #800000;">out_trade_no</span><span style="color: #800000;">"</span><span style="color: #000000;">: self.out_trade_no,
        </span><span style="color: #800000;">"</span><span style="color: #800000;">spbill_create_ip</span><span style="color: #800000;">"</span><span style="color: #000000;">: self.ip,
        </span><span style="color: #800000;">"</span><span style="color: #800000;">notify_url</span><span style="color: #800000;">"</span><span style="color: #000000;">: self.notify_url,
        </span><span style="color: #800000;">"</span><span style="color: #800000;">openid</span><span style="color: #800000;">"</span><span style="color: #000000;">: self.openid,
        </span><span style="color: #800000;">"</span><span style="color: #800000;">body</span><span style="color: #800000;">"</span><span style="color: #000000;">: self.body,
        </span><span style="color: #800000;">"</span><span style="color: #800000;">trade_type</span><span style="color: #800000;">"</span>: <span style="color: #800000;">"</span><span style="color: #800000;">JSAPI</span><span style="color: #800000;">"</span><span style="color: #000000;">,
        </span><span style="color: #800000;">"</span><span style="color: #800000;">appid</span><span style="color: #800000;">"</span><span style="color: #000000;">: self.appid,
        </span><span style="color: #800000;">"</span><span style="color: #800000;">total_fee</span><span style="color: #800000;">"</span><span style="color: #000000;">: self.total_fee,
        </span><span style="color: #800000;">"</span><span style="color: #800000;">mch_id</span><span style="color: #800000;">"</span><span style="color: #000000;">: self.mch_id
    }
    sign_str </span>= <span style="color: #800000;">"</span><span style="color: #800000;">&amp;</span><span style="color: #800000;">"</span>.join([f<span style="color: #800000;">"</span><span style="color: #800000;">{k}={data_dic[k]}</span><span style="color: #800000;">"</span> <span style="color: #0000ff;">for</span> k <span style="color: #0000ff;">in</span><span style="color: #000000;"> sorted(data_dic)])
    sign_str </span>= f<span style="color: #800000;">"</span><span style="color: #800000;">{sign_str}&amp;key={settings.pay_apikey}</span><span style="color: #800000;">"</span><span style="color: #000000;">
    md5 </span>=<span style="color: #000000;"> hashlib.md5()
    md5.update(sign_str.encode(</span><span style="color: #800000;">"</span><span style="color: #800000;">utf-8</span><span style="color: #800000;">"</span><span style="color: #000000;">))
    </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> md5.hexdigest().upper()

</span><span style="color: #ff0000;"># 1.生成商户订单 提供 支付统一下单 所需参数</span>
<span style="color: #0000ff;">def</span><span style="color: #000000;"> pay(self):
    self.appid</span>=<span style="color: #000000;">settings.AppId
    self.mch_id</span>=<span style="color: #000000;">settings.pay_mchid
    self.nonce_str</span>=<span style="color: #000000;">self.get_str()
    self.body</span>=<span style="color: #800000;">"商品名</span><span style="color: #800000;">"</span>  <span style="color: #008000;">#</span><span style="color: #008000;"> 商品名一般由小程序端传到后端</span>
    self.out_trade_no=<span style="color: #000000;">self.get_order()
    self.total_fee</span>=1<span style="color: #000000;">
    self.spbill_create_ip</span>=<span style="color: #000000;">self.ip
    self.notify_url</span>=<span style="color: #800000;">"</span><span style="color: #800000;">http://www.baidu.com</span><span style="color: #800000;">"</span><span style="color: #000000;">
    self.trade_type</span>=<span style="color: #800000;">"</span><span style="color: #800000;">JSAPI</span><span style="color: #800000;">"</span><span style="color: #000000;">
    self.sign </span>= self.get_sign()  <span style="color: #008000;">#</span><span style="color: #008000;"> 获取sign 签名</span>
    data=f<span style="color: #800000;">'''</span><span style="color: #800000;">
    &lt;xml&gt;
           &lt;appid&gt;{self.appid}&lt;/appid&gt;
           &lt;body&gt;{ self.body}&lt;/body&gt;
           &lt;mch_id&gt;{self.mch_id}&lt;/mch_id&gt;
           &lt;nonce_str&gt;{self.nonce_str}&lt;/nonce_str&gt;
           &lt;notify_url&gt;{self.notify_url}&lt;/notify_url&gt;
           &lt;openid&gt;{self.openid}&lt;/openid&gt;
           &lt;out_trade_no&gt;{self.out_trade_no}&lt;/out_trade_no&gt;
           &lt;spbill_create_ip&gt;{self.spbill_create_ip}&lt;/spbill_create_ip&gt;
           &lt;total_fee&gt;{self.total_fee}&lt;/total_fee&gt;
           &lt;trade_type&gt;{self.trade_type}&lt;/trade_type&gt;
           &lt;sign&gt;{self.sign}&lt;/sign&gt;
    &lt;/xml&gt;
    </span><span style="color: #800000;">'''</span>
    <span style="color: #ff0000;"># 2.支付统一下单</span>
    url=<span style="color: #800000;">"</span><span style="color: #800000;">https://api.mch.weixin.qq.com/pay/unifiedorder</span><span style="color: #800000;">"</span>
    <span style="color: #ff0000;"># 3.返回预付单信息</span>
    response=requests.post(url,data.encode(<span style="color: #800000;">"</span><span style="color: #800000;">utf-8</span><span style="color: #800000;">"</span>),headers={<span style="color: #800000;">"</span><span style="color: #800000;">content-type</span><span style="color: #800000;">"</span>:<span style="color: #800000;">"</span><span style="color: #800000;">application/xml</span><span style="color: #800000;">"</span><span style="color: #000000;">})
    res_data</span>=<span style="color: #000000;">self.xml_to_dict(response.content)
    data</span>=self.two_sign(res_data[<span style="color: #800000;">"</span><span style="color: #800000;">prepay_id</span><span style="color: #800000;">"</span><span style="color: #000000;">])
    </span><span style="color: #0000ff;">return</span><span style="color: #000000;">  data

</span><span style="color: #ff0000;"># 4.将组合数据再次签名</span>
<span style="color: #0000ff;">def</span><span style="color: #000000;"> two_sign(self,prepay_id):
    timeStamp</span>=<span style="color: #000000;">str(int(time.time()))
    nonceStr</span>=<span style="color: #000000;">self.get_str()
    data_dict</span>=<span style="color: #000000;">{
        </span><span style="color: #800000;">"</span><span style="color: #800000;">appId</span><span style="color: #800000;">"</span><span style="color: #000000;">:settings.AppId,
        </span><span style="color: #800000;">"</span><span style="color: #800000;">timeStamp</span><span style="color: #800000;">"</span><span style="color: #000000;">:timeStamp,
        </span><span style="color: #800000;">"</span><span style="color: #800000;">nonceStr</span><span style="color: #800000;">"</span><span style="color: #000000;">:nonceStr,
        </span><span style="color: #800000;">"</span><span style="color: #800000;">package</span><span style="color: #800000;">"</span>:f<span style="color: #800000;">"</span><span style="color: #800000;">prepay_id={prepay_id}</span><span style="color: #800000;">"</span><span style="color: #000000;">,
        </span><span style="color: #800000;">"</span><span style="color: #800000;">signType</span><span style="color: #800000;">"</span>:<span style="color: #800000;">"</span><span style="color: #800000;">MD5</span><span style="color: #800000;">"</span><span style="color: #000000;">
    }
    sign_str </span>= <span style="color: #800000;">"</span><span style="color: #800000;">&amp;</span><span style="color: #800000;">"</span>.join([f<span style="color: #800000;">"</span><span style="color: #800000;">{k}={data_dict[k]}</span><span style="color: #800000;">"</span> <span style="color: #0000ff;">for</span> k <span style="color: #0000ff;">in</span><span style="color: #000000;"> sorted(data_dict)])
    sign_str </span>= f<span style="color: #800000;">"</span><span style="color: #800000;">{sign_str}&amp;key={settings.pay_apikey}</span><span style="color: #800000;">"</span><span style="color: #000000;">
    md5 </span>=<span style="color: #000000;"> hashlib.md5()
    md5.update(sign_str.encode(</span><span style="color: #800000;">"</span><span style="color: #800000;">utf-8</span><span style="color: #800000;">"</span><span style="color: #000000;">))
    sign</span>=<span style="color: #000000;">md5.hexdigest().upper()
    data_dict[</span><span style="color: #800000;">"</span><span style="color: #800000;">paySign</span><span style="color: #800000;">"</span>]=<span style="color: #000000;">sign
    data_dict.pop(</span><span style="color: #800000;">"</span><span style="color: #800000;">appId</span><span style="color: #800000;">"</span><span style="color: #000000;">)
    </span><span style="color: #ff0000;"># 5.返回支付参数到小程序端,小程序端获取所需参数向微信服务器发送 调起支付 方法</span>
    <span style="color: #0000ff;">return</span>  data_dict</pre>
项目/urls.py
url(r'^pay/',views.Pay.as_view())
12-21 20:11
查看更多