微信开发之普通直连分账(境内普通商户)

简介: 单次分账请求按照传入的分账接收方账号和资金进行分账,同时会将订单剩余的待分账金额解冻给本商户。故操作成功后,订单不能再进行分账,也不能进行分账完结。

1、应用场景

直连商户分账主要用于商户将交易成功的资金,按照一定的周期,分账给其他方,可以是合作伙伴、员工、用户或者其他分润方。

单次分账请求按照传入的分账接收方账号和资金进行分账,同时会将订单剩余的待分账金额解冻给本商户。故操作成功后,订单不能再进行分账,也不能进行分账完结。

2、接口说明

image.png

微信开发文档地址:

https://pay.weixin.qq.com/wiki/doc/api/allocation.php?chapter=27_1&index=1

3、实现代码

PayCommonUtil

public class PayCommonUtil {

private static Logger log = LoggerFactory.getLogger(PayCommonUtil.class);

public static String hashHmac(SortedMap<Object,Object> parameters,String apiKey){
    StringBuffer sb = new StringBuffer();
    Set es = parameters.entrySet();
    Iterator it = es.iterator();
    while(it.hasNext()) {
      Map.Entry entry = (Map.Entry)it.next();
      String k = (String)entry.getKey();
      Object v = entry.getValue();
      if(null != v && !"".equals(v)
          && !"sign".equals(k) && !"key".equals(k)) {
        sb.append(k + "=" + v + "&");
      }
    }
    sb.append("key=" + apiKey);
    String sign = sha256_HMAC(sb.toString(),apiKey).toUpperCase();
    log.info("createSign方法sign签名=====:"+sign);
    return sign;
  }
  
  /**
     * sha256_HMAC加密
     * @param message 消息
     * @param secret  秘钥
     * @return 加密后字符串
     */
    public static String sha256_HMAC(String message, String secret) {
        String hash = "";
        try {
            Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
            SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
            sha256_HMAC.init(secret_key);
            byte[] bytes = sha256_HMAC.doFinal(message.getBytes());
            hash = byteArrayToHexString(bytes);
        } catch (Exception e) {
            System.out.println("Error HmacSHA256 ===========" + e.getMessage());
        }
        return hash;
    }
    
   /**
   * 
   * @Title: getRequestXml
   * @Description:将请求参数转换为xml格式的string
   * @param parameters 请求参数
   * @return String 返回类型
   * @throws
   */
  public static String getRequestXml(SortedMap<Object,Object> parameters){
    StringBuffer sb = new StringBuffer();
    sb.append("<xml>");
    Set es = parameters.entrySet();
    Iterator it = es.iterator();
    while(it.hasNext()) {
      Map.Entry entry = (Map.Entry)it.next();
      String k = (String)entry.getKey();
      String v = (String)entry.getValue();
      if ("attach".equalsIgnoreCase(k)||"body".equalsIgnoreCase(k)||"sign".equalsIgnoreCase(k)) {
        sb.append("<"+k+">"+"<![CDATA["+v+"]]></"+k+">");
      }else {
        sb.append("<"+k+">"+v+"</"+k+">");
      }
    }
    sb.append("</xml>");
    return sb.toString();
  }
}

SubAccount

public static Logger logger = LoggerFactory.getLogger(SubAccount.class);
/**
     * 请求单次分账
     * https://pay.weixin.qq.com/wiki/doc/api/allocation.php?chapter=27_1&index=1
     * @return
     */
    public static SortedMap<Object, Object> profitSharing() throws Exception {
        SortedMap<Object, Object> params = new TreeMap<>();
        //微信支付分配的商户号
        String mchId = "商户号";
        try {
            // 我们发送给微信服务器的参数是xml格式的string,微信返回来的信息也是xml格式的string
            // 获取package包
            SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
            //微信分配的公众账号ID
            parameters.put("appid", "appid");
            //微信支付分配的商户号
            parameters.put("mch_id", "商户号");
            //随机字符串,不长于32位
            parameters.put("nonce_str", "随机字符串");
            //微信支付订单号
            parameters.put("transaction_id", "4200000418201910287201948196");//     4200000418201910296095353357
            //商户系统内部的分账单号,在商户系统内部唯一(单次分账、多次分账、完结分账应使用不同的商户分账单号),同一分账单号多次请求等同一次。只能是数字、大小写字母_-|*@ 
            parameters.put("out_order_no", System.currentTimeMillis() + "");
            //分账接收方列表,不超过50个json对象,不能设置分账方作为分账接受方
            List<Map<String, Object>> receivers = new ArrayList<>();
            
            Map<String, Object> receiver1 = new HashMap<>();
            //MERCHANT_ID:商户ID,PERSONAL_WECHATID:个人微信,号PERSONAL_OPENID:个人openid
            receiver1.put("type", "MERCHANT_ID");
            //类型是MERCHANT_ID时,是商户ID,类型是PERSONAL_WECHATID时,是个人微信号,类型是PERSONAL_OPENID时,是个人openid
            receiver1.put("account", "商户号");
            //分账金额,单位为分,只能为整数,不能超过原订单支付金额及最大分账比例金额
            receiver1.put("amount", 10);
            //分账的原因描述,分账账单中需要体现
            receiver1.put("description", "分账给商户");
            receivers.add(receiver1);
            
            Map<String, Object> receiver2 = new HashMap<>();
            receiver2.put("type", "PERSONAL_WECHATID");
            receiver2.put("account", "微信号");
            receiver2.put("amount", 10);
            receiver2.put("description", "分账给个人");
            receivers.add(receiver2);

            Map<String, Object> receiver3 = new HashMap<>();
            receiver3.put("type", "PERSONAL_WECHATID");
            receiver3.put("account", "微信号");
            receiver3.put("amount", 1);
            receiver3.put("description", "分账给个人");
            receivers.add(receiver3);

            String receiversJson = JSONObject.toJSONString(receivers);

            parameters.put("receivers", receiversJson);
            System.out.println(receiversJson);
            parameters.put("sign_type", "HMAC-SHA256");
            String sign = PayCommonUtil.hashHmac(parameters, "支付签名密钥(api_key)");// 进行签名
            parameters.put("sign", sign);
            // 将请求的参数转为字符串
            String requestXML = PayCommonUtil.getRequestXml(parameters);
            logger.info("post请求微信支付参数============:" + requestXML);

            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            //安全证书P12文件目录
            FileInputStream instream = new FileInputStream(new File("/Users/mac/Desktop/mchid.p12"));
            try {
                keyStore.load(instream, mchId.toCharArray());
            } finally {
                instream.close();
            }
            SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mchId.toCharArray()).build();
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
            CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
            try {
                // 设置响应头信息
                HttpPost httpost = new HttpPost(WxUrl.SHARING);
                httpost.addHeader("Connection", "keep-alive");
                httpost.addHeader("Accept", "*/*");
                httpost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
                httpost.addHeader("Host", "api.mch.weixin.qq.com");
                httpost.addHeader("X-Requested-With", "XMLHttpRequest");
                httpost.addHeader("Cache-Control", "max-age=0");
                httpost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
                httpost.setEntity(new StringEntity(requestXML, "UTF-8"));
                CloseableHttpResponse response = httpclient.execute(httpost);
                try {
                    HttpEntity entity = response.getEntity();
                    String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
                    EntityUtils.consume(entity);
                    Map<String, String> result = XMLUtil.doXMLParse(jsonStr);
                    net.sf.json.JSONObject jsonObject = net.sf.json.JSONObject.fromObject(result);
                    logger.info("请求单次分账返回结果==={}", jsonObject);
                } finally {
                    response.close();
                }
            } finally {
                httpclient.close();
            }
            return params;
        } catch (JDOMException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //============结束==================
        return params;
    }
}

山水有相逢,来日皆可期,谢谢阅读,我们再会

我手中的金箍棒,上能通天,下能探海

上一篇:微信公众号关注或取关后再处理我们自己的业务逻辑

相关文章
支付宝境外(海外)问题方案集锦
说明:   境外和境内接口不同签约等不同,如果要接入境外请按照境外方式接入 。   境外接口官网:[url]https://global.alipay.com[/url] 声明:  业务和技术方案可能会有变动最终以境外业务和技术支持回复为准,下面问题仅供参考。
4491 0
该商户的支付宝账号暂不支持收款,请联系商户核实信息(ALIN42276)自查方案
错误原因 这个报错原因一般是在接口中传入了seller_id参数,但是这个seller_id和调用接口的appid对应的支付宝账户的pid不一致导致  解决方案 不传入seller_id参数或是把seller_id修改为和appid对应的支付宝账户的pid来测试
1973 0
|
1月前
|
JSON API 数据安全/隐私保护
1688阿里巴巴中国站获得商品快递费用 API接口
阿里巴巴1688中国站提供了丰富的API接口供开发者使用,以获取商品信息、订单详情、物流费用等。然而,关于获取商品快递费用的具体API接口,可能会因阿里巴巴平台的更新而有所变化。
|
4月前
支付设计白皮书:详解!《境外信用卡支付》收单完整过程
支付设计白皮书:详解!《境外信用卡支付》收单完整过程
65 0
|
10月前
|
API 数据处理 数据安全/隐私保护
作为一个客户经理你一个如何给客户介绍API接口
随着科技的发展,API(Application Programming Interface,应用程序接口)的应用已经逐渐普及,而API接口作为现代企业实现智能化运营和管理的重要工具之一,也备受关注。作为一名客户经理,向客户介绍API接口,需要做好充分的准备工作和沟通,下面是一些我在实践中总结的建议: 确定客户需求:在与客户进行沟通之前,我们必须先了解他们实际的业务需求,只有这样才能更好地为他们服务,为他们提供有用的API接口。同时,也可以针对客户需求来确定API接口的适用性和优势。
|
JSON 算法 安全
金润·核验通-运营商在网时长接口文档
运营商在网时长接口介绍:提供用户手机号,核验用户在运营商激活手机号正常使用至今的时长 更新时间:实时 接口类型:API接口 数据优势:直连官方数据,合法合规、权威、精确 数据安全:仅提供用户在网时长,保护个人信息安全 计费方式:核验计费,详情请咨询
金润·核验通-运营商在网时长接口文档
|
JSON 算法 安全
金润·核验通-运营商在网状态接口文档
运营商在网状态接口介绍:提供用户手机号,核验用户手机在网状态正常、停机、销号、在网但不可用等状态 更新时间:实时 接口类型:API接口 数据优势:直连官方数据,合法合规、权威、精确 数据安全:仅确认在网状态,保护个人信息安全 计费方式:核验计费,详情请咨询
金润·核验通-运营商在网状态接口文档
|
JSON API 数据格式
电商收付通系列②,获取微信支付平台证书
微信支付平台证书是指由微信支付负责申请的,包含微信支付平台标识、公钥信息的证书。商户可以使用平台证书中的公钥进行验签。注意,这里的证书区别于商户API证书,商户API证书是直接从商户后台下载查看的,而微信支付平台证书是通过电商收付通的证书接口获取的。
686 0
电商收付通系列②,获取微信支付平台证书
|
安全 API 数据安全/隐私保护
电商收付通系列⑤,商户进件之二级商户进件申请
用户提交商家进件资料后,电商平台可使用该接口,帮助其二级商户进件成为微信支付商户。
474 0
电商收付通系列⑤,商户进件之二级商户进件申请
电商收付通系列⑨,分账之添加分账接收方和请求分账
电商平台可通过此接口添加分账接收方,建立分账接收方列表。后续通过发起分账请求,将电商平台下的二级商户结算后的资金,分给分账接收方列表中具体的分账接收方。
230 0
电商收付通系列⑨,分账之添加分账接收方和请求分账