Python实现微信刷卡支付(条码支付)MicroPay

    转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/7686765.html

    一:资料阅读

    场景介绍:https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=5_1

    支付流程:https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=5_4

    提交刷卡支付:https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_10&index=1

    查询订单支付结果:https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_2

    二:配置信息准备

# ========支付相关配置信息===========
    _APP_ID = "";  # 公众账号appid
    _MCH_ID = "";  # 商户号
    _API_KEY = "";  # 微信商户平台(pay.weixin.qq.com) -->账户设置 -->API安全 -->密钥设置,设置完成后把密钥复制到这里
    _host_name = socket.gethostname()
    _ip_address = socket.gethostbyname(_host_name)
    _CREATE_IP = _ip_address;  # 发起支付ip

    # 有关url
    _MICROPAY_URL = "https://api.mch.weixin.qq.com/pay/micropay"; #刷卡支付api
    _QUERY_URL = "https://api.mch.weixin.qq.com/pay/orderquery"; #查询订单支付结果api

    

    三:编写刷卡支付工具类

    1:辅助函数

    def get_sign_for_wx(self, para, key):
        '''
        根据算法, 生成微信支付签名
        :param cr:
        :param uid:
        :param para:
        :param context:
        :return:
        '''
        keylist = list(para.keys())
        keylist.sort()
        s = ''
        for i in range(len(keylist)):
            s += str(keylist[i]) + '=' + str(para[keylist[i]])
            if i != len(keylist) - 1:
                s += '&'
        s += '&key=' + key
        signmd5 = hashlib.md5()
        signmd5.update(s)
        sign = (signmd5.hexdigest()).upper()
        return sign

    #拼接xml字符串
    def get_xml_data(self, doc, para):
        root = doc.createElement('xml')
        doc.appendChild(root)
        for key, value in sorted(para.items()):
            new_node = doc.createElement(key)
            node_value = doc.createTextNode(str(value))
            new_node.appendChild(node_value)
            root.appendChild(new_node)
        return doc

    2:提交刷卡支付

    def do_micropay(self,orderid,goodsName,goodsPrice,authCode,**kwargs):
        '''
        刷卡支付
        '''
        appid = self._APP_ID
        mch_id = self._MCH_ID
        key = self._API_KEY
        nonce_str = str(int(round(time.time() * 1000))) + str(random.randint(1, 999)) + string.join(random.sample(
            ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u',
             'v', 'w', 'x', 'y', 'z'], 5)).replace(" ", "")
        spbill_create_ip = self._CREATE_IP

        params = {}
        params['appid'] = appid
        params['mch_id'] = mch_id
        params['nonce_str'] = nonce_str
        params['out_trade_no'] = orderid.encode('utf-8')  # 客户端生成并传过来,参数必须用utf8编码,否则报错
        params['total_fee'] = goodsPrice  # 单位是分,必须是整数
        params['spbill_create_ip'] = spbill_create_ip
        params['body'] = goodsName.encode('utf-8')  # 中文必须用utf-8编码,否则xml格式错误
        params['auth_code'] = authCode

        doc = dom.Document()
        self.get_xml_data(doc, params)
        sign = self.get_sign_for_wx(params, self._API_KEY)
        params['sign'] = sign
        signnode = doc.createElement('sign')
        signvalue = doc.createTextNode(sign)
        signnode.appendChild(signvalue)
        doc.getElementsByTagName('xml')[0].appendChild(signnode)

        # 向微信刷卡支付发出请求
        req = urllib2.Request(self._MICROPAY_URL)
        req.headers['Content-Type'] = 'text/xml'
        req.data = doc.toprettyxml()
        res_data = urllib2.urlopen(req)

        # 提取支付结果
        res_read = res_data.read()
        doc = xmltodict.parse(res_read)
        return_code = doc['xml']['return_code']

        # 结果分析
        # 此字段是通信标识,非交易标识,交易是否成功需要查看result_code来判断
        if return_code == 'SUCCESS':
            result_code = doc['xml']['result_code']
            # 业务结果
            if result_code == 'SUCCESS':
                    buyer = doc['xml']['openid'] #支付者id
                    return (True, 'SUCCESS', u'支付成功 ',buyer)
            elif result_code == 'FAIL':
                error_code =  doc['xml']['err_code']
                error_code_des =  doc['xml']['err_code_des']
                return (False, error_code, error_code_des,'')
        else:
            return_msg = doc['xml']['return_msg']
            return (False, return_code, return_msg,'')

    3:根据订单号查询支付结果

    def do_micropay_query(self,orderid):
        appid = self._APP_ID
        mch_id = self._MCH_ID
        key = self._API_KEY
        out_trade_no = orderid.encode('utf-8')  # 客户端生成并传过来,参数必须用utf8编码,否则报错
        nonce_str = str(int(round(time.time() * 1000))) + str(random.randint(1, 999)) + string.join(random.sample(
            ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u',
             'v', 'w', 'x', 'y', 'z'], 5)).replace(" ", "")

        params = {}
        params['appid'] = appid
        params['mch_id'] = mch_id
        params['nonce_str'] = nonce_str
        params['out_trade_no'] = out_trade_no

        doc = dom.Document()
        self.get_xml_data(doc, params)
        sign = self.get_sign_for_wx(params, self._API_KEY)
        params['sign'] = sign
        signnode = doc.createElement('sign')
        signvalue = doc.createTextNode(sign)
        signnode.appendChild(signvalue)
        doc.getElementsByTagName('xml')[0].appendChild(signnode)

        # 发出查询请求
        req = urllib2.Request(self._QUERY_URL)
        req.headers['Content-Type'] = 'text/xml'
        req.data = doc.toprettyxml()
        res_data = urllib2.urlopen(req)

        # 返回查询结果
        res_read = res_data.read()
        doc = xmltodict.parse(res_read)
        return_code = doc['xml']['return_code']

        if return_code == 'SUCCESS':
            result_code = doc['xml']['result_code']
            # 业务结果
            if result_code == 'SUCCESS':
                trade_state = doc['xml']['trade_state']
                #支付成功
                if trade_state == 'SUCCESS':
                    buyer = doc['xml']['openid']
                    return (True, 'SUCCESS', u'支付成功 ',buyer)
                #未支付、支付中
                elif trade_state == 'NOTPAY':
                    return (False, 'NOTPAY', u'未支付','')
                elif trade_state == 'USERPAYING':
                    return (False, 'USERPAYING', u'支付中','')
                #支付关闭、撤销、失败
                elif trade_state == 'CLOSED':
                    return (False, 'CLOSED', u'支付关闭','')
                elif trade_state == 'REVOKED':
                    return (False, 'REVOKED', u'支付撤销','')
                elif trade_state == 'PAYERROR':
                    return (False, 'PAYERROR', u'支付失败','')
            else:
                error_code =  doc['xml']['err_code']
                error_code_des =  doc['xml']['err_code_des']
                return (False, error_code, error_code_des,'')
        else:
            return_msg = doc['xml']['return_msg']
            return (False, return_code, return_msg,'')

    

    

原文地址:https://www.cnblogs.com/ygj0930/p/7686765.html