业务实践系列(6):对账-微信交易账单数据解析

支付系统就一定需要对账,需要下载支付平台侧的账单与自己业务系统的交易数据时行对账。

微信账单:商户(支付通道)通过下载历史交易清单。比如掉单、系统错误等导致商户侧和微信侧数据不一致,通过对账单核对后可校正支付状态。

交易账单

  1. 微信侧未成功下单的交易不会出现在对账单中。支付成功后撤销的交易会出现在对账单中,跟原支付单订单号一致;
  2. 微信在次日9点启动生成前一天的对账单,建议商户10点后再获取;
  3. 对账单中涉及金额的字段单位为
  4. 对账单接口只能下载三个月以内的账单;
  5. 对账单是以商户号纬度来生成的,如一个商户号与多个appid有绑定关系,则使用其中任何一个appid都可以请求下载对账单。对账单中的appid取自交易时候提交的appid,与请求下载对账单时使用的appid无关。
  6. 自2018年起入驻的商户默认是开通免充值券后的结算对账单。

账单数据

账单数据格式请查阅微信支付官方说明:下载交易账单。原始的账单的文本数据包含了 \r\n 换行符。

  1. 获取微信账单数据,成功时,数据以文本表格的方式返回,第一行为表头,后面各行为对应的字段内容,字段内容跟查询订单或退款结果一致,具体字段说明可查阅相应接口。
  2. 从第二行起,为数据记录,各参数以逗号分隔,参数前增加`符号,为标准键盘1左边键的字符,字段顺序与表头一致。
  3. 倒数第二行为订单统计标题,最后一行为统计数据。

示例数据如下:

备注:原始数据的第一行表头首字母有个特殊的符号,返回到 Postman 时显示乱码,在 IDEA 断点查看响应内容又看不到这个特殊符号,粘贴到这里又有显示。

1
2
3
4
5
6
7
交易时间,公众账号ID,商户号,特约商户号,设备号,微信订单号,商户订单号,用户标识,交易类型,交易状态,付款银行,货币种类,应结订单金额,代金券金额,微信退款单号,商户退款单号,退款金额,充值券退款金额,退款类型,退款状态,商品名称,商户数据包,手续费,费率,订单金额,申请退款金额,费率备注
`2020-07-22 09:35:43,`wx9c63650xxxxxxxx,`14988xxxxx,`14876xxxxx,`,`4200000xxxxxxx479,`1200131xxxxx24,`ogdwzxxxxxxxRFSRy4,`NATIVE,`SUCCESS,`OTHERS,`CNY,`0.01,`0.00,`0,`0,`0.00,`0.00,`,`,`挂号费测试,`,`0.00000,`1.00%,`0.01,`0.00,`
`2020-07-22 09:48:22,`wx9c63650xxxxxxxx,`14988xxxxx,`14876xxxxx,`,`4200000xxxxxxx479,`1200131xxxxx24,`ogdwzxxxxxxxRFSRy4,`NATIVE,`REFUND,`OTHERS,`CNY,`0.00,`0.00,`50300704872020072201640769932,`12001318629846188408832,`0.01,`0.00,`ORIGINAL,`SUCCESS,`挂号费测试,`,`0.00000,`1.00%,`0.00,`0.01,`
`2020-07-22 10:05:37,`wx9c63650xxxxxxxx,`14988xxxxx,`14876xxxxx,`,`4200000xxxxxxx708,`1200131xxxxx48,`ogdwzxxxxxxxRFSRy4,`NATIVE,`REFUND,`OTHERS,`CNY,`0.00,`0.00,`50300405062020072201639753977,`12001318634185946677248,`0.01,`0.00,`ORIGINAL,`SUCCESS,`挂号费测试,`,`0.00000,`1.00%,`0.00,`0.01,`
`2020-07-22 10:02:20,`wx9c63650xxxxxxxx,`14988xxxxx,`14876xxxxx,`,`4200000xxxxxxx708,`1200131xxxxx48,`ogdwzxxxxxxxRFSRy4,`NATIVE,`SUCCESS,`OTHERS,`CNY,`0.01,`0.00,`0,`0,`0.00,`0.00,`,`,`挂号费测试,`,`0.00000,`1.00%,`0.01,`0.00,`
总交易单数,应结订单总金额,退款总金额,充值券退款总金额,手续费总金额,订单总金额,申请退款总金额
`4,`0.02,`0.02,`0.00,`0.00000,`0.02,`0.02

账单解析

实体类

账单明细

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/**
* @desc: 微信账单明细
*/
@Data
@SuperBuilder
@Accessors(chain = true)
public class WxPayBillDetail implements Serializable {

private static final long serialVersionUID = 8406089574169555667L;

/**
* 交易时间
*/
private String tradeTime;
/**
* 公众号账号ID
*/
private String publicId;
/**
* 商户号
*/
private String mchId;
/**
* 特约商户号(子商户号)
*/
private String subMchId;
/**
* 设备号
*/
private String deviceNo;
/**
* 微信支付单号
*/
private String wxTransactionId;
/**
* 商户订单号(payId)
*/
private String outTradeNo;
/**
* 用户标识
*/
private String userTag;
/**
* 交易类型
*/
private String tradeType;
/**
* 交易状态
*/
private String tradeStatus;
/**
* 付款银行
* 银行类型,采用字符串类型的银行标识,银行类型见银行列表
* 例如:ICBC_DEBIT 表示 工商银行(借记卡)
*/
private String bankType;
/**
* 货币种类
*/
private String currencyType;
/**
* 应结订单金额
*/
private String settlementTotalFee;
/**
* 代金券金额
*/
private String couponFee;
/**
* 微信退款单号
*/
private String wxRefundId;
/**
* 商户退款单号
*/
private String outRefundNo;
/**
* 退款金额(结算)
*/
private String settlementRefundFee;
/**
* 充值券退款金额
*/
private String couponRefundFee;
/**
* 退款类型
*/
private String refundType;
/**
* 退款状态
*/
private String refundStatus;
/**
* 商品名称
*/
private String goodsName;
/**
* 商品数据包
*/
private String goodsData;
/**
* 手续费
*/
private String serviceFee;
/**
* 费率
*/
private String serviceRate;
/**
* 订单金额
*/
private String payOrderTotalFee;
/**
* 申请退款金额
*/
private String refundFee;
/**
* 费率备注
*/
private String serviceRateRemark;
}

数据解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
/**
* @desc: 下载微信账单业务
*/
@Service
public class WxPayBillServiceImpl implements WxPayBillService {
private static final Logger logger = LogManager.getLogger(WxPayBillServiceImpl.class);

private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

//----------省略获取支付账号,发送下载交易账单请求逻辑............

/**
* 解析微信账单数据
*
* @param billData 文本表格数据
*/
private List<WxPayBillDetail> parseBillData(String billData) {

// 拆分行
String[] lineArray = billData.split("\r\n");
logger.info("微信账单明细表头:{}", lineArray[0]);
logger.info("微信账单汇总表头:{},汇总数据:{}", lineArray[lineArray.length - 2], lineArray[lineArray.length - 1]);

List<WxPayBillDetail> detailList = new ArrayList<>();
/*第一行是明细表头,最后两行是汇总表头和汇总数据*/
for (int i = 1; i < lineArray.length - 2; i++) {
// 明细数据行
String line = lineArray[i].replace("`", "");
String[] dataArray = line.split(",");
WxPayBillDetail billDetail = WxPayBillDetail.builder()
.tradeTime(dataArray[0])
.publicId(dataArray[1])
.mchId(dataArray[2])
.subMchId(dataArray[3])
.deviceNo(dataArray[4])
.wxTransactionId(dataArray[5])
.outTradeNo(dataArray[6])
.userTag(dataArray[7])
.tradeType(dataArray[8])
.tradeStatus(dataArray[9])
.bankType(dataArray[10])
.currencyType(dataArray[11])
.settlementTotalFee(dataArray[12])
.couponFee(dataArray[13])
.wxRefundId(dataArray[14])
.outRefundNo(dataArray[15])
.settlementRefundFee(dataArray[16])
.couponRefundFee(dataArray[17])
.refundType(dataArray[18])
.refundStatus(dataArray[19])
.goodsName(dataArray[20])
.goodsData(dataArray[21])
.serviceFee(dataArray[22])
.serviceRate(dataArray[23])
.build();
if (dataArray.length == 26) {
billDetail.setPayOrderTotalFee(dataArray[24]).setRefundFee(dataArray[25]);
}
detailList.add(billDetail);
}
return detailList;
}
}

业务实践系列(6):对账-微信交易账单数据解析

http://blog.gxitsky.com/2020/07/24/Business-06-wx-pay-bill/

作者

光星

发布于

2020-07-24

更新于

2023-03-07

许可协议

评论