前言
微信公眾號(hào)開(kāi)發(fā)又一重要項(xiàng)就是微信支付,如何在微信公眾號(hào)中或者微信自帶的瀏覽器中實(shí)現(xiàn)微信支付呢?這就是本文的目的。
對(duì)于微信支付有幾種分類(lèi),一種是app支付(顧名思義給予一些軟件app使用的)、微信內(nèi)H5支付(什么意思呢,就是微信內(nèi)置的瀏覽器自帶了一些js、css文件,當(dāng)然是微信特有的,上篇博客有講過(guò),獲取到的用戶(hù)昵稱(chēng)帶表情會(huì)亂碼,在微信自帶的瀏覽器你只要將它裝換為utf-8就能正常顯示,原因是內(nèi)置瀏覽器有對(duì)應(yīng)的font文件,所以在內(nèi)置瀏覽器中也有包含了支付功能的js文件,沒(méi)錯(cuò)在微信自帶的瀏覽器中你不用在你的html中引入js都可以使用它的內(nèi)置js,本文會(huì)講解如何用它的js調(diào)起支付)、其它PC端瀏覽器的掃碼支付。
開(kāi)發(fā)流程
- 服務(wù)器
同樣需要服務(wù)器,然后設(shè)置服務(wù)器的域名,比如這里還是設(shè)置域名為:www.show. 。
配置公眾號(hào)收集信息
首先需要一個(gè)有微信支付權(quán)限和網(wǎng)頁(yè)授權(quán)權(quán)限的公眾號(hào),其次需要一個(gè)有微信支付權(quán)限的商戶(hù)號(hào)(商戶(hù)號(hào)就是支付的錢(qián)到哪里)。同樣,登錄公眾平臺(tái)在開(kāi)發(fā)–>基本配置–>公眾號(hào)開(kāi)發(fā)信息里找到公眾號(hào)的開(kāi)發(fā)者ID(AppID)和開(kāi)發(fā)者密碼(AppSecret) ,然后在微信商戶(hù)平臺(tái)里找到mch_id和api密鑰。
注意:必須先在微信公眾平臺(tái)設(shè)置網(wǎng)頁(yè)授權(quán)域名(這個(gè)域名你就填服務(wù)器的www.show. )和在微信商戶(hù)平臺(tái)設(shè)置您的公眾號(hào)支付支付目錄,設(shè)置路徑:商戶(hù)平臺(tái)–>產(chǎn)品中心–>開(kāi)發(fā)配置–>公眾號(hào)支付–>添加(添加一個(gè)支付url,比如你的支付頁(yè)面是:www.show./payment )。公眾號(hào)支付在請(qǐng)求支付的時(shí)候會(huì)校驗(yàn)請(qǐng)求來(lái)源是否有在商戶(hù)平臺(tái)做了配置,所以必須確保支付目錄已經(jīng)正確的被配置,否則將驗(yàn)證失敗,請(qǐng)求支付不成功。
開(kāi)發(fā)流程
微信支付不是說(shuō)一開(kāi)始就傳訂單編號(hào)、價(jià)格、商品等信息去調(diào)用支付的,在調(diào)用支付接口前我們需要先去向微信發(fā)起下單請(qǐng)求,只有發(fā)起下單成功后才能調(diào)用支付接口。
首先配置你的公眾號(hào)、商戶(hù)和回調(diào)頁(yè)面信息,其它值做相應(yīng)修改,參數(shù)文件如下:
# -*- coding: utf-8 -*-
# ----------------------------------------------
# @Time : 18-3-21 上午11:50
# @Author : YYJ
# @File : wechatConfig.py
# @CopyRight: ZDWL
# ----------------------------------------------
"""
微信公眾號(hào)和商戶(hù)平臺(tái)信息配置文件
"""
# ----------------------------------------------微信公眾號(hào)---------------------------------------------- #
# 公眾號(hào)id
APPID = 'appid'
# 公眾號(hào)AppSecret
APPSECRET = 'appscrect'
# ----------------------------------------------微信商戶(hù)平臺(tái)---------------------------------------------- #
# 商戶(hù)id
MCH_ID = 'mc_id'
# 商戶(hù)API秘鑰
API_KEY = 'api秘鑰'
# ----------------------------------------------回調(diào)頁(yè)面---------------------------------------------- #
# 用戶(hù)授權(quán)獲取code后的回調(diào)頁(yè)面,如果需要實(shí)現(xiàn)驗(yàn)證登錄就必須填寫(xiě)
REDIRECT_URI = 'http://meili./index'
PC_LOGIN_REDIRECT_URI = 'http://meili./index'
defaults = {
# 微信內(nèi)置瀏覽器獲取code微信接口
'wechat_browser_code': 'https://open.weixin.qq.com/connect/oauth2/authorize',
# 微信內(nèi)置瀏覽器獲取access_token微信接口
'wechat_browser_access_token': 'https://api.weixin.qq.com/sns/oauth2/access_token',
# 微信內(nèi)置瀏覽器獲取用戶(hù)信息微信接口
'wechat_browser_user_info': 'https://api.weixin.qq.com/sns/userinfo',
# pc獲取登錄二維碼接口
'pc_QR_code': 'https://open.weixin.qq.com/connect/qrconnect',
# 獲取微信公眾號(hào)access_token接口
'mp_access_token': 'https://api.weixin.qq.com/cgi-bin/token',
# 設(shè)置公眾號(hào)行業(yè)接口
'change_industry': 'https://api.weixin.qq.com/cgi-bin/template/api_set_industry',
# 獲取公眾號(hào)行業(yè)接口
'get_industry': 'https://api.weixin.qq.com/cgi-bin/template/get_industry',
# 發(fā)送模板信息接口
'send_templates_message': 'https://api.weixin.qq.com/cgi-bin/message/template/send',
# 支付下單接口
'order_url': 'https://api.mch.weixin.qq.com/pay/unifiedorder',
}
SCOPE = 'snsapi_userinfo'
PC_LOGIN_SCOPE = 'snsapi_login'
GRANT_TYPE = 'client_credential'
STATE = ''
LANG = 'zh_CN'
下面就是支付下單和支付接口調(diào)用的封裝代碼了,其中包括了上一篇博客的授權(quán)登錄代碼和下一篇博客的發(fā)送模板消息的代碼封裝:
# -*- coding: utf-8 -*-
# ----------------------------------------------
# @Time : 18-3-21 下午1:36
# @Author : YYJ
# @File : WechatAPI.py
# @CopyRight: ZDWL
# ----------------------------------------------
import hashlib
import random
import time
from urllib import parse
from xml.etree.ElementTree import fromstring
import requests
from src.beauty.main.wechat.config import wechatConfig
class WechatAPI(object):
def __init__(self):
self.config = wechatConfig
self._access_token = None
self._openid = None
self.config = wechatConfig
self.dic = {}
@staticmethod
def process_response_login(rsp):
"""解析微信登錄返回的json數(shù)據(jù),返回相對(duì)應(yīng)的dict, 錯(cuò)誤信息"""
if 200 != rsp.status_code:
return None, {'code': rsp.status_code, 'msg': 'http error'}
try:
content = rsp.json()
except Exception as e:
return None, {'code': 9999, 'msg': e}
if 'errcode' in content and content['errcode'] != 0:
return None, {'code': content['errcode'], 'msg': content['errmsg']}
return content, None
def process_response_pay(self, rsp):
"""解析微信支付下單返回的json數(shù)據(jù),返回相對(duì)應(yīng)的dict, 錯(cuò)誤信息"""
rsp = self.xml_to_array(rsp)
if 'SUCCESS' != rsp['return_code']:
return None, {'code': '9999', 'msg': rsp['return_msg']}
if 'prepay_id' in rsp:
return {'prepay_id': rsp['prepay_id']}, None
return rsp, None
@staticmethod
def create_time_stamp():
"""產(chǎn)生時(shí)間戳"""
now = time.time()
return int(now)
@staticmethod
def create_nonce_str(length=32):
"""產(chǎn)生隨機(jī)字符串,不長(zhǎng)于32位"""
chars = "abcdefghijklmnopqrstuvwxyz0123456789"
strs = []
for x in range(length):
strs.append(chars[random.randrange(0, len(chars))])
return "".join(strs)
@staticmethod
def xml_to_array(xml):
"""將xml轉(zhuǎn)為array"""
array_data = {}
root = fromstring(xml)
for child in root:
value = child.text
array_data[child.tag] = value
return array_data
def get_sign(self):
"""生成簽名"""
# 簽名步驟一:按字典序排序參數(shù)
key = sorted(self.dic.keys())
buffer = []
for k in key:
buffer.append("{0}={1}".format(k, self.dic[k]))
# self.dic["paySign"] = self.get_sign(jsApiObj)
parm = "&".join(buffer)
# 簽名步驟二:在string后加入KEY
parm = "{0}&key={1}".format(parm, self.config.API_KEY).encode('utf-8')
# 簽名步驟三:MD5加密
signature = hashlib.md5(parm).hexdigest()
# 簽名步驟四:所有字符轉(zhuǎn)為大寫(xiě)
result_ = signature.upper()
return result_
def array_to_xml(self, sign_name=None):
"""array轉(zhuǎn)xml"""
if sign_name is not None:
self.dic[sign_name] = self.get_sign()
xml = ["<xml>"]
for k in self.dic.keys():
xml.append("<{0}>{1}</{0}>".format(k, self.dic[k]))
xml.append("</xml>")
return "".join(xml)
class WechatLogin(WechatAPI):
def get_code_url(self):
"""微信內(nèi)置瀏覽器獲取網(wǎng)頁(yè)授權(quán)code的url"""
url = self.config.defaults.get('wechat_browser_code') + (
'?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect' %
(self.config.APPID, parse.quote(self.config.REDIRECT_URI),
self.config.SCOPE, self.config.STATE if self.config.STATE else ''))
return url
def get_code_url_pc(self):
"""pc瀏覽器獲取網(wǎng)頁(yè)授權(quán)code的url"""
url = self.config.defaults.get('pc_QR_code') + (
'?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect' %
(self.config.APPID, parse.quote(self.config.REDIRECT_URI), self.config.PC_LOGIN_SCOPE,
self.config.STATE if self.config.STATE else ''))
return url
def get_access_token(self, code):
"""獲取access_token"""
params = {
'appid': self.config.APPID,
'secret': self.config.APPSECRET,
'code': code,
'grant_type': 'authorization_code'
}
token, err = self.process_response_login(requests
.get(self.config.defaults.get('wechat_browser_access_token'),
params=params))
if not err:
self._access_token = token['access_token']
self._openid = token['openid']
return self._access_token, self._openid
def get_user_info(self, access_token, openid):
"""獲取用戶(hù)信息"""
params = {
'access_token': access_token,
'openid': openid,
'lang': self.config.LANG
}
return self.process_response_login(requests
.get(self.config.defaults.get('wechat_browser_user_info'), params=params))
class WechatTemplates(WechatAPI):
def __init__(self):
super().__init__()
self.mp_access_token = None
self.mp_expires_in = None
def get_mp_access_token(self):
"""獲取公眾號(hào)的access_token"""
# err_code = {
# '-1': '系統(tǒng)繁忙,請(qǐng)稍候再試',
# '0': '請(qǐng)求成功',
# '40001': 'AppSecret錯(cuò)誤或者AppSecret不屬于這個(gè)公眾號(hào),請(qǐng)開(kāi)發(fā)者確認(rèn)AppSecret的正確性',
# '40002': '請(qǐng)確保grant_type字段值為client_credential',
# '40164': '調(diào)用接口的IP地址不在白名單中,請(qǐng)?jiān)诮涌贗P白名單中進(jìn)行設(shè)置',
# }
url = self.config.defaults.get('mp_access_token') + (
'?grant_type=%s&appid=%s&secret=%s' %
(self.config.GRANT_TYPE, self.config.APPID,
self.config.APPSECRET))
token_data = eval(requests.get(url).content)
if 'access_token' not in token_data:
return token_data['errcode'], token_data['errmsg'], False
else:
self.mp_access_token = token_data['access_token']
self.mp_expires_in = token_data['expires_in']
return self.mp_access_token, self.mp_expires_in, True
# 以下功能暫不使用
# def change_industry(self):
# """設(shè)置所屬行業(yè),每月可修改行業(yè)1次"""
# url = self.config.defaults.get('change_industry') + (
# '?access_token=%s' % self.mp_access_token)
# prams = {
# "industry_id1": "23",
# "industry_id2": "31"
# }
# data = requests.post(url, prams)
#
# def get_industry(self):
# """獲取行業(yè)信息"""
# if self.mp_access_token is None:
# _, msg, success = self.get_mp_access_token()
# if not success:
# return msg, False
# url = self.config.defaults.get('get_industry') + (
# '?access_token=%s' % self.mp_access_token)
# industry_data = requests.get(url)
# if 'primary_industry' in industry_data:
# primary_industry = industry_data['primary_industry']
# secondary_industry = industry_data['secondary_industry']
# return primary_industry, secondary_industry, True
# else:
# return '', '獲取行業(yè)信息錯(cuò)誤', False
#
# def get_templates_id(self):
# pass
#
def send_templates_message(self, touser, template_id, data, url=None, miniprogram=None):
post_data = {
"touser": touser,
"template_id": template_id,
"data": data
}
if url is not None:
post_data['url'] = url
if miniprogram is not None:
post_data['miniprogram'] = miniprogram
url = self.config.defaults.get('send_templates_message') + (
'?access_token=%s' % self.mp_access_token)
back_data = requests.post(url, json=post_data)
print(back_data)
if "errcode" in back_data and back_data["errcode"] == 0:
return True
else:
return False
class WechatPayAPI(WechatAPI):
def __init__(self, package, sign_type=None):
super().__init__()
self.appId = self.config.APPID
self.timeStamp = self.create_time_stamp()
self.nonceStr = self.create_nonce_str()
self.package = package
self.signType = sign_type
self.dic = {"appId": self.appId, "timeStamp": "{0}".format(self.create_time_stamp()),
"nonceStr": self.create_nonce_str(), "package": "prepay_id={0}".format(self.package)}
if sign_type is not None:
self.dic["signType"] = sign_type
else:
self.dic["signType"] = "MD5"
def get_dic(self):
self.dic['paySign'] = self.get_sign()
return self.dic
class WechatOrder(WechatAPI):
def __init__(self, body, trade_type, out_trade_no, total_fee, spbill_create_ip, notify_url, device_info=None,
sign_type=None, attach=None, fee_type=None, time_start=None, time_expire=None, goods_tag=None,
product_id=None, detail=None, limit_pay=None, openid=None, scene_info=None):
super().__init__()
self.device_info = device_info #
self.nonce_str = self.create_nonce_str()
self.sign_type = sign_type #
self.detail = detail #
self.body = body
self.attach = attach #
self.out_trade_no = out_trade_no
self.fee_type = fee_type #
self.total_fee = total_fee
self.spbill_create_ip = spbill_create_ip
self.time_start = time_start #
self.time_expire = time_expire #
self.goods_tag = goods_tag #
self.notify_url = notify_url
self.trade_type = trade_type
self.product_id = product_id #
self.limit_pay = limit_pay #
self.openid = openid #
self.scene_info = scene_info #
self.dic = {"appid": self.config.APPID, "mch_id": self.config.MCH_ID,
"nonce_str": self.nonce_str, "body": self.body,
'out_trade_no': out_trade_no,
'openid': self.openid,
"total_fee": self.total_fee, "spbill_create_ip": self.spbill_create_ip,
"notify_url": self.notify_url,
"trade_type": self.trade_type}
if self.device_info is not None:
self.dic["device_info"] = self.device_info
if self.sign_type is not None:
self.dic["sign_type"] = self.sign_type
if self.detail is not None:
self.dic["detail"] = self.detail
if self.attach is not None:
self.dic["attach"] = self.attach
if self.fee_type is not None:
self.dic["fee_type"] = self.fee_type
if self.time_start is not None:
self.dic["time_start"] = self.time_start
if self.time_expire is not None:
self.dic["time_expire"] = self.time_expire
if self.goods_tag is not None:
self.dic["goods_tag"] = self.goods_tag
if self.product_id is not None:
self.dic["product_id"] = self.product_id
if self.limit_pay is not None:
self.dic["limit_pay"] = self.limit_pay
if self.openid is not None:
self.dic["openid"] = self.openid
if self.scene_info is not None:
self.dic["scene_info"] = self.scene_info
def order_post(self):
if self.config.APPID is None:
return None, True
xml_ = self.array_to_xml('sign')
data = requests.post(self.config.defaults['order_url'], data=xml_.encode('utf-8'),
headers={'Content-Type': 'text/xml'})
return self.process_response_pay(data.content)
上面的WechatOrder類(lèi)就是支付下單,WechatPayAPI類(lèi)是支付請(qǐng)求,你看官方文檔的支付接口,可能剛開(kāi)始你會(huì)問(wèn)怎么調(diào)用這個(gè)接口不傳商品信息和價(jià)格信息啊,其實(shí)這些信息是在支付下單的時(shí)候傳過(guò)去的,下單需要的參數(shù)如下(根據(jù)你的需要填寫(xiě)非必須的字段):
名稱(chēng) |
變量名 |
必填 |
類(lèi)型 |
示例值 |
描述 |
公眾賬號(hào)ID |
appid |
是 |
String(32) |
wxd678efh567hg6787 |
微信支付分配的公眾賬號(hào)ID(企業(yè)號(hào)corpid即為此appId),在我的參數(shù)文件的APPID配置 |
商戶(hù)號(hào) |
mch_id |
是 |
String(32) |
1230000109 |
微信支付分配的商戶(hù)號(hào),在我的參數(shù)文件的MCH_ID配置 |
設(shè)備號(hào) |
device_info |
否 |
String(32) |
013467007045764 |
自定義參數(shù),可以為終端設(shè)備號(hào)(門(mén)店號(hào)或收銀設(shè)備ID),PC網(wǎng)頁(yè)或公眾號(hào)內(nèi)支付可以傳”WEB” |
隨機(jī)字符串 |
nonce_str |
是 |
String(32) |
5K8264ILTKCH16CQ2502SI8ZNMTM67VS |
隨機(jī)字符串,長(zhǎng)度要求在32位以?xún)?nèi),在我的WechatAPI的create_nonce_str() |
簽名 |
sign |
是 |
String(32) |
C380BEC2BFD727A4B6845133519F3AD6 |
通過(guò)簽名算法計(jì)算得出的簽名值,在我的WechatAPI的get_sign() |
簽名類(lèi)型 |
sign_type |
否 |
String(32) |
MD5 |
簽名類(lèi)型,默認(rèn)為MD5,支持HMAC-SHA256和MD5。 |
商品描述 |
body |
是 |
String(128) |
騰訊充值中心-QQ會(huì)員充值 |
商品簡(jiǎn)單描述,該字段請(qǐng)按照規(guī)范傳遞,具體請(qǐng)見(jiàn)官方文檔 |
商品詳情 |
detail |
否 |
String(6000) |
… |
商品詳細(xì)描述,對(duì)于使用單品優(yōu)惠的商戶(hù),改字段必須按照規(guī)范上傳,具體請(qǐng)見(jiàn)官方文檔 |
附加數(shù)據(jù) |
attach |
否 |
String(127) |
深圳分店 |
附加數(shù)據(jù),在查詢(xún)API和支付通知中原樣返回,可作為自定義參數(shù)使用。 |
商戶(hù)訂單號(hào) |
out_trade_no |
是 |
String(32) |
20150806125346 |
商戶(hù)系統(tǒng)內(nèi)部訂單號(hào),要求32個(gè)字符內(nèi),只能是數(shù)字、大小寫(xiě)字母_- |
標(biāo)價(jià)幣種 |
fee_type |
否 |
String(16) |
CNY |
符合ISO 4217標(biāo)準(zhǔn)的三位字母代碼,默認(rèn)人民幣:CNY,詳細(xì)列表請(qǐng)參見(jiàn)貨幣類(lèi)型 |
標(biāo)價(jià)金額 |
total_fee |
是 |
Int |
88 |
訂單總金額,單位為分,詳見(jiàn)支付金額 |
終端IP |
spbill_create_ip |
是 |
String(16) |
123.12.12.123 |
APP和網(wǎng)頁(yè)支付提交用戶(hù)端ip,Native支付填調(diào)用微信支付API的機(jī)器IP。r沒(méi)有獲取到做測(cè)試的時(shí)候可以直接填127.0.0.1 |
交易起始時(shí)間 |
time_start |
否 |
String(14) |
20091225091010 |
訂單生成時(shí)間,格式為yyyyMMddHHmmss,如2009年12月25日9點(diǎn)10分10秒表示為20091225091010。其他詳見(jiàn)官方文檔時(shí)間規(guī)則 |
交易結(jié)束時(shí)間 |
time_expire |
否 |
String(14) |
20091227091010 |
訂單失效時(shí)間,格式為yyyyMMddHHmmss,如2009年12月27日9點(diǎn)10分10秒表示為20091227091010。訂單失效時(shí)間是針對(duì)訂單號(hào)而言的,由于在請(qǐng)求支付的時(shí)候有一個(gè)必傳參數(shù)prepay_id只有兩小時(shí)的有效期,所以在重入時(shí)間超過(guò)2小時(shí)的時(shí)候需要重新請(qǐng)求下單接口獲取新的prepay_id。其他詳見(jiàn)時(shí)間規(guī)則。建議:最短失效時(shí)間間隔大于1分鐘 |
訂單優(yōu)惠標(biāo)記 |
goods_tag |
否 |
String(32) |
WXG |
訂單優(yōu)惠標(biāo)記,使用代金券或立減優(yōu)惠功能時(shí)需要的參數(shù),具體請(qǐng)見(jiàn)官方文檔 |
通知地址 |
notify_url |
是 |
String(256) |
http://www.weixin.qq.com/wxpay/pay.php |
異步接收微信支付結(jié)果通知的回調(diào)地址,通知url必須為外網(wǎng)可訪(fǎng)問(wèn)的url,不能攜帶參數(shù)。 |
交易類(lèi)型 |
trade_type |
是 |
String(16) |
JSAPI |
JSAPI 公眾號(hào)支付、NATIVE 掃碼支付、APP APP支付說(shuō)明詳見(jiàn)參數(shù)規(guī)定 |
商品ID |
product_id |
否 |
String(32) |
12235413214070356458058 |
trade_type=NATIVE時(shí)(即掃碼支付),此參數(shù)必傳。此參數(shù)為二維碼中包含的商品ID,商戶(hù)自行定義。 |
指定支付方式 |
limit_pay |
否 |
String(32) |
no_credit |
上傳此參數(shù)no_credit–可限制用戶(hù)不能使用信用卡支付 |
用戶(hù)標(biāo)識(shí) |
openid |
否 |
String(128) |
oUpF8uMuAJO_M2pxb1Q9zNjWeS6o |
trade_type=JSAPI時(shí)(即公眾號(hào)支付),此參數(shù)必傳,此參數(shù)為微信用戶(hù)在商戶(hù)對(duì)應(yīng)appid下的唯一標(biāo)識(shí)。openid如何獲取,可參考【獲取openid】。企業(yè)號(hào)請(qǐng)使用【企業(yè)號(hào)OAuth2.0接口】獲取企業(yè)號(hào)內(nèi)成員userid,再調(diào)用【企業(yè)號(hào)userid轉(zhuǎn)openid接口】進(jìn)行轉(zhuǎn)換 |
+場(chǎng)景信息 |
scene_info |
否 |
String(256) |
{“store_info” : {“id”: “SZTX001”,”name”: “騰大餐廳”,”area_code”: “440305”,”address”: “科技園中一路騰訊大廈” }} |
該字段用于上報(bào)場(chǎng)景信息,目前支持上報(bào)實(shí)際門(mén)店信息。該字段為JSON對(duì)象數(shù)據(jù),對(duì)象格式為{“store_info”:{“id”: “門(mén)店ID”,”name”: “名稱(chēng)”,”area_code”: “編碼”,”address”: “地址” }} ,字段詳細(xì)說(shuō)明請(qǐng)點(diǎn)擊行前的+展開(kāi) |
接著是我的urls.py文件中加一個(gè)下單支付請(qǐng)求url和支付結(jié)果返回回調(diào)url:
from django.conf.urls import url
from src.beauty.main.wechat.apps.index.views import AuthView, GetInfoView, WechatPay
urlpatterns = [
url(r'^$', views.home),
# 支付下單及請(qǐng)求
url(r'^wechatPay$', WechatPay.as_view()),
# 授權(quán)請(qǐng)求
url(r'^auth/$', AuthView.as_view()),
# 之前的授權(quán)回調(diào)頁(yè)面
url(r'^index$', GetInfoView.as_view()),
# 調(diào)起支付后返回結(jié)果的回調(diào)頁(yè)面
url(r'^success$', views.success),
# 這里我省掉了我的其它頁(yè)面
]
然后是我的views.py文件,我只展示支付和結(jié)果返回的view:
from django.contrib.auth import logout, authenticate, login
from django.contrib.auth.backends import ModelBackend
# from django.core import serializers
import json
import requests
import base64
import random
import time
from datetime import datetime, date
from django.core.serializers.json import DjangoJSONEncoder
from django.db.models import Q
from django.http import HttpResponse, HttpResponseServerError
from django.shortcuts import render, redirect
# from src.beauty.main.wechat.utils.wechatAPI import WechatAPI
from src.beauty.main.wechat.utils.WechatAPI import WechatLogin, WechatTemplates, WechatOrder, WechatPayAPI
from django.views.generic import View
from django.conf import settings
from django.http import HttpResponseRedirect
class WechatPay(View):
@staticmethod
def post(request):
# 這個(gè)if判斷是我傳入的訂單的id,測(cè)試的時(shí)候沒(méi)有傳入,你可以測(cè)試的時(shí)候去掉這個(gè)判斷
if 'order' in request.POST:
# order = request.POST['order']
# order = Order.objects.filter(is_effective=True).filter(uuid=order).first()
body = 'JSP支付測(cè)試'
trade_type = 'JSAPI'
import random
rand = random.randint(0, 100)
out_trade_no = 'HSTY3JMKFHGA325' + str(rand)
total_fee = 1
spbill_create_ip = '127.0.0.1'
notify_url = 'http://www.show./success'
order = WechatOrder(body=body,
trade_type=trade_type,
out_trade_no=out_trade_no,
openid=request.session['openid'],
total_fee=total_fee,
spbill_create_ip=spbill_create_ip,
notify_url=notify_url)
datas, error = order.order_post()
if error:
return HttpResponseServerError('get access_token error')
order_data = datas['prepay_id'].encode('iso8859-1').decode('utf-8'),
pay = WechatPayAPI(package=order_data[0])
dic = pay.get_dic()
dic["package"] = "prepay_id=" + order_data[0]
return HttpResponse(json.dumps(dic), content_type="application/json")
def success(request):
# 這里寫(xiě)支付結(jié)果的操作,重定向
return redirect('/')
最后在你的需要支付頁(yè)面的html中添加如下:
<script>
function onBridgeReady(data){
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId": data.appId, //公眾號(hào)名稱(chēng),由商戶(hù)傳入
"timeStamp": data.timeStamp, //時(shí)間戳,自1970年以來(lái)的秒數(shù)
"nonceStr": data.nonceStr, //隨機(jī)串
"package": data.package, //訂單id,這是微信下單微信生成的訂單id不是你自己的
"signType":"MD5", //微信簽名方式:
"paySign": data.paySign //微信簽名
}, function(res){
if(res.err_msg == "get_brand_wcpay_request:ok" ) {
# 支付成功的跳轉(zhuǎn)頁(yè)面,我這里跳到了首頁(yè)
window.location.href = '/';
} // 使用以上方式判斷前端返回,微信團(tuán)隊(duì)鄭重提示:res.err_msg將在用戶(hù)支付成功后返回ok,但并不保證它絕對(duì)可靠。
});
}
# 點(diǎn)擊支付的響應(yīng)函數(shù),調(diào)起下單請(qǐng)求,并返回支付需要上傳的數(shù)據(jù)(都在data里)
$('#wechatPay').click(function(){
var order = $(this).data('parm');
$.ajaxSetup({
data: {csrfmiddlewaretoken: '{{ csrf_token }}'},
});
$.ajax({
type: 'POST',
url: '/wechatPay',
data: {
'order': order
},
dataType: 'json',
success: function (data) {
if (typeof WeixinJSBridge == "undefined"){
if( document.addEventListener ){
document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
}else if (document.attachEvent){
document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
}
}else{
onBridgeReady(data);
}
},
error: function () {
}
});
});
</script>
結(jié)語(yǔ)
中間配置有問(wèn)題歡迎留言,這是我的調(diào)用結(jié)果:

|