参考文章:https://www.cnblogs.com/lurenjia1994/p/9670695.html
开发文档:https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon_sl.php?chapter=13_4&index=3
由于公司运营需求,需要从微信支付服务商调用子商户发送现金红包,于是先看开发文档,再参考前辈的文章,经过复制粘贴,修修补补,经过数次踩坑填坑,终于把红包发了出去,话不多说,以下代码只删除了敏感数据,按注释填入即可。
运行脚本:
# -*- coding: utf-8 -*-
from datetime import datetime
import requests
time = datetime.now().strftime('%Y%m%d%H%M%S') #获取当前时间
# 构造发送红包所需数据
#注意:Key不进行上传,sign不进行签名。
dict_k = {
'act_name': '邀请好友有奖', # 活动名称
'client_ip': '127.0.0.1', # 调用接口的IP地址,我用的是本机地址
'mch_billno': '1450' + str(time) + billno_get(), # 用时间和随机数拼接商户订单号,
'mch_id': mch_id, # 商户号
'msgappid': appid, # 发放公众账号ID,授理模式必填
'nonce_str': sign_1.getrangestr(32), # 随机码
're_openid': openid, # 用户openid
'remark': '成功邀请好友红包', # 备注信息
'send_name': '易成车车帮', # 商户名称
'sub_mch_id': sub_mch_id, # 调用子商户发放红包
'total_amount': '100', # 付款金额,单位分
'total_num': '1', # 红包发放总人数
'wishing': '成功邀请好友注册会员并加油奖励红包', # 红包祝福语
'wxappid': wxappid # 公众账号appid
}
dict_k['sign'] = sign_1.signfun(dict_k) # 签名
# data = sign_1.json_xml(dict_k)
data = sign_1.dict_to_xml_str('xml', dict_k).encode('utf8') # 生成微信支付所需的XML文本
# print('上传文档:%s' % data) #打印上传的文档,调试用
# 引入服务商的API证书和接口
cert1 = 'apiclient_cert.pem'
cert2 = 'apiclient_key.pem'
url = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack'
# 以POST方式提交文档发送红包
res = requests.post(url, data=data, cert=(cert1, cert2))
# 在控制台打印发送结果
print(res.text)
调用的函数脚本:
import hashlib
import json
from random import choice
import OpenSSL
import xmltodict
#生成随机数,拼接商户单号用
def billno_get():
result = ''
chars = '0123456789'
for i in range(4):
result += choice(chars)
return result
# 生成随机数,签名用
#由于商户单号我们的要求是纯数字,所以增加一个随机数函数
#商户单号拼接和nonce_str可以根据需求共同调用一个函数,以简化代码行数
def gtrangestr(len):
result = ''
chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'
for i in range(len):
result += choice(chars)
return result
# 签名步骤1:合成字符串
def sign_fun(props):
tempStr = ''
key = 'key' #服务商的KEY
props = sorted(props.items())
for prop in props:
tempStr += '%s=%s&' % (prop[0], prop[1])
# tempStr = tempStr
print('%skey=%s' % (tempStr, key))
return md('%skey=%s' % (tempStr, key)).upper()
# 签名步骤2:MD5将步骤1的字符串加密并转为全部大写,获得签名
def md(instr):
return hashlib.md5(instr.encode('utf8')).hexdigest()
# json转xml
def json_xml(jsonstr):
if 'xml' not in jsonstr:
jsonstr = {'xml': jsonstr}
jsonstr = json.dumps(jsonstr)
jsonstr = json.loads(jsonstr)
return xmltodict.unparse(jsonstr)
踩过的坑:
1、API证书,调用证书需要用绝对路径或把证书放在和脚本同目录中。
2、返回数据提示签名错误,首先要严格按照开发文档上传参数,一定要对照清楚不能多也不能漏;要发送的数据 集拼接成URL键值对格式时的参数名要按照ASCII码从小到大排,不能乱。注意了,key不上传但参与签名,所以key在后面拼接。sign值需要上传但是不参与签名,所以不能放在集合字典内,在生成上传的数据文档前要把sign值放进字典。sign值全部大写。
3、签名可以使用官方的签名校验工具进行调试。