微信下载对账单

最近接手了一个棘手的工作:微信下载对账单。

刚接手完全懵逼,怎么和微信对接啊。然后就是百度。。

终于找到了组织:

微信支付|开发文档 :点击跳转

 

通过文档我们可以看到,首先是:

1.下载对账单开放接口链接:

https://api.mch.weixin.qq.com/pay/downloadbill

 关于应用场景:

商户可以通过该接口下载历史交易清单。比如掉单、系统错误等导致商户侧和微信侧数据不一致,通过对账单核对后可校正支付状态。
注意:
1、微信侧未成功下单的交易不会出现在对账单中。支付成功后撤销的交易会出现在对账单中,跟原支付单订单号一致;
2、微信在次日9点启动生成前一天的对账单,建议商户10点后再获取;
3、对账单中涉及金额的字段单位为“元”。
4、对账单接口只能下载三个月以内的账单。

2.传入的参数:

接着我们看下传入参数:

其中,微信分配的appId 和 商户号 是自己的。

还有就是需要 去商户平台查自己商户号以及key。这个key主要用在生成签名中。

看一下查詢代码:

        SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
        parameters.put("appid", ConfigUtil.APPID); // APPid
        parameters.put("mch_id", ConfigUtil.MCH_ID); // 商户id
        // parameters.put("device_info", "");//微信支付分配的终端设备号,填写此字段,只下载该设备号 的对账单
        parameters.put("nonce_str", PayCommonUtil.CreateNoncestr());
        // 下载对账单的日期,格式:20140603,当前日期前一天。
        String billDate = DateUtil.date2Str(DateUtil.addDay(new Date(), -1), "yyyyMMdd");
        parameters.put("bill_date", billDate);//
        // bill_type:ALL返回当日所有订单信息,默认值SUCCESS返回当日成功支付的订单。REFUND,返回当日退款订单
        parameters.put("bill_type", "ALL");
        String sign = PayCommonUtil.createSign("utf-8", parameters);
        parameters.put("sign", sign);
        String reuqestXml = PayCommonUtil.getRequestXml(parameters);
        String result = CommonUtil.httpsRequest(ConfigUtil.DOWNLOAD_BILL_URL, "POST", reuqestXml);

configUtil 工具类里面要配置APPID,MCH_ID,已及Key 。(注:所有的工具类我都放文章末尾链接里,自己下载即可。)我们需要在ConfigUtil工具类中配置一下:

     public final static String APPID = "";//服务号的应用号
     public final static String APP_SECRECT = "";//服务号的应用密码
     public final static String TOKEN = "weixinCourse";//服务号的配置token
     public final static String MCH_ID = "";//商户号
     public final static String API_KEY = "";//API密钥
     public final static String SIGN_TYPE = "MD5";//签名加密方式
     public final static String CERT_PATH = "D:/apiclient_cert.p12";//微信支付证书存放路径地址

3.随机数:

我们看一下随机数的生成

public static String CreateNoncestr() {
        String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        String res = "";
        for (int i = 0; i < 16; i++) {
            Random rd = new Random();
            res += chars.charAt(rd.nextInt(chars.length() - 1));
        }
        return res;
    }

4.关于签名:

关于签名,有三点需要注意:

①格式是:utf-8;

②签名类型:MD5以及HMAC-SHA256。默认为MD5,本例也是MD5。

签名的生成:需要前面几个值(APPID等)以及Key

public static String createSign(String characterEncoding,SortedMap<Object,Object> parameters){
        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=" + ConfigUtil.API_KEY);
        String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
        return sign;
    }

例如这样:

<xml>
  <appid>wx2421b1c4370ec43b</appid>
  <bill_date>20141110</bill_date>
  <bill_type>ALL</bill_type>
  <mch_id>10000100</mch_id>
  <nonce_str>21df7dc9cd8616b56919f20d9f679233</nonce_str>
  <sign>332F17B766FC787203EBE9D6E40457A1</sign>
</xml>

代码:

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)) {
            if ("attach".equalsIgnoreCase(k)||"body".equalsIgnoreCase(k)) {
                sb.append("<"+k+">"+"<![CDATA["+v+"]]></"+k+">");
            }else {
                sb.append("<"+k+">"+v+"</"+k+">");
            }
        }
        sb.append("</xml>");
        return sb.toString();
    }

之后把xml传给微信对账单接口而后接口会返回值:

5.返回值解析:

关于返回值,这里我详解下:最重要一点是:成功和失败返回数据流类型不一样:成功返回文本格式,失败返回xml格式数据

①返回失败的情况 :返回xml ,其中无数据也会返回xml 。并且格式是下图。

下面是错误码

②成功:数据以文本方式返回。

拿微信给的成功返回数据举例:

交易时间,公众账号ID,商户号,子商户号,设备号,微信订单号,商户订单号,用户标识,交易类型,交易状态,付款银行,货币种类,总金额,代金券或立减优惠金额,微信退款单号,商户退款单号,退款金额,代金券或立减优惠退款金额,退款类型,退款状态,商品名称,商户数据包,手续费,费率
`2014-11-1016:33:45,`wx2421b1c4370ec43b,`10000100,`0,`1000,`1001690740201411100005734289,`1415640626,`085e9858e3ba5186aafcbaed1,`MICROPAY,`SUCCESS,`CFT,`CNY,`0.01,`0.0,`0,`0,`0,`0,`,`,`被扫支付测试,`订单额外描述,`0,`0.60%
`2014-11-1016:46:14,`wx2421b1c4370ec43b,`10000100,`0,`1000,`1002780740201411100005729794,`1415635270,`085e9858e90ca40c0b5aee463,`MICROPAY,`SUCCESS,`CFT,`CNY,`0.01,`0.0,`0,`0,`0,`0,`,`,`被扫支付测试,`订单额外描述,`0,`0.60%
总交易单数,总交易额,总退款金额,总代金券或立减优惠退款金额,手续费总金额
`2,`0.02,`0.0,`0.0,`0

我们对成功的数据进行处理:

①把第一行表头去掉

代码为:

String tradeMsg = result.substring(result.indexOf("`"));

数据为:

`2014-11-1016:33:45,`wx2421b1c4370ec43b,`10000100,`0,`1000,`1001690740201411100005734289,`1415640626,`085e9858e3ba5186aafcbaed1,`MICROPAY,`SUCCESS,`CFT,`CNY,`0.01,`0.0,`0,`0,`0,`0,`,`,`被扫支付测试,`订单额外描述,`0,`0.60%
`2014-11-1016:46:14,`wx2421b1c4370ec43b,`10000100,`0,`1000,`1002780740201411100005729794,`1415635270,`085e9858e90ca40c0b5aee463,`MICROPAY,`SUCCESS,`CFT,`CNY,`0.01,`0.0,`0,`0,`0,`0,`,`,`被扫支付测试,`订单额外描述,`0,`0.60%
总交易单数,总交易额,总退款金额,总代金券或立减优惠退款金额,手续费总金额
`2,`0.02,`0.0,`0.0,`0

②去掉汇总数据,并且去掉"`"这个符号。

代码为:

String tradeInfo = tradeMsg.substring(0, tradeMsg.indexOf("总")).replace("`", "");// 去掉汇总数据,并且去掉'`'

数据为:

2014-11-1016:33:45,wx2421b1c4370ec43b,10000100,0,1000,1001690740201411100005734289,1415640626,085e9858e3ba5186aafcbaed1,MICROPAY,SUCCESS,CFT,CNY,0.01,0.0,0,0,0,0,,,被扫支付测试,订单额外描述,0,0.60%
2014-11-1016:46:14,wx2421b1c4370ec43b,10000100,0,1000,1002780740201411100005729794,1415635270,085e9858e90ca40c0b5aee463,MICROPAY,SUCCESS,CFT,CNY,0.01,0.0,0,0,0,0,,,被扫支付测试,订单额外描述,0,0.60%

可以看到和我们想要的数据已经大致一样了。

③用spilt方法拿出每一天数据放进数组里。之后再用spilt方法把数据放进二维数组里。

String[] tradeArray = tradeInfo.split("%");  // 根据%来区分
 for (String tradeDetailInfo : tradeArray) {
            String[] tradeDetailArray = tradeDetailInfo.split(",");
 }

④最后保存下来就可以了。


            PtWxTradeDetail entity = null;
            entity = new PtWxTradeDetail();
            entity.setId(null); // 自动生成id
            entity.setTransDate(DateUtil.str2Date(tradeDetailArray[0], format));// 交易时间
            entity.setCommonId(tradeDetailArray[1]);// 公众账号ID
            entity.setBusinessNo(tradeDetailArray[2]);// 商户号
            entity.setChildBusinessNo(tradeDetailArray[3]);// 子商户号
            entity.setEquipmentNo(tradeDetailArray[4]);// 设备号
            entity.setWxOrderNo(tradeDetailArray[5]);// 微信订单号
            entity.setBusinessOrderNo(tradeDetailArray[6]);// 商户订单号
            entity.setUserIdentity(tradeDetailArray[7]);// 用户标识
            entity.setTransType(tradeDetailArray[8]);// 交易类型
            entity.setTransStatus(tradeDetailArray[9]);// 交易状态
            entity.setPaymentBank(tradeDetailArray[10]);// 付款银行
            entity.setCurrency(tradeDetailArray[11]);// 货币种类
            entity.setTotalAmount(tradeDetailArray[12]);// 总金额
            entity.setRedEnvelopesAmount(tradeDetailArray[13]);// 企业红包金额
            entity.setWxRefundNo(tradeDetailArray[14]);// 微信退款单号
            entity.setBusinessRefundNo(tradeDetailArray[15]);// 商户退款单号
            entity.setRefundAmount(tradeDetailArray[16]);// 退款金额
            entity.setRedEnvelopesRefundAmount(tradeDetailArray[17]);// 企业红包退款金额
            entity.setRefundType(tradeDetailArray[18]);// 退款类型
            entity.setRefundStatus(tradeDetailArray[19]);// 退款状态
            entity.setBusinessName(tradeDetailArray[20]);// 商品名称
            entity.setBusinessData(tradeDetailArray[21]);// 商户数据包
            entity.setFee(tradeDetailArray[22]);// 手续费
            entity.setRate(tradeDetailArray[23] + "%");// 费率
            entity.setCreateDate(new Date());
            wxTradeDetailDao.insert(entity);

最后,微信支付工具类下载链接(百度网盘):点击下载

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
微信账单下载和解析入库可以分为两个步骤进行。 1. 下载微信账单 可以使用微信支付的对账单下载接口来下载账单。接口需要提供以下参数: - appid:微信支付分配的公众账号ID; - mch_id:微信支付分配的商户号; - nonce_str:随机字符串,不长于32位; - sign:签名; - bill_date:对账单日期,格式为yyyyMMdd; - bill_type:账单类型,ALL(默认值)、SUCCESS、REFUND、RECHARGE_REFUND。 可以使用 Apache HttpClient 或者 OkHttp 等 HTTP 客户端库来调用接口。示例代码如下: ```java import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.HttpClient; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.EntityUtils; import java.io.FileOutputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; public class WechatBillDownloader { private static final String URL = "https://api.mch.weixin.qq.com/pay/downloadbill"; public static void main(String[] args) throws IOException { // 构建 HTTP 请求 HttpPost post = new HttpPost(URL); List<NameValuePair> params = new ArrayList<>(); params.add(new BasicNameValuePair("appid", "your_appid")); params.add(new BasicNameValuePair("mch_id", "your_mch_id")); params.add(new BasicNameValuePair("nonce_str", "your_nonce_str")); params.add(new BasicNameValuePair("sign", "your_sign")); params.add(new BasicNameValuePair("bill_date", "20220101")); params.add(new BasicNameValuePair("bill_type", "ALL")); post.setEntity(new UrlEncodedFormEntity(params, StandardCharsets.UTF_8)); // 发送 HTTP 请求 HttpClient client = HttpClientBuilder.create().build(); HttpResponse response = client.execute(post); // 解析 HTTP 响应 HttpEntity entity = response.getEntity(); if (entity != null) { // 将响应结果保存到文件中 FileOutputStream output = new FileOutputStream("wechat_bill.csv"); output.write(EntityUtils.toByteArray(entity)); output.close(); } } } ``` 2. 解析微信账单并入库 可以使用 OpenCSV 等 CSV 解析库来解析微信账单,并将解析后的数据插入数据库中。具体的解析和入库逻辑可以参考前面的示例代码。 需要注意的是,微信支付对账单的格式和内容经常会有变化,需要根据实际情况进行适当的调整和修改。此外,对账单中可能会包含敏感的商户交易信息,需要注意数据的保密性和安全性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值