微信开发之普通直连分账(境内普通商户)
  lwWnUiDFsXce 2023年11月02日 47 0

1、应用场景

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

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


2、接口说明

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

微信开发文档地址:

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 class 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;
    }
}
【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
lwWnUiDFsXce