坑爹的微信支付

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u013473520/article/details/56838677

坑爹的微信支付


上节课我们讲了支付宝支付,这节课我们讲微信支付,微信支付比支付宝支付稍微简单一点,原因在于没有各种非对称加密,不过有一点我们要记得,需要我们自己设计密钥。

class NeoTenpayAgent(object):
    def __init__(self):
        self.partner_id = Config.WEIXIN_MCH_ID
        self.partner_key = Config.WEIXIN_MCH_KEY
        self.app_id = Config.WEIXIN_APP_ID
        self.notify_url = Config.WEIXIN_NOTIFY_URL
        self.session = requests.Session()

    def generate_params(self, user_id, order_no,
        item_name, item_description, price):
        params = {
        'body': item_name,
        'fee_type': 'CNY',
        'notify_url': self.notify_url,
        'out_trade_no': order_no,
        'mch_id': self.partner_id,
        'spbill_create_ip': '196.168.1.1',
        'total_fee': str(price),
        'appid': self.app_id,
        'nonce_str': uuid.uuid4().hex,
        'trade_type': 'APP',
        }
        chunk = '&'.join(
        '{}={}'.format(k, v)
        for k, v in sorted(params.items())
        )
        chunk += '&key=' + self.partner_key
        params['sign'] = hashlib.md5(chunk.encode('utf-8')).hexdigest().upper()

        xml_params = E.xml(
        E.body(params['body']),
        E.fee_type(params['fee_type']),
        E.notify_url(params['notify_url']),
        E.out_trade_no(params['out_trade_no']),
        E.mch_id(params['mch_id']),
        E.spbill_create_ip(params['spbill_create_ip']),
        E.total_fee(params['total_fee']),
        E.appid(params['appid']),
        E.nonce_str(params['nonce_str']),
        E.sign(params['sign']),
        E.trade_type(params['trade_type']),
        )
        data = lxml.etree.tostring(xml_params, encoding='utf-8')
        page = self.session.post(
        'https://api.mch.weixin.qq.com/pay/unifiedorder',
        data=data,
        )
        page.encoding = 'utf-8'
        resp = lxml.etree.fromstring(page.text)
        if resp.xpath('/xml/err_code/text()'):
        for item in resp.xpath('/xml/err_code/text()'):
            err_code = item
        for item in resp.xpath('/xml/err_code_des/text()'):
            err_code_des = item
        if err_code == 'ORDERPAID':
        # 订单已支付,无需再次尝试
            raise ValueError(err_code_des)
        else:
            raise Exception('({}) {}'.format(
        err_code, err_code_des
        ))
        # 调起支付的参数
        for item in resp.xpath('/xml/prepay_id/text()'):
            params = {
            'appid': params['appid'],
            'noncestr': params['nonce_str'],
            'package': 'Sign=WXPay',
            'partnerid': self.partner_id,
            'prepayid': item,
            'timestamp': _timestamp_from_datetime(datetime.now()),
            }
        chunk = '&'.join(
        '{}={}'.format(k, v)
        for k, v in sorted(params.items())
        )
        chunk += '&key=' + self.partner_key
        params['sign'] = hashlib.md5(
        chunk.encode('utf-8')
        ).hexdigest().upper()

        return params

    def verify(self, params):
        params = lxml.etree.fromstring(params)
        if not params.xpath('/xml/sign/text()'):
        raise ValueError('参数 sign 不存在')

        # 值为空的字段不参与签名
        sign_params = {}
        for item in params.xpath('/xml')[0]:
            if item.tag not in ['sign'] and item.text:
                sign_params[item.tag] = item.text
                chunk = '&'.join(
                '{}={}'.format(
                k.decode('utf-8') if isinstance(k, str) else k,
                v.decode('utf-8') if isinstance(v, str) else v,
                )
                for k, v in sorted(sign_params.items())
        )
        chunk = (chunk + '&key=' + self.partner_key).encode('utf-8')
        signature = hashlib.md5(chunk).hexdigest().upper()
        if params.xpath('/xml/sign/text()')[0] != signature:
            raise ValueError('签名不正确')

这就是根据微信后台API设计的商户后台服务器。

值得注意的是,商户回调需要我们自己设计。

def handle_weipay():
    NeoTenpayAgent().verify(request.data.decode('utf-8'))
    import xml.etree.cElementTree as ET
    data = ET.fromstring(request.data.decode('utf-8'))
    data = {d.tag: d.text for d in data}
    if data.get('return_code') == 'SUCCESS':
        order_id = data.get('out_trade_no')
        Ten_or_Ali_order_id = data.get('transaction_id')
        payment_type = '微信'
        payment_state = data.get('result_code')
        subject = data.get('attach', '证件照')
        fee = data.get('total_fee')
        """
        写数据库
        """
        print(payment_state)
    else:
        print('支付失败')
    with open('static/logg/weipaylog.txt', 'at') as f:
        f.write(str(data))
    from xml.etree.cElementTree import Element, tostring
    elem = Element('xml')
    for key, value in {'return_code': 'SUCCESS', 'return_msg': 'OK'}.items():
        child = Element(key)
        child.text = value
        elem.append(child)
    return tostring(elem, encoding='utf-8')

最后我们返回给微信服务器必须要像我那样写。其实代码也不复杂,只不顾业务逻辑比较繁琐。

展开阅读全文

没有更多推荐了,返回首页