python3封装微信分账功能

之前一篇文章介绍python3封装成类调用微信JSAPI下单、支付、生成付款码,本文介绍python实现微信分账功能。
微信支付里面分账接口调用时需要证书,本文介绍python使用证书。

1 JSAPI文档地址

JSAPI文档,普通商户微信分账是通过https请求实现的。

2 代码实现

封装一个类WxPay,实现微信分账,有如下接口:

  • 普通商户添加分账接收方
  • 普通商户删除分账接收方
  • 普通商户单次分账请求
  • 普通商户查询分账请求
  • 普通商户完结分账
2.1 类主体框架
import logging
import requests
import time
import json
import hmac
import hashlib

headers = {
    'Accept': 'application/json, text/javascript, */*; q=0.01',
    'Accept-Encoding': 'gzip, deflate, br',
    'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
    'Cache-Control': 'no-cache',
    'Connection': 'keep-alive',
    'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
    'Pragma': 'no-cache',
    'User-Agent': 'self-defind-user-agent',
    'Cookie': 'name=self-define-cookies-in header',
    'X-Requested-With': 'XMLHttpRequest'
}

def get_md5(data, salt=True):
    if salt:
        return hashlib.md5('get{0}{1}md5'.format(data, time.time()).encode(encoding='UTF-8')).hexdigest()
    else:
        return hashlib.md5(data.encode(encoding='UTF-8')).hexdigest()

class WxPay:
    __key = 'xxxxxxxx'  # 商户API密钥,自己的商户密钥
    __appid = 'xxxxxxxxx'  # 小程序ID(是),自己的小程序ID
    __mch_id = 'xxxxxx'  # 商户号,自己的商户号
    __device_info = ''  # 设备号(否),这里用门店号做参数
    __nonce_str = ''  # 随机字符串(是)
    __sign = ''  # 签名(是)
    __body = ''  # 商品描述(是)
    __out_trade_no = ''  # 商户订单号(是),传入系统商品订单
    __total_fee = ''  # 标价金额(是),订单总金额,单位为分
    __spbill_create_ip = ''  # 终端IP(是)
    __notify_url = 'https://www.xxxxxx.com/'  # 通知地址(是),填项自己的url地址
    __trade_type = 'JSAPI'  # 交易类型(是),小程序支付
    __cert_name = 'xxxx.p12' # 证书名称
    __cert_pwd = 'xxxxx'  # 同__mch_id
2.2 生成随机字符串函数

在类里面定义随机字符串生成函数,代码如下:

	@staticmethod
    def get_nonce_str():
        return get_md5(WxPay.__appid)
2.3 生成MD5签名函数

在类里面定义签名字符串生成函数,代码如下:

	@staticmethod
    def get_sign_str(sign_dict: dict):
        data = ''
        sort_keys = sorted(sign_dict)  # 从小到大排序
        for i, key in enumerate(sort_keys):
            data += '{0}={1}&'.format(key, sign_dict.get(key, ''))
        data += 'key={0}'.format(WxPay.__key)
        print(data)

        return get_md5(data, False).upper()

注意:签名里面的key一定要先按升序排序,再组合生成MD5

2.4 生成HMAC-SHA256签名函数
	@staticmethod
    def create_hmac_sha256_signature(key: str, message: str):
        byte_key = key.encode('utf-8')
        message = message.encode('utf-8')
        return hmac.new(byte_key, message, hashlib.sha256).hexdigest().upper()

    @staticmethod
    def get_sign_strc_hmac_sha256(sign_dict: dict):
        data = ''
        sort_keys = sorted(sign_dict)  # 从小到大排序
        for i, key in enumerate(sort_keys):
            data += '{0}={1}&'.format(key, sign_dict.get(key, ''))
        data += 'key={0}'.format(WxPay.__key)
        print(data)

        return WxPay.create_hmac_sha256_signature(WxPay.__key, data)
2.5 数据转换函数
	@staticmethod
    def get_xml_str(sign_dict: dict):
        xml_data = '<xml>'
        for k, v in sign_dict.items():
            xml_data += '<{0}>{1}</{0}>'.format(k, v)
        xml_data += '</xml>'
        # print(xml_data)

        return xml_data

	@staticmethod
	def xml_to_dict(xml_data: str):
	    dict_data = {}
	    result = xml_data.split('\n')
	    for res in result:
	        if 'total_fee' in res:
	            dict_data['total_fee'] = res.split('<total_fee>')[-1].split('<')[0]
	            continue
	
	        tmp1 = res.split('><![CDATA[')
	        if len(tmp1) == 2:
	            tmp2, tmp3 = tmp1[0].split('<'), tmp1[1].split(']')
	            dict_data[tmp2[-1]] = tmp3[0] if tmp3 else ''
	
	    return dict_data
2.6 创建带证书接口请求函数
  1. 先安装requests_pkcs12,用于发送带证书接口请求
  2. 微信申请证书,参照微信证书申请文档
  3. 代码如下:
	@staticmethod
    def send_post_cert(url, jsonData):
        try:
            from requests_pkcs12 import post
            # 注意:用res.content,不用res.text,否则会有中文乱码
            res = post(url=url, data=jsonData.encode('utf-8'), headers=headers,
                       pkcs12_filename=WxPay.__cert_name, pkcs12_password=WxPay.__cert_pwd)
            print(res.content.decode("utf-8"))
            return res.content.decode("utf-8")
        except Exception as e:
            logging.error('[send_get]Failed to json.load, {0}'.format(e))
            return ''

说明:

  • pkcs12_filename:对应的是证书名称
  • pkcs12_password:对应证书密码,密码是商户号
  • 证书格式:.p12格式证书
2.7 普通商户添加分账接收方
	@staticmethod
    def profit_add_receiver(type: str, account: str, relation_type: str):  # 普通商户添加分账接收方
        # https://pay.weixin.qq.com/wiki/doc/api/allocation.php?chapter=27_1&index=1
        nonce_str = WxPay.get_nonce_str()
        argc_dict = {'appid': WxPay.__appid, 'mch_id': WxPay.__mch_id,
                     'receiver': json.dumps({'account': account, 'relation_type': relation_type, 'type': type},
                                            separators=(',', ':'), ensure_ascii=False),
                     'nonce_str': nonce_str, 'sign_type': 'HMAC-SHA256'}
        sign_str = WxPay.get_sign_strc_hmac_sha256(argc_dict)
        argc_dict['sign'] = sign_str

        url = 'https://api.mch.weixin.qq.com/pay/profitsharingaddreceiver'
        data = WxPay.get_xml_str(argc_dict)

        return WxPay.send_post(url, data)
2.8 普通商户删除分账接收方
	@staticmethod
    def profit_del_receiver(type: str, account: str):  # 普通商户删除分账接收方
        # https://pay.weixin.qq.com/wiki/doc/api/allocation.php?chapter=27_1&index=1
        nonce_str = WxPay.get_nonce_str()
        argc_dict = {'appid': WxPay.__appid, 'mch_id': WxPay.__mch_id,
                     'receiver': json.dumps({'account': account, 'type': type},
                                            separators=(',', ':'), ensure_ascii=False),
                     'nonce_str': nonce_str, 'sign_type': 'HMAC-SHA256'}
        sign_str = WxPay.get_sign_strc_hmac_sha256(argc_dict)
        argc_dict['sign'] = sign_str

        url = 'https://api.mch.weixin.qq.com/pay/profitsharingremovereceiver'
        data = WxPay.get_xml_str(argc_dict)

        return WxPay.send_post(url, data)
2.9 普通商户单次分账请求
	@staticmethod
    def create_profit_sharing(transaction_id: str, out_order_no: str, type: str, account: str, amount: int,
                              description: str):  # 普通商户单次分账请求
        # https://pay.weixin.qq.com/wiki/doc/api/allocation.php?chapter=27_1&index=1
        nonce_str = WxPay.get_nonce_str()
        argc_dict = {'appid': WxPay.__appid, 'mch_id': WxPay.__mch_id, 'transaction_id': transaction_id,
                     'out_order_no': out_order_no,
                     'receivers': json.dumps({'account': account, 'amount': amount, 'description': description,
                                              'type': type}, separators=(',', ':'), ensure_ascii=False),
                     'nonce_str': nonce_str, 'sign_type': 'HMAC-SHA256'}
        sign_str = WxPay.get_sign_strc_hmac_sha256(argc_dict)
        argc_dict['sign'] = sign_str

        url = 'https://api.mch.weixin.qq.com/secapi/pay/profitsharing'
        data = WxPay.get_xml_str(argc_dict)

        return WxPay.send_post_cert(url, data)
2.10 普通商户查询分账请求
	@staticmethod
    def get_profit_sharing(transaction_id: str, out_order_no: str):  # 普通商户查询分账请求
        # https://pay.weixin.qq.com/wiki/doc/api/allocation.php?chapter=27_1&index=1
        nonce_str = WxPay.get_nonce_str()
        argc_dict = {'mch_id': WxPay.__mch_id, 'transaction_id': transaction_id,
                     'out_order_no': out_order_no, 'nonce_str': nonce_str, 'sign_type': 'HMAC-SHA256'}
        sign_str = WxPay.get_sign_strc_hmac_sha256(argc_dict)
        argc_dict['sign'] = sign_str

        url = 'https://api.mch.weixin.qq.com/pay/profitsharingquery'
        data = WxPay.get_xml_str(argc_dict)

        return WxPay.send_post(url, data)
2.11 普通商户完结分账
	@staticmethod
    def finish_profit_sharing(transaction_id: str, out_order_no: str, description: str):  # 普通商户完结分账
        # https://pay.weixin.qq.com/wiki/doc/api/allocation.php?chapter=27_1&index=1
        nonce_str = WxPay.get_nonce_str()
        argc_dict = {'appid': WxPay.__appid, 'mch_id': WxPay.__mch_id, 'transaction_id': transaction_id,
                     'out_order_no': out_order_no, 'description': description,
                     'nonce_str': nonce_str, 'sign_type': 'HMAC-SHA256'}
        sign_str = WxPay.get_sign_strc_hmac_sha256(argc_dict)
        argc_dict['sign'] = sign_str

        url = 'https://api.mch.weixin.qq.com/secapi/pay/profitsharingfinish'
        data = WxPay.get_xml_str(argc_dict)

        return WxPay.send_post_cert(url, data)

3 完整代码

完整代码和接口调用例子

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

丁爸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值