微信支付-企业付款到零钱问题集锦

前言

做拉新活动的奖金分发,商品售卖的分销体系、给与用户奖金

1. 需要证书

<xml>
<return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[证书出错,请登录微信支付商户平台下载证书]]></return_msg>
<mch_appid><![CDATA[wx9d6ec35cfc350cf1]]></mch_appid>
<mchid><![CDATA[1504059301]]></mchid>
<result_code><![CDATA[FAIL]]></result_code>
<err_code><![CDATA[CA_ERROR]]></err_code>
<err_code_des><![CDATA[证书出错,请登录微信支付商户平台下载证书]]></err_code_des>
</xml>

这个没得说,用户支付是不需要证书的,但是企业支付到用户需要,商户平台下载就好,不行就再配置一个

2. 使用微信官方提供的SDK报错

WXPay.requestWithCert 调用报错:

java.io.IOException: Short read of DER length

贴一下SDK源码

    /**
     * 请求,只请求一次,不做重试
     * @param domain
     * @param urlSuffix
     * @param uuid
     * @param data
     * @param connectTimeoutMs
     * @param readTimeoutMs
     * @param useCert 是否使用证书,针对退款、撤销等操作
     * @return
     * @throws Exception
     */
    private String requestOnce(final String domain, String urlSuffix, String uuid, String data, int connectTimeoutMs, int readTimeoutMs, boolean useCert) throws Exception {
        BasicHttpClientConnectionManager connManager;
        if (useCert) {
            // 证书
            char[] password = config.getMchID().toCharArray();
            InputStream certStream = config.getCertStream();

            KeyStore ks = KeyStore.getInstance("PKCS12");
            ks.load(certStream, password);

            // 实例化密钥库 & 初始化密钥工厂
            KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            kmf.init(ks, password);

            // 创建 SSLContext
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(kmf.getKeyManagers(), null, new SecureRandom());

            SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
                    sslContext,
                    new String[]{"TLSv1"},
                    null,
                    new DefaultHostnameVerifier());

            connManager = new BasicHttpClientConnectionManager(
                    RegistryBuilder.<ConnectionSocketFactory>create()
                            .register("http", PlainConnectionSocketFactory.getSocketFactory())
                            .register("https", sslConnectionSocketFactory)
                            .build(),
                    null,
                    null,
                    null
            );
        }
        else {
            connManager = new BasicHttpClientConnectionManager(
                    RegistryBuilder.<ConnectionSocketFactory>create()
                            .register("http", PlainConnectionSocketFactory.getSocketFactory())
                            .register("https", SSLConnectionSocketFactory.getSocketFactory())
                            .build(),
                    null,
                    null,
                    null
            );
        }

        HttpClient httpClient = HttpClientBuilder.create()
                .setConnectionManager(connManager)
                .build();

        String url = "https://" + domain + urlSuffix;
        HttpPost httpPost = new HttpPost(url);

        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(readTimeoutMs).setConnectTimeout(connectTimeoutMs).build();
        httpPost.setConfig(requestConfig);

        StringEntity postEntity = new StringEntity(data, "UTF-8");
        httpPost.addHeader("Content-Type", "text/xml");
        httpPost.addHeader("User-Agent", USER_AGENT + " " + config.getMchID());
        httpPost.setEntity(postEntity);

        HttpResponse httpResponse = httpClient.execute(httpPost);
        HttpEntity httpEntity = httpResponse.getEntity();
        return EntityUtils.toString(httpEntity, "UTF-8");

    }

出错的原因是 InputStream 不能被反复读取
InputStream certStream = config.getCertStream();
所以我把SDK改了改(有更好的解决方案欢迎留言指教)

InputStream certStream = config.getCertStream();
// 把上面这句改成下面这个,简单来说就是不存 InputStream,改成存储 ByteArray,这个可以被反复读取
byte[] certBytes = config.getCertBytes();
InputStream certStream = new ByteArrayInputStream(certBytes);

3.支付金额问题

09:43:22.705 [http-nio-19999-exec-1] INFO  wxpay java sdk - [<init>,136] - report worker num: 6
09:43:22.710 [http-nio-19999-exec-1] INFO  wxpay java sdk - [report,201] - report v1,WXPaySDK/3.0.9,kCkGa9ENnHJNfzHtal4QyXAAFv9bzkYe,1646790202,6051,api.mch.weixin.qq.com,true,5000,5000,0,0,0,6B8775B5537711CEA8D098A3A2288C9D06E2CA8CEDC26454059B46D3817DFF35
<xml>
<return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[支付失败]]></return_msg>
<mch_appid><![CDATA[wx9d6ec35cfc350cf1]]></mch_appid>
<mchid><![CDATA[1504059301]]></mchid>
<result_code><![CDATA[FAIL]]></result_code>
<err_code><![CDATA[AMOUNT_LIMIT]]></err_code>
<err_code_des><![CDATA[付款金额超出限制。低于最小金额1.00元或累计超过200.00元。]]></err_code_des>
</xml>
09:43:22.755 [pool-11-thread-1] INFO  wxpay java sdk - [run,145] - get first report msg: v1,WXPaySDK/3.0.9,kCkGa9ENnHJNfzHtal4QyXAAFv9bzkYe,1646790202,6051,api.mch.weixin.qq.com,true,5000,5000,0,0,0,6B8775B5537711CEA8D098A3A2288C9D06E2CA8CEDC26454059B46D3817DFF35
09:43:22.756 [pool-11-thread-1] INFO  wxpay java sdk - [run,150] - try get remain report msg

这个没什么好说的,自己看着办

4. 商户配置问题

<xml>
<return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[支付失败]]></return_msg>
<mch_appid><![CDATA[wx9d6ec35cfc350cf1]]></mch_appid>
<mchid><![CDATA[1504059301]]></mchid>
<result_code><![CDATA[FAIL]]></result_code>
<err_code><![CDATA[PAY_CHANNEL_NOT_ALLOWED]]></err_code>
<err_code_des><![CDATA[本商户号未配置API发起,请查看产品中心企业付款配置]]></err_code_des>
</xml>

我们从 产品中心 - 企业付款到零钱,进入产品页面,点击产品设置
在这里插入图片描述
这里默认是关闭状态
在这里插入图片描述
授权、添加IP
在这里插入图片描述
在这里插入图片描述
我这里给了开发、测试、生产,3个IP地址授权
在这里插入图片描述

The End 测试

还是贴一下测试代码吧,作为参考
这里的 WXPayUtil、wxpay,都是微信官方的SDK里的,自己去下载就好

    public void companyPayTest() throws Exception{
        // 1、拼凑企业支付需要的参数
        // 微信公众号的appid
        String appid = myConfig.getAppID();
        // 商户号 - 同时也是证书的支付密码
        String mch_id = myConfig.getMchID();
        // 生成随机数
        String nonce_str = WXPayUtil.generateNonceStr();;
        // 生成商户订单号
        String partner_trade_no =  WXPayUtil.generateOutTradeNo(18L);
        // 支付给用户openid
        String openid = "oFd-P5VFL6KYQMVD6YGMT8wSHAlY";
        // 是否验证真实姓名呢
        String check_name = "NO_CHECK";
        // 收款用户姓名
        String re_user_name = "魏衡";
        // 企业付款金额,单位为分
        String amount = "100";
        // 企业付款操作说明信息。必填。
        String desc = "测试开发,稍后会还给公司的";
        String spbill_create_ip = "192.168.2.50";

        // 生成map集合
        SortedMap<String, String> packageParams = new TreeMap();
        // 微信公众号的appid
        packageParams.put("mch_appid", appid);
        // 商户号
        packageParams.put("mchid", mch_id);
        packageParams.put("nonce_str",nonce_str);
        packageParams.put("partner_trade_no",partner_trade_no);
        packageParams.put("openid",openid);
        packageParams.put("check_name",check_name);
        packageParams.put("re_user_name",re_user_name);
        packageParams.put("amount",amount);
        packageParams.put("desc",desc);
        //调用接口的机器Ip地址
        packageParams.put("spbill_create_ip",spbill_create_ip);

        // 生成自己的签名
        String sign  = WXPayUtil.generateSignature(packageParams, myConfig.getKey());
        packageParams.put("sign", sign);

        // 微信 企业支付到零钱的url地址
//        String wxUrl = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers"; //获取退款的api接口

        System.out.println("==========reuqestXml:" + reuqestXml);
        String result = wxpay.requestWithCert(WXPayConstants.COMPANY_PAY, packageParams, myConfig.getHttpConnectTimeoutMs(), myConfig.getHttpReadTimeoutMs());
        System.out.println(result);
    }

好吧,支付成功
在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值