美文网首页pythonpython第三方模块编程之美-Pyhon
微信支付(python):企业付款到零钱

微信支付(python):企业付款到零钱

作者: 与蟒唯舞 | 来源:发表于2018-07-15 10:37 被阅读294次

    微信支付开发文档:

    总的来说,微信支付很简单,看文档肯定是没有问题的。

    settings.py 文件中的一些配置:

    import os
    
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    
    # 微信支付相关
    WXPAY_APPID = '微信分配的公众账号ID'
    WXPAY_MCHID = '商户号'
    WXPAY_APIKEY = '商户平台设置的密钥KEY'
    
    # 服务器存放证书路径(微信支付签发的)
    WXPAY_CLIENT_CERT_PATH = os.path.join(BASE_DIR, 'key', WXPAY_APPID, 'apiclient_cert.pem')
    WXPAY_CLIENT_KEY_PATH = os.path.join(BASE_DIR, 'key', WXPAY_APPID, 'apiclient_key.pem')
    

    自己封装的工具文件 weixin_pay.py

    # -*- coding: utf-8 -*-
    from __future__ import unicode_literals
    from django.conf import settings
    from random import Random
    import hashlib
    import requests
    import re
    
    
    def get_client_ip(request):
        """
        获取请求IP
        :param request:
        :return:
        """
        ip = ''
        try:
            x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
            if x_forwarded_for:
                ip = x_forwarded_for.split(',')[0]
            else:
                ip = request.META.get('REMOTE_ADDR')
        except:
            pass
        return ip
    
    
    def format_url(params, api_key=None):
        """
        字典序排序
        :param params:
        :param api_key:
        :return:
        """
        url = "&".join(['%s=%s' % (key, params[key]) for key in sorted(params)])
        if api_key:
            url = '%s&key=%s' % (url, api_key)
        return url
    
    
    def calculate_sign(params, api_key):
        """
        计算签名
        :param params:
        :param api_key:
        :return:
        """
        # 签名步骤一:按字典序排序参数, 在string后加入KEY
        url = format_url(params, api_key)
        # 签名步骤二:MD5加密, 所有字符转为大写
        return hashlib.md5(url.encode('utf-8')).hexdigest().upper()
    
    
    def random_str():
        """
        生成32位随机字符串
        :return:
        """
        chars = 'abcdefghijklmnopqrstuvwxyz0123456789'
        random = Random()
        return "".join([chars[random.randint(0, len(chars) - 1)] for i in range(32)])
    
    
    def dict_to_xml(params):
        xml = ["<xml>", ]
        for k, v in params.items():
            xml.append('<%s>%s</%s>' % (k, v, k))
        xml.append('</xml>')
        return ''.join(xml)
    
    
    def dict_to_xml2(params):
        xml = ["<xml>", ]
        for k, v in params.items():
            xml.append('<%s><![CDATA[%s]]></%s>' % (k, v, k))
        xml.append('</xml>')
        return ''.join(xml)
    
    
    def xml_to_dict(xml):
        xml = xml.strip()
        if xml[:5].upper() != "<XML>" and xml[-6:].upper() != "</XML>":
            return None, None
    
        result = {}
        sign = None
        content = ''.join(xml[5:-6].strip().split('\n'))
    
        pattern = re.compile(r"<(?P<key>.+)>(?P<value>.+)</(?P=key)>")
        m = pattern.match(content)
        while m:
            key = m.group("key").strip()
            value = m.group("value").strip()
            if value != "<![CDATA[]]>":
                pattern_inner = re.compile(r"<!\[CDATA\[(?P<inner_val>.+)\]\]>")
                inner_m = pattern_inner.match(value)
                if inner_m:
                    value = inner_m.group("inner_val").strip()
                if key == "sign":
                    sign = value
                else:
                    result[key] = value
    
            next_index = m.end("value") + len(key) + 3
            if next_index >= len(content):
                break
            content = content[next_index:]
            m = pattern.match(content)
    
        return sign, result
    
    
    class WeiXinPay(object):
        def __init__(self, mch_appid, mchid, api_key):
            self.api_key = api_key
            self.url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers"
            self.params = {
                "mch_appid": mch_appid,
                "mchid": mchid
            }
    
        def update_params(self, kwargs):
            self.params["desc"] = "付款描述信息"
            self.params["check_name"] = "NO_CHECK"
            self.params.update(kwargs)
    
        def post_xml(self):
            sign = calculate_sign(self.params, self.api_key)
            self.params["sign"] = sign
            xml = dict_to_xml(self.params)
            # 要特别注意的是需要带证书(微信支付签发的)
            response = requests.post(self.url, data=xml.encode('utf-8'), cert=(settings.WXPAY_CLIENT_CERT_PATH, settings.WXPAY_CLIENT_KEY_PATH))
            return xml_to_dict(response.text)
    
        def post_xml2(self):
            sign = calculate_sign(self.params, self.api_key)
            self.params["sign"] = sign
            xml = dict_to_xml2(self.params)
            # 要特别注意的是需要带证书(微信支付签发的)
            response = requests.post(self.url, data=xml.encode('utf-8'), cert=(settings.WXPAY_CLIENT_CERT_PATH, settings.WXPAY_CLIENT_KEY_PATH))
            return xml_to_dict(response.text)
    
    
    class Pay(WeiXinPay):
        def __init__(self, mch_appid, mchid, api_key):
            super(Pay, self).__init__(mch_appid, mchid, api_key)
    
        def post(self, openid, trade_no, amount, ip, name, nonce_str):
            kwargs = {
                "openid": openid,
                "partner_trade_no": trade_no,
                "amount": amount,
                "spbill_create_ip": ip,
                "re_user_name": name,
                "nonce_str": nonce_str
            }
            self.update_params(kwargs)
            return self.post_xml()[1]
    
    
    class PayQuery(WeiXinPay):
        """
        查询企业付款
        """
        def __init__(self, mch_appid, mchid, api_key):
            super(PayQuery, self).__init__(mch_appid, mchid, api_key)
            self.url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo"
    
        def post(self, trade_no, nonce_str):
            kwargs = {
                "partner_trade_no": trade_no,
                "nonce_str": nonce_str
            }
            self.update_params(kwargs)
            return self.post_xml2()[1]
    

    接下来就是简单的使用了:

    openid = '用户openid'
    trade_no = '随机生成的商户订单号'
    amount = '企业付款金额,单位为分'
    ip = 'Ip地址'
    name = '收款用户姓名'
    nonce_str = '随机字符串'
    pay = Pay(settings.WXPAY_APPID, settings.WXPAY_MCHID, settings.WXPAY_APIKEY)
    response = pay.post(openid, trade_no, amount * 100, ip, name, nonce_str)
    
    if response and response["return_code"] == "SUCCESS":
        if response["result_code"] == "SUCCESS":
            print '付款成功'
    

    一些细节问题还需要根据自己的业务需求进行相应的调整。

    参考链接:
    https://my.oschina.net/u/3757872/blog/1594134

    相关文章

      网友评论

        本文标题:微信支付(python):企业付款到零钱

        本文链接:https://www.haomeiwen.com/subject/gzaupftx.html