統一下單接口json
'https://api.mch.weixin.qq.com/pay/unifiedorder'api
參數:微信
appid:微信公衆號APPIDapp
mch_id :微信的商戶IDdom
nonce_str:32爲之內的隨機字符串post
body:訂單的信息(標題不一樣的支付方式標題的表現形式不一樣)url
out_trade_no:訂單ID(該商品在後臺的ID號)debug
total_fee:訂單金額code
spbill_create_ip:客戶端請求IP地址orm
trade_type:支付類型(APP[app支付],JSAPI[公衆號支付須要openid],MWEB[H5支付])
notify_url:支付回調地址
代碼:
def weixinpay(appid,mch_id,nonce_str,body,order_id,total_fee,trade_type,openid,spbill_create_ip): params = { 'appid':appid, 'mch_id':mch_id, 'nonce_str':nonce_str, 'body':body, 'out_trade_no':order_id, 'total_fee':total_fee, 'spbill_create_ip':spbill_create_ip, 'trade_type':trade_type, 'openid':openid, 'notify_url':''.join(['http://',settings.WAPI_PROXY_DOMAIN,'/wapi/wxpay/notify/']) } if params['openid'] == '': params.pop('openid') return params else: return params
#將鍵值對轉換成key=value&key=value的形式
def key_value(value):
key_sort = sorted(value.keys())
arry=[]
for k in key_sort:
v = str(value.get(k,'')).strip()
v = v.encode('utf-8')
k = k.encode('utf-8')
arry.append('%s=%s'%(k,v))
temp = '&'.join(arry)
return temp
#生成sign
def get_sign(params,APIKEY):
stringA = key_value(params)
stringSignTemp=stringA + '&key=' + APIKEY
sign = (md5(stringSignTemp).hexdigest()).upper()
params['sign'] = sign
return sign
#拼接xml
def get_xml(params,APIKEY):
get_sign(params,APIKEY)
xml = '<xml>'
for k,v in params.items():
k = str(k).encode('utf-8')
v = str(v).encode('utf-8')
xml += '<' + k + '>' + v + '</' + k + '>'
xml += '</xml>'
retrun xml
#經過統一下單接口請求獲取prepay_id
def get_prepay_id(params,APIKEY): xml = get_xml(params,APIKEY) headers = {'Content-Type': 'application/xml'} r = requests.post(url, data=xml, headers=headers) re_xml = ElementTree.fromstring(r.text.encode('utf8')) xml_status = re_xml.getiterator('return_code')[0].text xml_msg = re_xml.getiterator('return_msg')[0].text if len(re_xml.getiterator('result_code')) != 0: xml_result_code = re_xml.getiterator('result_code')[0].text if xml_result_code != 'SUCCESS': xml_err_code = re_xml.getiterator('err_code')[0].text if xml_result_code != 'SUCCESS': return HttpResponseBadRequest({xml_result_code: [u'%s' % xml_err_code]}) if xml_status != 'SUCCESS': error = u"鏈接微信出錯啦!" return error prepay_id = re_xml.getiterator('prepay_id')[0].text params['prepay_id'] = prepay_id if params['trade_type'] != 'JSAPI': params['package'] = 'Sign=WXPay' params['timestamp'] = str(int(time.time()))
獲取prepay_id後再次簽名,返回給終端參數
APIKEY:申請後獲得的密鑰
def re_finall(params,APIKEY): #獲得prepay_id後再次簽名,返回給終端參數 tag = get_prepay_id(params,APIKEY) if not params.has_key('prepay_id'): return tag if params['trade_type'] != 'JSAPI': sign_again_params = { 'appid': params['appid'], 'noncestr': params['nonce_str'], 'package': params['package'], 'partnerid': params['mch_id'], 'timestamp': params['timestamp'], 'prepayid': params['prepay_id'] } sign = get_sign(sign_again_params,APIKEY) params['sign'] = sign return params else: sign_again_params = { 'appId': params['appid'], 'nonceStr': params['nonce_str'], 'package': 'prepay_id='+params['prepay_id'], 'signType': 'MD5', 'timeStamp': params['timestamp'], # 'prepayid': params['prepay_id'] } sign = get_sign(sign_again_params,APIKEY) params['sign'] = sign return params
#驗證簽名:
def checkSign(params,APIKEY): signlocal = params.pop('sign') sign = get_sign(params,APIKEY) if sign != signlocal: return False return True
支付回調信息:
def create(self, request, *args, **kwargs): out_trade_no = str(request.POST.get('out_trade_no')) appid = int(request.POST.get('app',0)) log.debug(out_trade_no) data = get_object_or_404(WxNotify,out_trade_no = out_trade_no) params = {} params['appid'] = data.appid params['mch_id'] = data.mch_id params['nonce_str'] = data.nonce_str params['transaction_id'] = data.transaction_id params['out_trade_no'] =data.out_trade_no params['out_refund_no'] = str(RindomStr(16)) params['total_fee'] = data.total_fee params['refund_fee'] = data.total_fee params['op_user_id'] = data.mch_id # params['sign'] = get_sign(params) thirdinfo_paths = thirdinfo_path(appid) xml = get_xml(params,thirdinfo_paths.APIKEY) # headers = {'Content-Type': 'application/xml'} # r = requests.post(refund_url, data=xml, headers=headers) # log.debug(r.content) r = postXmlSSL(xml,refund_url,thirdinfo_paths.SSLCERT_PATH,thirdinfo_paths.SSLKEY_PATH,second=30,cert=True,post=True) log.debug(r) options = optparse.Values({"pretty": False}) jsonstr = json.loads(xml2json(r,options))['xml'] # convertedDict = xmltodict.parse(r) # log.debug(convertedDict) # jsonStr = json.dumps(convertedDict) # jsonstr = jsonStr.replace('\\','') try: data = request.POST.copy() data.update(jsonstr) log.debug(data) f = RefundInfoForm(data,request=request) if f.is_valid(): f.save() else: raise FormValidationError(f) except: log.debug(jsonstr) if jsonstr['result_code'] == 'SUCCESS': pay_order = PayOrder.objects.all().filter(order_id=out_trade_no) ########################################################################## #若是type爲退貨,則修改退貨狀態爲完成,同時更新退貨完成時間,payorder的狀態不修改 type = request.POST.get('type','') if type == 'salesreturn': refundstatus = get_object_or_404(RefundStatus,payorder=pay_order) refundstatus.status = 'complete' refundstatus.f_time = datetime.datetime.now() refundstatus.save() return jsonstr ########################################################################## pay_order.update(status="closed") return jsonstr