新接口测试通过
diff --git a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/TransactionProxy.java b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/TransactionProxy.java
index 570587a..5d6be32 100644
--- a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/TransactionProxy.java
+++ b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/TransactionProxy.java
@@ -15,4 +15,7 @@
@PostMapping("/api/consume/queryresult")
QueryTransDtlResponse queryDtlResult(@RequestBody QueryDtlResultParam param);
+
+ @PostMapping("/api/consume/thirdquery")
+ QueryTransDtlResponse queryDtlResultByThird(@RequestBody QueryDtlResultParam param);
}
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/agent/ynrccpay/YnrccPayChkfile.java b/payapi/src/main/java/com/supwisdom/dlpay/agent/ynrccpay/YnrccPayChkfile.java
new file mode 100644
index 0000000..1690847
--- /dev/null
+++ b/payapi/src/main/java/com/supwisdom/dlpay/agent/ynrccpay/YnrccPayChkfile.java
@@ -0,0 +1,138 @@
+package com.supwisdom.dlpay.agent.ynrccpay;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 农商行快捷支付对账单
+ * 4
+ * ZF01|20210308|20201225161726|20210308151427000066|5607894487|10020104721000000001||0.01|156|0|0.01||20201225161726000115
+ * ZF01|20210308|20210308161616|20210308140757000064|5607894462|10020104721000000001||0.01|156|0|0.01||20210113170353000126
+ * ZF01|20210308|20210308181818|20210308150900000065|5607894483|10020104721000000001||0.01|156|0|0.01||20201225110202000098
+ * ZF02|20210308|20210308152004|114075700006420210308152004|20210308140757000064|10020104721000000001||0.01|156|0|0.01||
+ * */
+public class YnrccPayChkfile {
+
+ private String payFlag; //交易代码:ZF01-支付;ZF02-退款
+ private String clearDate; //清算日期
+ private String transDateTime; //交易时间 yyyyMMddHHmmss
+ private String billNo; //商户订单号
+ private String agentRefno; //银行流水号
+ private String merchantNo; //商户号
+ private String termNo; //终端号
+ private String amount; //交易金额,单位:元
+ private String currencyType; //币种 156-人民币
+ private String feeAmount; //手续费,单位:元
+ private String diffAmount; //交易金额与手续费金额的差值(交易金额-手续费金额),单位:元
+ private String remark1; //备注1
+ private String remark2; //备注2
+
+ public static final String PAY = "ZF01";
+ public static final String REFUND = "ZF02";
+ public static final List<String> HEADER = Arrays.asList("payFlag", "clearDate", "transDateTime", "billNo", "agentRefno",
+ "merchantNo", "termNo", "amount", "currencyType", "feeAmount", "diffAmount", "remark1", "remark2");
+
+ public String getPayFlag() {
+ return payFlag;
+ }
+
+ public void setPayFlag(String payFlag) {
+ this.payFlag = payFlag;
+ }
+
+ public String getClearDate() {
+ return clearDate;
+ }
+
+ public void setClearDate(String clearDate) {
+ this.clearDate = clearDate;
+ }
+
+ public String getTransDateTime() {
+ return transDateTime;
+ }
+
+ public void setTransDateTime(String transDateTime) {
+ this.transDateTime = transDateTime;
+ }
+
+ public String getBillNo() {
+ return billNo;
+ }
+
+ public void setBillNo(String billNo) {
+ this.billNo = billNo;
+ }
+
+ public String getAgentRefno() {
+ return agentRefno;
+ }
+
+ public void setAgentRefno(String agentRefno) {
+ this.agentRefno = agentRefno;
+ }
+
+ public String getMerchantNo() {
+ return merchantNo;
+ }
+
+ public void setMerchantNo(String merchantNo) {
+ this.merchantNo = merchantNo;
+ }
+
+ public String getTermNo() {
+ return termNo;
+ }
+
+ public void setTermNo(String termNo) {
+ this.termNo = termNo;
+ }
+
+ public String getAmount() {
+ return amount;
+ }
+
+ public void setAmount(String amount) {
+ this.amount = amount;
+ }
+
+ public String getCurrencyType() {
+ return currencyType;
+ }
+
+ public void setCurrencyType(String currencyType) {
+ this.currencyType = currencyType;
+ }
+
+ public String getFeeAmount() {
+ return feeAmount;
+ }
+
+ public void setFeeAmount(String feeAmount) {
+ this.feeAmount = feeAmount;
+ }
+
+ public String getDiffAmount() {
+ return diffAmount;
+ }
+
+ public void setDiffAmount(String diffAmount) {
+ this.diffAmount = diffAmount;
+ }
+
+ public String getRemark1() {
+ return remark1;
+ }
+
+ public void setRemark1(String remark1) {
+ this.remark1 = remark1;
+ }
+
+ public String getRemark2() {
+ return remark2;
+ }
+
+ public void setRemark2(String remark2) {
+ this.remark2 = remark2;
+ }
+}
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/agent/ynrccpay/YnrccPayUtil.java b/payapi/src/main/java/com/supwisdom/dlpay/agent/ynrccpay/YnrccPayUtil.java
index 38a6982..ce51759 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/agent/ynrccpay/YnrccPayUtil.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/agent/ynrccpay/YnrccPayUtil.java
@@ -17,10 +17,10 @@
public static final String MER_NAME = "ynrcc.netpay.Mer_IdName";
public static final String MER_URL = "ynrcc.netpay.MerURL";
-
+ public static final String chkFileDelimiter = "|";
public static final String SUCCESS = "ZF0000";
public static final String WAIT_FOR_QUERY = "ZF0098"; //等待查询结果
- public static final String NO_RECORDS_TODAY = "0406"; //当日无交易明细
+ public static final String NO_RECORDS_TODAY = "ZF0101"; //当日无交易明细
public static String toJson(Object obj) {
@@ -76,12 +76,13 @@
errcode.add(Pair.of(AgentCode.ILLEGAL_DATA, new YnrccRespCode("ZF00A0", "成功接收订单")));
errcode.add(Pair.of(AgentCode.ILLEGAL_DATA, new YnrccRespCode("ZF00A1", "支付方取消订单")));
- errcode.add(Pair.of(AgentCode.ILLEGAL_DATA, new YnrccRespCode("ZF0101", "无相关数据")));
+ errcode.add(Pair.of(AgentCode.REFNO_NOT_EXISTS, new YnrccRespCode("ZF0101", "无相关数据")));
errcode.add(Pair.of(AgentCode.ILLEGAL_DATA, new YnrccRespCode("ZF0214", "平台已冻结或已注销")));
//自定义错误 ZExxxx
errcode.add(Pair.of(AgentCode.CONFIG_ERROR, new YnrccRespCode("ZE0001", "系统参数未配置")));
errcode.add(Pair.of(AgentCode.COMMON_ERROR, new YnrccRespCode("ZE0002", "签名计算错误")));
+ errcode.add(Pair.of(AgentCode.ILLEGAL_DATA, new YnrccRespCode("ZE0097", "请求农商行网关快捷支付返回数据有误")));
errcode.add(Pair.of(AgentCode.ILLEGAL_DATA, new YnrccRespCode("ZE0098", "请求农商行网关快捷支付返回数据为空")));
errcode.add(Pair.of(AgentCode.SERVER_INTERNAL_ERROR, new YnrccRespCode("ZE0099", "请求农商行网关快捷支付httpStatus非200")));
}
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/api/dao/ShopSourceTypeConfigDao.java b/payapi/src/main/java/com/supwisdom/dlpay/api/dao/ShopSourceTypeConfigDao.java
index e861165..9c59a82 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/api/dao/ShopSourceTypeConfigDao.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/api/dao/ShopSourceTypeConfigDao.java
@@ -14,4 +14,7 @@
@Query("select a from TShopSourceTypeConfig a where a.shopaccno=?1 and a.sourceType=?2 and a.configid=?3 ")
TShopSourceTypeConfig getShopSourceTypeConfigById(String shopaccno, String sourceType, String configid);
+
+ @Query("select distinct a.shopaccno from TShopSourceTypeConfig a where a.sourceType=?1 order by a.shopaccno ")
+ List<String> getSourcetypeBindShopaccnos(String sourceType);
}
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/api/dao/TransactionMainDao.java b/payapi/src/main/java/com/supwisdom/dlpay/api/dao/TransactionMainDao.java
index b72f8d2..10a3139 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/api/dao/TransactionMainDao.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/api/dao/TransactionMainDao.java
@@ -8,6 +8,7 @@
import javax.persistence.LockModeType;
import javax.persistence.QueryHint;
+import java.util.List;
public interface TransactionMainDao extends CrudRepository<TTransactionMain, String> {
@@ -28,4 +29,12 @@
@Query("select min(t.accdate) from TTransactionMain t where t.sourceType=?1 ")
String findMinAccdateBySourcetype(String sourcetype);
+
+ @Query("from TTransactionMain t where t.reverseRefno=?1 and t.status='success' order by t.refno ")
+ List<TTransactionMain> findByRefundSuccessTransdtl(String refno);
+
+ @Query("from TTransactionMain t where t.reverseRefno=?1 order by t.refno ")
+ List<TTransactionMain> findByRefundTransdtl(String refno);
+
+
}
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/api/service/SourceTypeService.java b/payapi/src/main/java/com/supwisdom/dlpay/api/service/SourceTypeService.java
index 8e4048b..0e81d21 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/api/service/SourceTypeService.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/api/service/SourceTypeService.java
@@ -52,4 +52,7 @@
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
TSourceTypeCheckStatus saveOrUpdateSourceTypeCheckStatus(TSourceTypeCheckStatus s);
+ @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class, readOnly = true)
+ List<String> getShopaccnoBySourcetype(String sourcetype);
+
}
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/api/service/impl/SourceTypeServiceImpl.java b/payapi/src/main/java/com/supwisdom/dlpay/api/service/impl/SourceTypeServiceImpl.java
index 62c471f..f0bd529 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/api/service/impl/SourceTypeServiceImpl.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/api/service/impl/SourceTypeServiceImpl.java
@@ -11,6 +11,7 @@
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -210,4 +211,10 @@
}
return sourceTypeCheckDao.save(s);
}
+
+ @Override
+ public List<String> getShopaccnoBySourcetype(String sourcetype) {
+ List<String> list = shopSourceTypeConfigDao.getSourcetypeBindShopaccnos(sourcetype);
+ return list != null ? list : new ArrayList<String>(0);
+ }
}
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/impl/ynrcc_netpay_service_impl.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/impl/ynrcc_netpay_service_impl.kt
index 3949c55..d8b5af1 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/impl/ynrcc_netpay_service_impl.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/impl/ynrcc_netpay_service_impl.kt
@@ -22,6 +22,7 @@
import org.springframework.util.LinkedMultiValueMap
import org.springframework.util.MultiValueMap
import org.springframework.web.client.RestTemplate
+import java.net.URLDecoder
import java.nio.charset.StandardCharsets
@Service
@@ -186,7 +187,10 @@
return error("ZE0098", "请求农商行网关【$opt】返回数据为空!")
}
- val resData = YNRCCFastGateWayPayApi.verify(resJson.signature, resJson.plain) //调SDK验证签名
+ val resData = when ("对账" == opt) {
+ true -> YNRCCFastGateWayPayApi.verify(resJson.signature, URLDecoder.decode(resJson.plain,"UTF-8")) //对账需先解码
+ false -> YNRCCFastGateWayPayApi.verify(resJson.signature, resJson.plain) //调SDK验证签名
+ }
logger.info("农商行网关快捷支付请求【$opt】返回:\nurl=[$url]\nResponse Plain=[" + YnrccPayUtil.toJson(resData) + "]")
val respCode = resData["RespCode"]?.trim()?.replace("\r\n", "")
return if (YnrccPayUtil.SUCCESS == respCode) {
@@ -421,7 +425,7 @@
resp.code = result["RespCode"]
resp.message = result["RespDesc"]
if (YnrccPayUtil.SUCCESS == result["RespCode"]) {
- resp.plain = result["Plain"] //对账单
+ resp.plain = result["FileContent"] //对账单
}
return resp
}
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/ynrcc_netpay_service.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/ynrcc_netpay_service.kt
index 127e319..2510ab4 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/ynrcc_netpay_service.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/ynrcc_netpay_service.kt
@@ -86,7 +86,7 @@
}
override fun query(transaction: TTransactionMain): AgentResponse<DtlStatus> {
- val resp = ynrccNetPayService.doQueryYnrccPayResult(transaction.shopDtl.shopaccno, transaction.refno, transaction.shopDtl.transdate)
+ val resp = ynrccNetPayService.doQueryYnrccPayResult(transaction.shopDtl.shopaccno, transaction.refno, transaction.shopDtl.accdate)
return AgentResponse<DtlStatus>().also {
val code = agentCode(resp.code, resp.message)
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/ynrccpay_checkfile_service.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/ynrccpay_checkfile_service.kt
index 0c7126e..21fc8c1 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/ynrccpay_checkfile_service.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/agent/service/ynrccpay_checkfile_service.kt
@@ -3,6 +3,7 @@
import com.supwisdom.dlpay.agent.AgentCode
import com.supwisdom.dlpay.agent.AgentResponse
import com.supwisdom.dlpay.agent.CheckFileProvider
+import com.supwisdom.dlpay.agent.ynrccpay.YnrccPayChkfile
import com.supwisdom.dlpay.agent.ynrccpay.YnrccPayUtil
import com.supwisdom.dlpay.api.domain.TSourceTypeCheckStatus
import com.supwisdom.dlpay.api.domain.TTransactionChkfile
@@ -10,10 +11,16 @@
import com.supwisdom.dlpay.api.service.TransactionReconciliationService
import com.supwisdom.dlpay.exception.TransactionException
import com.supwisdom.dlpay.framework.service.SystemUtilService
+import com.supwisdom.dlpay.framework.util.StringUtil
+import com.supwisdom.dlpay.framework.util.TradeDict
import com.supwisdom.dlpay.util.ConstantUtil
import mu.KotlinLogging
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component
+import java.io.BufferedReader
+import java.io.ByteArrayInputStream
+import java.io.InputStreamReader
+import java.nio.charset.Charset
@Component("ynrccpayCheckFileProvider")
class YnrccpayCheckFileProvider : CheckFileProvider {
@@ -58,49 +65,89 @@
return successDownload("[$billDate]日对账数据已入库成功", checkStatus)
}
- val shopaccno = ""
- val resp = ynrccNetPayService.doQueryYnrccPayChkfile(billDate, shopaccno)
- when (resp.code) {
- YnrccPayUtil.SUCCESS -> {
- //TODO: 农商行网关快捷支付 对账文件解析
- val agentUrl = ""
-
- //成功
- return AgentResponse<TSourceTypeCheckStatus>().also {
- it.code = AgentCode.FAIL
- it.agentMsg = "获取对账文件逻辑暂缺"
-// it.payload = sourceTypeService.saveOrUpdateSourceTypeCheckStatus(checkStatus.apply {
-// this.checkFileOk = false
-// this.chkfileUrl = agentUrl
-// })
+ val fileDataList = ArrayList<YnrccPayChkfile>(0)
+ val shopaccList = sourceTypeService.getShopaccnoBySourcetype(TradeDict.PAYTYPE_YNRCC_PAY) //所有开通快捷支付的商户
+ for (shopacc in shopaccList) {
+ val resp = ynrccNetPayService.doQueryYnrccPayChkfile(billDate, shopacc)
+ when (resp.code) {
+ YnrccPayUtil.SUCCESS -> {
+ //成功
+ BufferedReader(InputStreamReader(resp.plain?.byteInputStream(Charset.forName("UTF-8")))).use { reader ->
+ val totalCnt = reader.readLine()?.trim()?.toInt() //总条目数
+ var records = 0
+ while (true) {
+ val line = reader.readLine() ?: break
+ if (line.isEmpty()) continue
+ val columns = line.split(YnrccPayUtil.chkFileDelimiter)
+ val bean = YnrccPayChkfile()
+ try {
+ StringUtil.transforToBean(YnrccPayChkfile.HEADER, columns, bean)
+ }catch (etr:Exception){
+ throw TransactionException(97, "商户[$shopacc]对账单下载[$billDate]文件明细解析错误!${etr.message}")
+ }
+ fileDataList.add(bean)
+ records++
+ }
+ if (totalCnt != records) {
+ throw TransactionException(97, "商户[$shopacc]对账单下载[$billDate]文件总交易笔数和明细不符!")
+ }
+ }
}
+ YnrccPayUtil.NO_RECORDS_TODAY -> {
+ //fixme:当日无交易明细
+ }
+ else -> {
+ //报错,退出对账单拉取
+ logger.error("农商行网关快捷支付商户[$shopacc]对账单下载[$billDate]报错:${resp.message}")
+ chkfile.status = ConstantUtil.CHKFILE_STATUS_ERROR
+ chkfile.remark = "商户[$shopacc]请求获取对账文件报错:${resp.message}"
+ transactionReconciliationService.saveOrUpdateTransactionChkfile(chkfile)
- }
- YnrccPayUtil.NO_RECORDS_TODAY -> {
- //当日无交易明细,也创建空记录
- transactionReconciliationService.doSuccessTransactionChkfile(chkfile, "请求银行返回:当日无交易明细")
- //成功
- return successDownload("当日无交易明细", checkStatus.apply {
- this.chkfileUrl = "none"
- })
- }
- else -> {
- //报错,退出对账单拉取
- logger.error("农商行网关快捷支付对账单下载[$billDate]报错:${resp.message}")
- chkfile.status = ConstantUtil.CHKFILE_STATUS_ERROR
- chkfile.remark = "请求获取对账文件报错:${resp.message}"
- transactionReconciliationService.saveOrUpdateTransactionChkfile(chkfile)
-
- //失败
- return AgentResponse<TSourceTypeCheckStatus>().also {
- it.code = AgentCode.FAIL
- it.agentMsg = chkfile.remark
- it.payload = sourceTypeService.saveOrUpdateSourceTypeCheckStatus(checkStatus.apply {
- this.remark = chkfile.remark
- })
+ //失败,直接返回
+ return AgentResponse<TSourceTypeCheckStatus>().also {
+ it.code = AgentCode.FAIL
+ it.agentMsg = chkfile.remark
+ it.payload = sourceTypeService.saveOrUpdateSourceTypeCheckStatus(checkStatus.apply {
+ this.remark = chkfile.remark
+ })
+ }
}
}
}
+
+ if(fileDataList.isEmpty()){
+ //当日无交易明细,也创建空记录
+ transactionReconciliationService.doSuccessTransactionChkfile(chkfile, "请求银行返回:当日无交易明细")
+ //成功
+ return successDownload("当日无交易明细", checkStatus.apply {
+ this.chkfileUrl = "none"
+ })
+ }
+
+ //保存对账单
+ val failcnt = doBatchSaveYnrccPayCheckDetails(chkfile, fileDataList)
+ if (failcnt > 0) {
+ chkfile.status = ConstantUtil.CHKFILE_STATUS_ERROR
+ chkfile.remark = "对账单数据存在保存失败记录,请手动核对对账单数据"
+ transactionReconciliationService.saveOrUpdateTransactionChkfile(chkfile)
+
+ return AgentResponse<TSourceTypeCheckStatus>().also {
+ it.code = AgentCode.FAIL
+ it.agentMsg = chkfile.remark
+ it.payload = sourceTypeService.saveOrUpdateSourceTypeCheckStatus(checkStatus.apply {
+ this.checkFileOk = false
+ this.chkfileUrl = "none"
+ this.remark = chkfile.remark
+ })
+ }
+ }
+
+ //成功
+ transactionReconciliationService.doSuccessTransactionChkfile(chkfile, "对账单数据下载成功")
+ return successDownload("[$billDate]日对账数据入库成功", checkStatus.apply {
+ this.chkfileUrl = "none"
+ })
+
} catch (et: TransactionException) {
return AgentResponse<TSourceTypeCheckStatus>().also {
it.code = AgentCode.FAIL
@@ -154,4 +201,26 @@
}
}
+ private fun doBatchSaveYnrccPayCheckDetails(chkfile: TTransactionChkfile, list: ArrayList<YnrccPayChkfile>): Int {
+ try {
+ transactionReconciliationService.doBatchSaveYnrccPayTransactionChkDtl(chkfile, list)
+ return 0 //批量保存成功,无失败
+ } catch (e1: Exception) {
+ }
+
+ //批量保存有异常,逐笔保存
+ var failcnt = 0
+ var index = 1
+ for (bean in list) {
+ try {
+ transactionReconciliationService.saveYnrccPayTransactionChkDtl(chkfile, bean, index++)
+ } catch (e2: Exception) {
+ failcnt++
+ e2.printStackTrace()
+ continue
+ }
+ }
+ return failcnt
+ }
+
}
\ No newline at end of file
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 f01d870..fd77c55 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
@@ -7,6 +7,7 @@
import com.supwisdom.dlpay.api.domain.TShopdtl
import com.supwisdom.dlpay.api.domain.TTransactionMain
import com.supwisdom.dlpay.api.repositories.ShopaccService
+import com.supwisdom.dlpay.api.service.ConsumePayService
import com.supwisdom.dlpay.api.service.DtlQueryResultService
import com.supwisdom.dlpay.api.service.TransactionServiceProxy
import com.supwisdom.dlpay.exception.TransactionException
@@ -123,6 +124,9 @@
@Autowired
private lateinit var systemUtilService: SystemUtilService
+ @Autowired
+ lateinit var consumePayService: ConsumePayService
+
@Async("queryAgentPayResult")
fun queryResult(transaction: TTransactionMain, qcnt: Int) {
try {
@@ -148,31 +152,41 @@
transaction.sourceType + "Agent")
logger.info("refno=[${transaction.refno}]开始第" + (qcnt + 1) + "次查询支付结果:")
+ var endFlag = false
val resp = service.query(transaction)
when (resp.code) {
AgentCode.SUCCESS -> {
//查询成功
when (resp.dtlStatus) {
- DtlStatus.SUCCESS ->
+ DtlStatus.SUCCESS -> {
+ endFlag = true
transactionService.success(transaction.refno, resp.agentRefno, false) //流水成功
+ }
DtlStatus.REFUND -> {
//流水已退款 TODO:流水成功后才退款,无查询原成功流水逻辑
+ endFlag = true
logger.error("refno=[${transaction.refno}]查询结果为:已退款!!!")
return
}
DtlStatus.PARTIAL_REFUND -> {
//流水已部分退款 TODO:暂无逻辑
+ endFlag = true
logger.error("refno=[${transaction.refno}]查询结果为:已部分退款!!!")
return
}
else -> {
//流水失败
+ endFlag = true
transactionService.fail(transaction.refno, "查询流水状态为交易失败")
}
}
}
- AgentCode.REFNO_NOT_EXISTS ->
- transactionService.fail(transaction.refno, "银行流水不存在") //银行返回流水不存在
+ AgentCode.REFNO_NOT_EXISTS -> {
+ if(TradeDict.REVERSE_FLAG_NONE == transaction.reverseType) {
+ endFlag = true
+ transactionService.fail(transaction.refno, "银行流水不存在") //银行返回流水不存在
+ }
+ }
AgentCode.REQUIRE_QUERY -> {
queryResult(transaction, qcnt + 1) //查询次数加1
}
@@ -181,6 +195,36 @@
logger.error("查询refno=[${transaction.refno}]流水结果返回失败:code=[${resp.agentCode}],message=[${resp.agentMsg}]")
}
}
+
+ //fixme: 撤销或退款可能不需要传商户订单号,必须查询原流水状态
+ if (!endFlag && (TradeDict.REVERSE_FLAG_CANCEL == transaction.reverseType || TradeDict.REVERSE_FLAG_REFUND == transaction.reverseType)) {
+ consumePayService.getTransactionMainDtl(transaction.reverseRefno, null, null)?.let {
+ val origResp = service.query(it) //冲正流水,只能查询原始流水是否为退款状态
+ when (origResp.code) {
+ AgentCode.SUCCESS ->{
+ when (origResp.dtlStatus) {
+ DtlStatus.SUCCESS ->
+ transactionService.fail(transaction.refno, "查询确认退款失败!") //原始流水还是成功状态,则退款流水必定失败!!!
+ DtlStatus.REFUND -> {
+ //流水已退款
+ transactionService.success(transaction.refno, origResp.agentRefno, false) //TODO: 确保这条原始流水只有一笔全额冲正流水成功!!!
+ }
+ DtlStatus.PARTIAL_REFUND -> {
+ //流水已部分退款 TODO:暂无逻辑
+ }
+ else -> {
+ //流水失败 无逻辑
+ }
+ }
+ }
+ else -> {
+ //其他都重新查
+ queryResult(transaction, qcnt + 1) //查询次数加1
+ }
+ }
+ }
+ }
+
} catch (ex: Exception) {
ex.printStackTrace()
}
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/consume_api_controller.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/consume_api_controller.kt
index c9a6945..8d8a26d 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/consume_api_controller.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/consume_api_controller.kt
@@ -11,12 +11,11 @@
import com.supwisdom.dlpay.api.bean.groups.InitAction
import com.supwisdom.dlpay.api.domain.TSourceType
import com.supwisdom.dlpay.api.service.*
-import com.supwisdom.dlpay.api.util.Constants
import com.supwisdom.dlpay.exception.TransactionCheckException
import com.supwisdom.dlpay.framework.ResponseBodyBuilder
import com.supwisdom.dlpay.framework.service.SystemUtilService
-import com.supwisdom.dlpay.framework.tenant.TenantContext
import com.supwisdom.dlpay.framework.util.*
+import mu.KotlinLogging
import org.apache.commons.lang3.StringUtils
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.ApplicationContext
@@ -62,6 +61,8 @@
@Autowired
private lateinit var ynrccNetPayBusinessService: YnrccNetPayBusinessService
+ private val logger = KotlinLogging.logger { }
+
/**
* ============================================================================
* 消费流水结果查询统一接口
@@ -984,18 +985,91 @@
}
/**
- * 直接调第三方查询流水结果 (方便测试)
+ * ============================================================================
+ * 直接调第三方查询流水结果 (通用)
+ * ============================================================================
* */
@PostMapping("/thirdquery")
- fun thirdToQueryResult(refno: String): ResponseEntity<Any> {
- consumePayService.getTransactionMainDtl(refno, null, null)?.let {
- agentQueryResultTask.queryResult(it, 0)
- return ResponseEntity.ok(
- ResponseBodyBuilder.create()
- .success("已成功进入查询异步查询队列")
- )
- } ?: return ResponseEntity.ok(
- ResponseBodyBuilder.create()
+ fun queryDtlResultByThird(@Valid @RequestBody param: QueryDtlResultParam): ResponseEntity<Any> {
+ consumePayService.getTransactionMainDtl(param.refno, param.billno, param.shopaccno)?.let {
+ if (TradeDict.DTL_STATUS_SUCCESS == it.status || TradeDict.DTL_STATUS_FAIL == it.status) {
+ return ResponseEntity.ok(ResponseBodyBuilder.create()
+ .success(QueryTransDtlResponse(it.refno, it.outTradeNo, it.shopDtl.amount,
+ it.status, it.sourceType, it.personDtl.payinfo, it.reverseFlag,
+ it.shopDtl.transdesc,it.personDtl.remark), "查询成功"))
+ }
+
+ //发往第三方查询
+ var endFlag = false
+ val service = ApplicationUtil.findAgentPayService<Any>(applicationContext, it.sourceType + "Agent")
+ val resp = service.query(it)
+ when (resp.code) {
+ AgentCode.SUCCESS -> {
+ //查询成功
+ when (resp.dtlStatus) {
+ DtlStatus.SUCCESS -> {
+ endFlag = true
+ transactionService.success(it.refno, resp.agentRefno, false) //流水成功
+ }
+ DtlStatus.REFUND -> {
+ //流水已退款 TODO:流水成功后才退款,无查询原成功流水逻辑
+ }
+ DtlStatus.PARTIAL_REFUND -> {
+ //流水已部分退款 TODO:暂无逻辑
+ }
+ else -> {
+ //流水失败
+ endFlag = true
+ transactionService.fail(it.refno, "查询流水状态为交易失败")
+ }
+ }
+ }
+ AgentCode.REFNO_NOT_EXISTS -> {
+ if(TradeDict.REVERSE_FLAG_NONE == it.reverseType){
+ endFlag = true
+ transactionService.fail(it.refno, "银行流水不存在") //银行返回流水不存在
+ }
+ }
+ AgentCode.REQUIRE_QUERY -> {
+ //流水无结果 TODO: 还需继续查询
+ }
+ else -> {
+ //其他明确错误,查询失败
+ logger.error("向第三方查询 refno=[${it.refno}]流水结果返回失败:code=[${resp.agentCode}],message=[${resp.agentMsg}]")
+ }
+ }
+
+ //TODO: 撤销或退款可能不需要传商户订单号,必须查询原流水状态
+ if (!endFlag && (TradeDict.REVERSE_FLAG_CANCEL == it.reverseType || TradeDict.REVERSE_FLAG_REFUND == it.reverseType)) {
+ consumePayService.getTransactionMainDtl(it.reverseRefno, null, null)?.let { origDtl ->
+ val origResp = service.query(origDtl) //有冲正流水,原流水必定是成功流水。判断原流水状态是否为退款状态
+ when (origResp.code) {
+ AgentCode.SUCCESS -> {
+ when (origResp.dtlStatus) {
+ DtlStatus.SUCCESS ->
+ transactionService.fail(it.refno, "查询确认退款失败!") //原始流水还是成功状态,则退款流水必定失败!!!
+ DtlStatus.REFUND -> {
+ //流水已退款
+ transactionService.success(it.refno, origResp.agentRefno, false) //TODO: 确保这条原始流水只有一笔全额冲正流水成功!!!
+ }
+ DtlStatus.PARTIAL_REFUND -> {
+ //流水已部分退款 TODO:暂无逻辑
+ }
+ else -> {
+ //流水失败 无逻辑
+ }
+ }
+ }
+ else -> {
+ logger.error("向第三方查询 refno=[${it.refno}]冲正流水结果,原始流水支付状态查询返回失败:code=[${origResp.agentCode}],message=[${origResp.agentMsg}]")
+ }
+ }
+ }
+ }
+
+ return queryDtlResult(param) //直接查询逻辑
+
+ } ?: return ResponseEntity.ok(ResponseBodyBuilder.create()
.fail(TradeErrorCode.TRANSACTION_NOT_EXISTS, "流水不存在")
)
}
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/transaction_reconciliation_service_impl.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/transaction_reconciliation_service_impl.kt
index 9937a31..8292e63 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/transaction_reconciliation_service_impl.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/transaction_reconciliation_service_impl.kt
@@ -1,6 +1,7 @@
package com.supwisdom.dlpay.api.service.impl
import com.supwisdom.dlpay.agent.citizencard.YnrccUtil
+import com.supwisdom.dlpay.agent.ynrccpay.YnrccPayChkfile
import com.supwisdom.dlpay.api.bean.YnrccChkfileBean
import com.supwisdom.dlpay.api.dao.PersondtlDao
import com.supwisdom.dlpay.api.dao.TransactionChkdtlDao
@@ -9,6 +10,7 @@
import com.supwisdom.dlpay.api.domain.TSourceTypeCheckStatus
import com.supwisdom.dlpay.api.domain.TTransactionChkdtl
import com.supwisdom.dlpay.api.domain.TTransactionChkfile
+import com.supwisdom.dlpay.api.domain.TTransactionMain
import com.supwisdom.dlpay.api.service.SourceTypeService
import com.supwisdom.dlpay.api.service.TransactionReconciliationService
import com.supwisdom.dlpay.api.service.TransactionServiceProxy
@@ -305,4 +307,72 @@
transactionChkfileDao.save(chkfile)
return sourceTypeService.saveOrUpdateSourceTypeCheckStatus(checkStatus)
}
+
+ override fun doBatchSaveYnrccPayTransactionChkDtl(chkfile: TTransactionChkfile, list: ArrayList<YnrccPayChkfile>): Boolean {
+ var idx=1
+ for (bean in list) {
+ saveYnrccPayTransactionChkDtl(chkfile, bean, idx++)
+ }
+ return true
+ }
+
+ override fun saveYnrccPayTransactionChkDtl(chkfile: TTransactionChkfile, bean: YnrccPayChkfile, idx:Int): TTransactionChkdtl {
+ return when(bean.payFlag){
+ YnrccPayChkfile.PAY->{
+ transactionChkdtlDao.save(TTransactionChkdtl().apply {
+ this.chkfileId = chkfile.id
+ this.accdate = chkfile.accdate
+ this.sourcetype = chkfile.sourcetype
+ this.recordno = idx
+ this.amount = -1 * bean.amount.toDouble()
+ this.otherRefno = bean.agentRefno
+ this.localRefno = bean.billNo
+ this.otherAccdate = bean.clearDate
+ this.transtype = "pay"
+ this.otherStatus = "success"
+ this.remark = null
+ this.extdata = "农商行网关快捷支付"
+ this.chkresult = ConstantUtil.CHKDTL_CHKRESULT_UNCHECK
+ this.resolved = ConstantUtil.CHKDTL_RESOLVED_NONE
+ this.lastsaved = systemUtilService.sysdatetime.sysdate
+ this.tenantid = TenantContext.getTenantSchema()
+ })
+ }
+ YnrccPayChkfile.REFUND->{
+ val refno = bean.agentRefno //商户订单号
+ var localRefno = bean.billNo
+ val refundSuccessList = transactionMainDao.findByRefundSuccessTransdtl(refno)
+ if (null != refundSuccessList && refundSuccessList.size > 0) {
+ localRefno = refundSuccessList[0].refno //成功的退款流水
+ } else {
+ val refundTransdtlList = transactionMainDao.findByRefundTransdtl(refno)
+ if (null != refundTransdtlList && refundTransdtlList.size > 0) {
+ localRefno = refundTransdtlList[0].refno //第一笔退款的流水
+ }
+ }
+
+ transactionChkdtlDao.save(TTransactionChkdtl().apply {
+ this.chkfileId = chkfile.id
+ this.accdate = chkfile.accdate
+ this.sourcetype = chkfile.sourcetype
+ this.recordno = idx
+ this.amount = bean.amount.toDouble()
+ this.otherRefno = bean.billNo
+ this.localRefno = localRefno
+ this.otherAccdate = bean.clearDate
+ this.transtype = "refund"
+ this.otherStatus = "success"
+ this.remark = null
+ this.extdata = "农商行网关快捷支付退款[${bean.agentRefno}]"
+ this.chkresult = ConstantUtil.CHKDTL_CHKRESULT_UNCHECK
+ this.resolved = ConstantUtil.CHKDTL_RESOLVED_NONE
+ this.lastsaved = systemUtilService.sysdatetime.sysdate
+ this.tenantid = TenantContext.getTenantSchema()
+ })
+ }
+ else -> {
+ throw TransactionException(97, "不能识别对账单明细中交易代码[${bean.payFlag}]!")
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/transaction_reconciliation_service.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/transaction_reconciliation_service.kt
index d7ce27d..5c4e132 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/transaction_reconciliation_service.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/transaction_reconciliation_service.kt
@@ -1,5 +1,6 @@
package com.supwisdom.dlpay.api.service
+import com.supwisdom.dlpay.agent.ynrccpay.YnrccPayChkfile
import com.supwisdom.dlpay.api.bean.YnrccChkfileBean
import com.supwisdom.dlpay.api.domain.TSourceTypeCheckStatus
import com.supwisdom.dlpay.api.domain.TTransactionChkdtl
@@ -65,6 +66,10 @@
@Transactional(rollbackFor = [Exception::class])
fun doConfirmChkfileStatus(chkfile: TTransactionChkfile, checkStatus: TSourceTypeCheckStatus): TSourceTypeCheckStatus
+ @Transactional(rollbackFor = [Exception::class])
+ fun doBatchSaveYnrccPayTransactionChkDtl(chkfile: TTransactionChkfile, list: ArrayList<YnrccPayChkfile>): Boolean
+ @Transactional(rollbackFor = [Exception::class])
+ fun saveYnrccPayTransactionChkDtl(chkfile: TTransactionChkfile, bean: YnrccPayChkfile, idx: Int): TTransactionChkdtl
}
\ No newline at end of file
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/framework/controller/framework_controller.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/framework/controller/framework_controller.kt
index a55845f..c5e603c 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/framework/controller/framework_controller.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/framework/controller/framework_controller.kt
@@ -1,17 +1,24 @@
package com.supwisdom.dlpay.framework.controller
+import com.google.gson.Gson
import com.jcabi.manifests.Manifests
+import com.supwisdom.dlpay.agent.service.YnrccNetPayService
import com.supwisdom.dlpay.api.bean.ApiVersionResponse
import com.supwisdom.dlpay.framework.ResponseBodyBuilder
+import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
+import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController
@RestController
@RequestMapping("/api/common")
class AboutController {
+ @Autowired
+ lateinit var ynrccNetPayService: YnrccNetPayService
+
@GetMapping("/version")
fun version(): ResponseEntity<Any> {
return try {
@@ -24,4 +31,27 @@
.success(ApiVersionResponse("unknown")))
}
}
+
+ /**
+ * 查看农商行快捷支付对账单
+ * */
+ @GetMapping("/ynrccpaychkfile")
+ fun testYnrccpayChkfile(
+ @RequestParam("accdate") accdate: String,
+ @RequestParam("shopaccno") shopaccno: String
+ ): ResponseEntity<Any> {
+ return try {
+ val resp = ynrccNetPayService.doQueryYnrccPayChkfile(accdate, shopaccno)
+
+ ResponseEntity.ok(
+ ResponseBodyBuilder.create()
+ .success(Gson().toJson(resp))
+ )
+ } catch (e: IllegalArgumentException) {
+ ResponseEntity.ok(
+ ResponseBodyBuilder.create()
+ .fail(99, "throw exception!")
+ )
+ }
+ }
}
\ No newline at end of file