import hashlib import time from urllib.parse import quote import requests import xmltodict class WechatPayObject: """配置账号信息""" # 微信公众号身份的唯一标识。审核通过后,在微信发送的邮件中查看 def __init__(self): # 开发者调用支付统一下单API生成预交易单 self.APPID = 'wx2a9f5ef9baf2760f' # 商户id self.MCHID = '1508209741' # 异步通知url,商户根据实际开发过程设定 self.NOTIFY_URL = 'test' self.TRADE_TYPE = 'APP' self.APIKEY = 'ZHansjeransjeransjer680301000000' self.url = 'https://api.mch.weixin.qq.com/pay/unifiedorder' # 微信请求url self.error = None self.params = None def get_parameter(self, order_id, body, total_fee, spbill_create_ip, notify_url): self.params = { 'appid': self.APPID, # appid 'mch_id': self.MCHID, # 商户号 'nonce_str': self.getNonceStr(), 'body': body, # 商品描述 'out_trade_no': str(order_id), # 商户订单号 'total_fee': str(int(total_fee)), 'spbill_create_ip': spbill_create_ip, # 127.0.0.1 'trade_type': self.TRADE_TYPE, # 交易类型 'notify_url': notify_url, # 微信支付结果异步通知地址 'receipt': 'Y' } return self.params def getNonceStr(self, length=32): """生成随机字符串""" import random chars = "abcdefghijklmnopqrstuvwxyz0123456789" strs = [] for x in range(length): strs.append(chars[random.randrange(0, len(chars))]) return "".join(strs) def key_value_url(self, value, urlencode): """ 将键值对转为 key1=value1&key2=value2 对参数按照key=value的格式,并按照参数名ASCII字典序排序 """ slist = sorted(value) buff = [] for k in slist: v = quote(value[k]) if urlencode else value[k] buff.append("{0}={1}".format(k, v)) return "&".join(buff) def get_sign(self, params): """ 生成sign 拼接API密钥 """ stringA = self.key_value_url(params, False) stringSignTemp = stringA + '&key=' + self.APIKEY # APIKEY, API密钥,需要在商户后台设置 sign = (hashlib.md5(stringSignTemp.encode("utf-8")).hexdigest()).upper() params['sign'] = sign return params def get_req_xml(self): """ 拼接XML """ self.get_sign(self.params) xml = "" for k, v in self.params.items(): # v = v.encode('utf8') # k = k.encode('utf8') xml += '<' + k + '>' + v + '' xml += "" return xml.encode("utf-8") def get_prepay_id(self): """ 请求获取prepay_id """ xml = self.get_req_xml() respone = requests.post(self.url, xml, headers={'Content-Type': 'application/xml'}) msg = respone.text.encode('ISO-8859-1').decode('utf-8') xmlresp = xmltodict.parse(msg) if xmlresp['xml']['return_code'] == 'SUCCESS': if xmlresp['xml']['result_code'] == 'SUCCESS': prepay_id = xmlresp['xml']['prepay_id'] self.params['prepay_id'] = prepay_id self.params['package'] = "Sign=WXPay" self.params['timestamp'] = str(int(time.time())) return self.params else: return 'failure' else: return 'failure' def re_finall(self): """得到prepay_id后再次签名,返回给终端参数 """ self.get_prepay_id() if self.error: return sign_again_params = { 'appid': self.params['appid'], 'noncestr': self.params['nonce_str'], 'packageId': self.params['package'], 'partnerid': self.params['mch_id'], 'timestamp': self.params['timestamp'], 'prepayid': self.params['prepay_id'] } self.get_sign(sign_again_params) sign_again_params['sign'] = sign_again_params['sign'] return sign_again_params # 返回给app def get_notifypay(self, data): dictdata = dict(data) _dictdata = dict(dictdata['xml']) success = self.get_sign(_dictdata) # print('success', success) if success: success.pop("sign", None) success.pop("sign_type", None) return success else: return None @staticmethod def xml_to_dict(params): """ 拼接XML """ if not isinstance(params, dict): return None xml = "" for k, v in params.items(): # v = v.encode('utf8') # k = k.encode('utf8') xml += '<' + k + '>' + v + '' xml += "" return xml if __name__ == '__main__': # 调用统一支付接口 # 订单id order_id = '12345678903424' # 描述信息 body = 'soober支付' # 价格 total_fee = '50' # 调用微信支付API的机器IP spbill_create_ip = '127.0.0.1' pay = WechatPayObject() # 获取参数 parameter_dict = pay.get_parameter(order_id, body, total_fee, spbill_create_ip) print('parameter_dict', parameter_dict) # parameter_dict 参数中获取MWEB_URL 调转页面在路径后面添加redirect_url # 统一调用接口 response = pay.re_finall() # 回调函数 print('response', response) # 调起支付接口