改进下载对账文件的方案
diff --git a/config/application-devel-pg.properties b/config/application-devel-pg.properties
index 52289ce..8e2b45e 100644
--- a/config/application-devel-pg.properties
+++ b/config/application-devel-pg.properties
@@ -10,7 +10,7 @@
spring.datasource.username=payapi
spring.datasource.password=123456
spring.datasource.continue-on-error=true
-#spring.datasource.initialization-mode=always
+spring.datasource.initialization-mode=always
# Redis settings
#spring.redis.host=ykt.supwisdom.com
spring.redis.host=172.28.201.101
diff --git a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/CitizenCardPayProxy.java b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/CitizenCardPayProxy.java
index e2042d9..d68a238 100644
--- a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/CitizenCardPayProxy.java
+++ b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/CitizenCardPayProxy.java
@@ -13,7 +13,6 @@
@FeignClient(value = "citizenCardPay", url = "${payapi.url}")
public interface CitizenCardPayProxy {
@RequestMapping(value = "/api/consume/citizencard/payinit", method = RequestMethod.GET)
- @Valid
CitizenPayResponse citizencardPayinit(@RequestBody CitizenCardPayinitParam param);
@RequestMapping(value = "/api/consume/citizencard/payfinish", method = RequestMethod.GET)
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/system/service/impl/ParamServiceImpl.java b/payapi/src/main/java/com/supwisdom/dlpay/system/service/impl/ParamServiceImpl.java
index 191697e..88e7e1b 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/system/service/impl/ParamServiceImpl.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/system/service/impl/ParamServiceImpl.java
@@ -164,7 +164,7 @@
}
@Override
- @Cacheable(cacheNames = "dictionary_cache", key = "#{@tenantHolder.genKey('sourcetype', #sourceType)}")
+ @Cacheable(cacheNames = "dictionary_cache", key = "@tenantHolder.genKey('sourcetype', #sourceType)")
public TSourceType getSourceType(String sourceType) {
if (!StringUtil.isEmpty(sourceType)) {
return sourceTypeDao.getBySourceType(sourceType.trim());
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/async_tasks.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/async_tasks.kt
index 4139d9e..5b9745a 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/async_tasks.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/async_tasks.kt
@@ -2,7 +2,6 @@
import com.supwisdom.dlpay.agent.AgentCode
import com.supwisdom.dlpay.agent.DtlStatus
-
import com.supwisdom.dlpay.agent.citizencard.YnrccUtil
import com.supwisdom.dlpay.api.domain.TDtlQuery
import com.supwisdom.dlpay.api.domain.TTransactionMain
@@ -129,8 +128,9 @@
}
AgentCode.REFNO_NOT_EXISTS ->
transactionService.fail(transaction.refno, "银行流水不存在") //银行返回流水不存在
- AgentCode.REQUIRE_QUERY ->
+ AgentCode.REQUIRE_QUERY -> {
queryResult(transaction, qcnt + 1) //查询次数加1
+ }
else -> {
//其他明确错误,查询失败
logger.error("查询refno=[${transaction.refno}]流水结果返回失败:code=[${resp.agentCode}],message=[${resp.agentMsg}]")
diff --git a/ynrcc-agent/build.gradle b/ynrcc-agent/build.gradle
index a46f4d7..a00c65d 100644
--- a/ynrcc-agent/build.gradle
+++ b/ynrcc-agent/build.gradle
@@ -49,6 +49,7 @@
implementation group: 'taglibs', name: 'standard', version: '1.1.2'
implementation group: 'commons-codec', name: 'commons-codec', version: '1.6'
implementation 'org.dom4j:dom4j:2.1.1'
+ implementation 'commons-beanutils:commons-beanutils:1.9.3'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'io.rest-assured:rest-assured:3.3.0'
diff --git a/ynrcc-agent/src/main/java/com/supwisdom/agent/api/bean/CheckFileHeader.java b/ynrcc-agent/src/main/java/com/supwisdom/agent/api/bean/CheckFileHeader.java
new file mode 100644
index 0000000..d19df54
--- /dev/null
+++ b/ynrcc-agent/src/main/java/com/supwisdom/agent/api/bean/CheckFileHeader.java
@@ -0,0 +1,76 @@
+package com.supwisdom.agent.api.bean;
+
+/**
+ * 第一行:总笔数|总金额|代扣总笔数|代扣总金额|退款总笔数|退款总金额|
+ */
+public class CheckFileHeader {
+ private int totalCount;
+ private int totalAmount;
+ private int payCount;
+ private int payAmount;
+ private int refundCount;
+ private int refundAmount;
+
+ public int getTotalCount() {
+ return totalCount;
+ }
+
+ public void setTotalCount(int totalCount) {
+ this.totalCount = totalCount;
+ }
+
+ public int getTotalAmount() {
+ return totalAmount;
+ }
+
+ public void setTotalAmount(int totalAmount) {
+ this.totalAmount = totalAmount;
+ }
+
+ public int getPayCount() {
+ return payCount;
+ }
+
+ public void setPayCount(int payCount) {
+ this.payCount = payCount;
+ }
+
+ public int getPayAmount() {
+ return payAmount;
+ }
+
+ public void setPayAmount(int payAmount) {
+ this.payAmount = payAmount;
+ }
+
+ public int getRefundCount() {
+ return refundCount;
+ }
+
+ public void setRefundCount(int refundCount) {
+ this.refundCount = refundCount;
+ }
+
+ public int getRefundAmount() {
+ return refundAmount;
+ }
+
+ public void setRefundAmount(int refundAmount) {
+ this.refundAmount = refundAmount;
+ }
+
+ public boolean isZero() {
+ return (totalAmount == 0 && totalCount == 0
+ && payAmount == 0 && payCount == 0 && refundAmount == 0 && refundCount == 0);
+ }
+
+ @Override
+ public String toString() {
+ return totalCount +
+ ", " + totalAmount +
+ ", " + payCount +
+ ", " + payAmount +
+ ", " + refundCount +
+ ", " + refundAmount;
+ }
+}
diff --git a/ynrcc-agent/src/main/java/com/supwisdom/agent/api/bean/CheckFileLine.java b/ynrcc-agent/src/main/java/com/supwisdom/agent/api/bean/CheckFileLine.java
new file mode 100644
index 0000000..e3d9b69
--- /dev/null
+++ b/ynrcc-agent/src/main/java/com/supwisdom/agent/api/bean/CheckFileLine.java
@@ -0,0 +1,100 @@
+package com.supwisdom.agent.api.bean;
+
+/**
+ * * 第二行及以后:交易日期|交易时间|报文业务类型|业务系统流水号|银行流水号|付款银行卡号|收款商户银行卡号|核心记账日期|交易金额|交易摘要|
+ * <p>
+ * private static final String[]chkFileColumnList=new String[]{"transdate","transtime","flag","refno","agentrefno",
+ * "payerid","payeeid","agentdate","amount","summary"};
+ */
+public class CheckFileLine {
+ private String transdate;
+ private String transtime;
+ private String flag;
+ private String refno;
+ private String agentrefno;
+ private String payerid;
+ private String payeeid;
+ private String agentdate;
+ private Integer amount;
+ private String summary;
+
+ public String getTransdate() {
+ return transdate;
+ }
+
+ public void setTransdate(String transdate) {
+ this.transdate = transdate;
+ }
+
+ public String getTranstime() {
+ return transtime;
+ }
+
+ public void setTranstime(String transtime) {
+ this.transtime = transtime;
+ }
+
+ public String getFlag() {
+ return flag;
+ }
+
+ public void setFlag(String flag) {
+ this.flag = flag;
+ }
+
+ public String getRefno() {
+ return refno;
+ }
+
+ public void setRefno(String refno) {
+ this.refno = refno;
+ }
+
+ public String getAgentrefno() {
+ return agentrefno;
+ }
+
+ public void setAgentrefno(String agentrefno) {
+ this.agentrefno = agentrefno;
+ }
+
+ public String getPayerid() {
+ return payerid;
+ }
+
+ public void setPayerid(String payerid) {
+ this.payerid = payerid;
+ }
+
+ public String getPayeeid() {
+ return payeeid;
+ }
+
+ public void setPayeeid(String payeeid) {
+ this.payeeid = payeeid;
+ }
+
+ public String getAgentdate() {
+ return agentdate;
+ }
+
+ public void setAgentdate(String agentdate) {
+ this.agentdate = agentdate;
+ }
+
+ public Integer getAmount() {
+ return amount;
+ }
+
+ public void setAmount(Integer amount) {
+ this.amount = amount;
+ }
+
+ public String getSummary() {
+ return summary;
+ }
+
+ public void setSummary(String summary) {
+ this.summary = summary;
+ }
+}
diff --git a/ynrcc-agent/src/main/java/com/supwisdom/agent/api/controller/YnrccApiController.java b/ynrcc-agent/src/main/java/com/supwisdom/agent/api/controller/YnrccApiController.java
index 8c229d3..52fa611 100644
--- a/ynrcc-agent/src/main/java/com/supwisdom/agent/api/controller/YnrccApiController.java
+++ b/ynrcc-agent/src/main/java/com/supwisdom/agent/api/controller/YnrccApiController.java
@@ -4,18 +4,24 @@
import com.supwisdom.agent.Util.DlpayUtil;
import com.supwisdom.agent.Util.ErrorCode;
import com.supwisdom.agent.Util.StringUtil;
+import com.supwisdom.agent.api.bean.CheckFileHeader;
+import com.supwisdom.agent.api.bean.CheckFileLine;
import com.supwisdom.agent.api.bean.DlpayReq;
import com.supwisdom.agent.api.bean.DlpayResp;
import com.supwisdom.agent.api.service.YnrccApiService;
import com.supwisdom.agent.api.service.YnrccParamCheckService;
+import org.apache.commons.beanutils.BeanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.*;
+import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.FormParam;
+import java.io.*;
+import java.lang.reflect.InvocationTargetException;
+import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
@@ -28,6 +34,18 @@
@Autowired
private YnrccParamCheckService ynrccParamCheckService;
+ /**
+ * 第一行:总笔数|总金额|代扣总笔数|代扣总金额|退款总笔数|退款总金额|
+ * 第二行及以后:交易日期|交易时间|报文业务类型|业务系统流水号|银行流水号|付款银行卡号|收款商户银行卡号|核心记账日期|交易金额|交易摘要|
+ */
+ private static final String[] chkFileColumnList = new String[]{"transdate", "transtime", "flag", "refno", "agentrefno",
+ "payerid", "payeeid", "agentdate", "amount", "summary"};
+ private static final String[] chkFileHeaderColumnList = new String[]{"totalCount", "totalAmount", "payCount",
+ "payAmount", "refundCount", "refundAmount"};
+ private static final String chkFileDelimiter = "|";
+ private static final String FLAG_WITHHOLD = "BC5512";
+ private static final String FLAG_REFUND = "BC5513";
+
private static final Logger logger = LoggerFactory.getLogger(YnrccApiController.class);
private boolean checkYnrccSign(Map<String, String> params, DlpayResp resp) {
@@ -375,5 +393,106 @@
}
}
+ private <T> void populate(String[] fields, String[] column, T bean) {
+ if (fields.length != column.length) {
+ throw new IllegalArgumentException("错误的列定义");
+ }
+ try {
+ Map<String, String> data = new HashMap<>();
+ for (int col = 0; col < column.length; ++col) {
+ data.put(column[col], fields[col]);
+ }
+ BeanUtils.populate(bean, data);
+ } catch (InvocationTargetException | IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ throw new IllegalArgumentException("错误的列定义");
+ }
+ private <T> T populate(String[] fields, String[] column, Class<T> beanClass) {
+ try {
+ T bean = beanClass.newInstance();
+ populate(fields, column, bean);
+ } catch (InstantiationException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ throw new IllegalArgumentException("错误的列定义");
+ }
+
+ private void writeLine(OutputStream output, String delimiter, Object... columns) throws IOException {
+ for (Object item : columns) {
+ output.write(item.toString().getBytes(StandardCharsets.UTF_8));
+ output.write(delimiter.getBytes());
+ }
+ output.write("\n".getBytes());
+ }
+
+ private void parseFile(String filePath, OutputStream output) {
+ int lineno = 1;
+ try {
+ BufferedReader reader = new BufferedReader(
+ new InputStreamReader(
+ new FileInputStream(filePath), "GBK"));
+ String header = reader.readLine();
+ if (header == null) {
+ throw new IllegalArgumentException("数据文件内容为空");
+ }
+
+ CheckFileHeader fileHeader = populate(chkFileHeaderColumnList,
+ header.split(chkFileDelimiter), CheckFileHeader.class);
+
+
+ CheckFileLine record = new CheckFileLine();
+ writeLine(output, ",", "refno", "agentrefno", "agentdate", "flag", "payerid",
+ "payeeid", "amount", "summary");
+ while (true) {
+ String line = reader.readLine();
+ if (line == null) {
+ break;
+ }
+ lineno++;
+ String[] field = line.split(chkFileDelimiter);
+ populate(chkFileColumnList, field, record);
+ int amount;
+ String flag;
+ if (FLAG_WITHHOLD.equals(record.getFlag())) {
+ amount = -record.getAmount();
+ flag = "pay";
+ fileHeader.setPayCount(fileHeader.getPayCount() - 1);
+ fileHeader.setPayAmount(fileHeader.getPayAmount() - record.getAmount());
+ } else if (FLAG_REFUND.equals(record.getFlag())) {
+ amount = +record.getAmount();
+ flag = "refund";
+ fileHeader.setRefundCount(fileHeader.getRefundCount() - 1);
+ fileHeader.setRefundAmount(fileHeader.getRefundAmount() - record.getAmount());
+ } else {
+ throw new IllegalArgumentException("对账文件【报文业务类型】错误,行数 " + lineno + " 。");
+ }
+ fileHeader.setTotalCount(fileHeader.getTotalCount() - 1);
+ fileHeader.setTotalAmount(fileHeader.getTotalAmount() - record.getAmount());
+ writeLine(output, ",", record.getRefno(),
+ record.getAgentrefno(), record.getAgentdate(),
+ flag, record.getPayerid(), record.getPayeeid(),
+ amount, record.getSummary());
+ }
+ if (!fileHeader.isZero()) {
+ throw new IllegalArgumentException("对账文件总金额与笔数与明细不符");
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new IllegalArgumentException("对账文件数据格式错误,行数 " + lineno + " 。");
+ }
+ }
+
+ @GetMapping("/download")
+ public void downloadFile(@RequestParam("file") String file, HttpServletResponse response) throws IOException {
+ try {
+ parseFile(file, response.getOutputStream());
+ } catch (Exception e) {
+ e.printStackTrace();
+ response.sendError(HttpStatus.SERVICE_UNAVAILABLE.value(), e.getMessage());
+ }
+ }
}