From: Xia Kaixiang Date: Thu, 18 Jul 2019 05:34:33 +0000 (+0800) Subject: 流水扫描查询任务 X-Git-Tag: 1.0.0^2~26 X-Git-Url: https://source.supwisdom.com/gerrit/gitweb?a=commitdiff_plain;h=61f2420bd3ce13c09f9c994ab5ac2cc50acbf1cd;p=epayment%2Ffood_payapi.git 流水扫描查询任务 --- diff --git a/payapi/src/main/java/com/supwisdom/dlpay/api/dao/DtlQueryDao.java b/payapi/src/main/java/com/supwisdom/dlpay/api/dao/DtlQueryDao.java new file mode 100644 index 00000000..ea6c3bef --- /dev/null +++ b/payapi/src/main/java/com/supwisdom/dlpay/api/dao/DtlQueryDao.java @@ -0,0 +1,13 @@ +package com.supwisdom.dlpay.api.dao; + +import com.supwisdom.dlpay.api.domain.TDtlQuery; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +import java.util.List; + +public interface DtlQueryDao extends JpaRepository { + + @Query("from TDtlQuery t where t.accdate=?1 and t.status=?2 and t.qcnt<=?3 order by t.lastsaved desc ") + List getNeedQueryDtls(String accdate, String status, int maxQcnt); +} diff --git a/payapi/src/main/java/com/supwisdom/dlpay/api/domain/TDtlQuery.java b/payapi/src/main/java/com/supwisdom/dlpay/api/domain/TDtlQuery.java new file mode 100644 index 00000000..feec7c50 --- /dev/null +++ b/payapi/src/main/java/com/supwisdom/dlpay/api/domain/TDtlQuery.java @@ -0,0 +1,115 @@ +package com.supwisdom.dlpay.api.domain; + +import org.hibernate.annotations.GenericGenerator; + +import javax.persistence.*; +import java.sql.Timestamp; + +@Entity +@Table(name = "TB_DTL_QUERY") +public class TDtlQuery { + @Id + @GenericGenerator(name = "idGenerator", strategy = "uuid") + @GeneratedValue(generator = "idGenerator") + @Column(name = "id", nullable = false, length = 32) + private String id; + + @Column(name = "ACCDATE", nullable = false, length = 32) + private String accdate; + + @Column(name = "REFNO", nullable = false, length = 32) + private String refno; + + @Column(name = "STATUS", nullable = false, length = 32) + private String status; + + @Column(name = "REMARK", length = 600) + private String remark; + + @Column(name = "QCNT", length = 9) + private Integer qcnt; + + @Column(name = "LASTSAVED") + @Version + private Timestamp lastsaved; + + @Column(name = "tenantid", nullable = false, length = 20) + private String tenantId; + + public TDtlQuery(){ + } + + public TDtlQuery(String accdate, String refno, String status, String remark, Integer qcnt, Timestamp lastsaved, String tenantId) { + this.accdate = accdate; + this.refno = refno; + this.status = status; + this.remark = remark; + this.qcnt = qcnt; + this.lastsaved = lastsaved; + this.tenantId = tenantId; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getAccdate() { + return accdate; + } + + public void setAccdate(String accdate) { + this.accdate = accdate; + } + + public String getRefno() { + return refno; + } + + public void setRefno(String refno) { + this.refno = refno; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + public Integer getQcnt() { + return qcnt; + } + + public void setQcnt(Integer qcnt) { + this.qcnt = qcnt; + } + + public Timestamp getLastsaved() { + return lastsaved; + } + + public void setLastsaved(Timestamp lastsaved) { + this.lastsaved = lastsaved; + } + + public String getTenantId() { + return tenantId; + } + + public void setTenantId(String tenantId) { + this.tenantId = tenantId; + } +} diff --git a/payapi/src/main/java/com/supwisdom/dlpay/util/ConstantUtil.java b/payapi/src/main/java/com/supwisdom/dlpay/util/ConstantUtil.java index 6cacabd3..3c7b5de4 100644 --- a/payapi/src/main/java/com/supwisdom/dlpay/util/ConstantUtil.java +++ b/payapi/src/main/java/com/supwisdom/dlpay/util/ConstantUtil.java @@ -29,4 +29,8 @@ public class ConstantUtil { * */ public static final String CARDTYPE_CITIZENCARD = "citizencard"; public static final String CARDTYPE_BANKCARD = "bankcard"; + + public static final String QUERYTYPE_NEED_QUERY = "query"; + public static final String QUERYTYPE_QUERY_FINISH = "finish"; + public static final int QUERY_MAX_COUNT = 10; } 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 133427f5..4139d9e6 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 @@ -4,10 +4,15 @@ 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 import com.supwisdom.dlpay.api.repositories.ShopaccService +import com.supwisdom.dlpay.api.service.DtlQueryResultService import com.supwisdom.dlpay.api.service.TransactionServiceProxy +import com.supwisdom.dlpay.framework.service.SystemUtilService import com.supwisdom.dlpay.framework.util.ApplicationUtil +import com.supwisdom.dlpay.framework.util.TradeDict +import com.supwisdom.dlpay.util.ConstantUtil import mu.KotlinLogging import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler import org.springframework.beans.factory.annotation.Autowired @@ -70,12 +75,28 @@ class AgentQueryResultTask { @Autowired private lateinit var applicationContext: ApplicationContext + @Autowired + private lateinit var dtlQueryResultService: DtlQueryResultService + + @Autowired + private lateinit var systemUtilService: SystemUtilService + @Async("queryAgentPayResult") fun queryResult(transaction: TTransactionMain, qcnt: Int) { try { if (qcnt >= YnrccUtil.QUERY_MAX_COUNT) { //查询超最大次数 logger.error("查询refno=[${transaction.refno}]流水结果超最大查询次数[${YnrccUtil.QUERY_MAX_COUNT}]") + + //保存进查询表,定时扫描任务去查询 + dtlQueryResultService.saveOrUpdateDtlQuery(TDtlQuery().apply { + this.accdate = transaction.accdate + this.refno = transaction.refno + this.status = ConstantUtil.QUERYTYPE_NEED_QUERY + this.remark = null + this.qcnt = 0 + this.lastsaved = systemUtilService.sysdatetime.sysdate + }) return } diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/scheduler_task.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/scheduler_task.kt index 0e6d6943..38f652f5 100644 --- a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/scheduler_task.kt +++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/scheduler_task.kt @@ -1,15 +1,30 @@ package com.supwisdom.dlpay.api +import com.supwisdom.dlpay.agent.AgentCode +import com.supwisdom.dlpay.agent.DtlStatus +import com.supwisdom.dlpay.api.domain.TDtlQuery import com.supwisdom.dlpay.api.domain.TShopdtl 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.framework.domain.TTaskLock +import com.supwisdom.dlpay.framework.service.SystemUtilService +import com.supwisdom.dlpay.framework.util.ApplicationUtil +import com.supwisdom.dlpay.framework.util.TradeDict +import com.supwisdom.dlpay.util.ConstantUtil import org.springframework.beans.factory.annotation.Autowired +import org.springframework.context.ApplicationContext import org.springframework.scheduling.annotation.Scheduled +import org.springframework.stereotype.Component import org.springframework.stereotype.Service @Service class MySchedulerTask { @Autowired private lateinit var shopaccService: ShopaccService + @Autowired + private lateinit var systemUtilService: SystemUtilService fun doShopBlanceUpdate(dtl: TShopdtl) { shopaccService.recalcShopBalance(dtl.refno, true) @@ -17,8 +32,159 @@ class MySchedulerTask { @Scheduled(cron = "\${shopbalance.updater.cron:-}") fun dealShopUnupdatedDtl() { - shopaccService.findUnupdatedShopDtl(100).forEach { - doShopBlanceUpdate(it) + var tasklock = TTaskLock() + try { + //集群控制 + try { + tasklock = systemUtilService.doLockTask("SHOPBLANCEUPDATETASK", 10, "更新账户余额任务") + if (tasklock == null) { + return + } + } catch (e: Exception) { + return + } + + shopaccService.findUnupdatedShopDtl(100).forEach { + doShopBlanceUpdate(it) + } + } catch (ex: Exception) { + ex.printStackTrace() + } finally { + if (tasklock?.taskcode.isNotEmpty()) { + tasklock.taskstatus = 0 + tasklock.tasktime = systemUtilService.sysdatetime.hostdatetime + systemUtilService.updateTaskLock(tasklock) + } } + + } +} + +/** + * 定时扫描TDtlQuery,查询第三方流水状态 + * */ +@Component +class DtlQueryResultSchedulerTask { + @Autowired + private lateinit var systemUtilService: SystemUtilService + @Autowired + private lateinit var dtlQueryResultService: DtlQueryResultService + @Autowired + lateinit var transactionService: TransactionServiceProxy + @Autowired + lateinit var consumePayService: ConsumePayService + @Autowired + private lateinit var applicationContext: ApplicationContext + + @Scheduled(cron = "\${query.third.transdtl.result.cron:-}") + fun queryThirdTransdtlResult() { + var tasklock = TTaskLock() + try { + //集群控制 + try { + tasklock = systemUtilService.doLockTask("QUERYTHIRDTRANSDTLRESULTTASK", 10, "查询第三方流水状态任务") + if (tasklock == null) { + return + } + } catch (e: Exception) { + return + } + + //仅查询当天数据,查询次数在规定次数之下 + dtlQueryResultService.getNeedQueryRecords(systemUtilService.accdate, ConstantUtil.QUERY_MAX_COUNT).forEach { + try { + doQuery(it) + } catch (exp: Exception) { + it.qcnt = it.qcnt + 1 + dtlQueryResultService.saveOrUpdateDtlQuery(it) //次数加一 + } + } + } catch (ex: Exception) { + ex.printStackTrace() + } finally { + if (tasklock?.taskcode.isNotEmpty()) { + tasklock.taskstatus = 0 + tasklock.tasktime = systemUtilService.sysdatetime.hostdatetime + systemUtilService.updateTaskLock(tasklock) + } + } + } + + private fun doQuery(dtlQuery: TDtlQuery) { + if (ConstantUtil.QUERYTYPE_NEED_QUERY != dtlQuery.status) { + return //已结束 + } + val dtl = consumePayService.getTransactionMainDtl(dtlQuery.refno, null, null) + if (null == dtl) { + dtlQuery.qcnt = dtlQuery.qcnt + 1 + dtlQuery.status = ConstantUtil.QUERYTYPE_QUERY_FINISH + dtlQuery.remark = "refno未找到流水" + dtlQueryResultService.saveOrUpdateDtlQuery(dtlQuery) + return + } else if (TradeDict.DTL_STATUS_WIP != dtl.status) { + dtlQuery.qcnt = dtlQuery.qcnt + 1 + dtlQuery.status = ConstantUtil.QUERYTYPE_QUERY_FINISH + dtlQuery.remark = "原始流水非wip状态" + dtlQueryResultService.saveOrUpdateDtlQuery(dtlQuery) + return + } else if (TradeDict.PAYTYPE_CITIZEN_CARD != dtl.sourceType) { + //fixme: 现仅供大理农商卡对接查询 + dtlQuery.qcnt = dtlQuery.qcnt + 1 + dtlQuery.status = ConstantUtil.QUERYTYPE_QUERY_FINISH + dtlQuery.remark = "非大理市民卡支付流水" + dtlQueryResultService.saveOrUpdateDtlQuery(dtlQuery) + return + } + + val service = ApplicationUtil.findAgentPayService(applicationContext, dtl.sourceType + "Agent") + val resp = service.query(dtl) + when (resp.code) { + AgentCode.SUCCESS -> { + //查询成功 + when (resp.dtlStatus) { + DtlStatus.SUCCESS -> { + transactionService.success(dtl.refno, resp.agentRefno, false) //流水成功 + dtlQuery.qcnt = dtlQuery.qcnt + 1 + dtlQuery.status = ConstantUtil.QUERYTYPE_QUERY_FINISH + dtlQuery.remark = "查询成功,流水为付款成功状态" + dtlQueryResultService.saveOrUpdateDtlQuery(dtlQuery) + return + } + DtlStatus.REFUND, DtlStatus.PARTIAL_REFUND -> { + dtlQuery.qcnt = dtlQuery.qcnt + 1 + dtlQuery.status = ConstantUtil.QUERYTYPE_QUERY_FINISH + dtlQuery.remark = "查询成功,流水为已退款或部分退款状态" + dtlQueryResultService.saveOrUpdateDtlQuery(dtlQuery) + return + } + else -> { + //流水失败 + transactionService.fail(dtl.refno, "查询流水状态为交易失败") + dtlQuery.qcnt = dtlQuery.qcnt + 1 + dtlQuery.status = ConstantUtil.QUERYTYPE_QUERY_FINISH + dtlQuery.remark = "查询成功,流水为失败状态" + dtlQueryResultService.saveOrUpdateDtlQuery(dtlQuery) + return + } + } + } + AgentCode.REFNO_NOT_EXISTS -> { + transactionService.fail(dtl.refno, "银行流水不存在") //银行返回流水不存在 + dtlQuery.qcnt = dtlQuery.qcnt + 1 + dtlQuery.status = ConstantUtil.QUERYTYPE_QUERY_FINISH + dtlQuery.remark = "查询成功,返回流水不存在" + dtlQueryResultService.saveOrUpdateDtlQuery(dtlQuery) + return + } + else -> { + //其他明确错误,后续再查询 + dtlQuery.qcnt = dtlQuery.qcnt + 1 + dtlQuery.remark = "查询失败!${resp.agentMsg}" + dtlQueryResultService.saveOrUpdateDtlQuery(dtlQuery) + return + } + } + } + } \ No newline at end of file diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/dtl_query_result_service.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/dtl_query_result_service.kt new file mode 100644 index 00000000..9673b0f4 --- /dev/null +++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/dtl_query_result_service.kt @@ -0,0 +1,15 @@ +package com.supwisdom.dlpay.api.service + +import com.supwisdom.dlpay.api.domain.TDtlQuery +import org.springframework.transaction.annotation.Propagation +import org.springframework.transaction.annotation.Transactional + +interface DtlQueryResultService { + + @Transactional(propagation = Propagation.REQUIRED, rollbackFor = [Exception::class]) + fun saveOrUpdateDtlQuery(dtlQuery: TDtlQuery): TDtlQuery + + @Transactional(propagation = Propagation.REQUIRED, rollbackFor = [Exception::class], readOnly = true) + fun getNeedQueryRecords(accdate: String, maxCount:Int): List + +} \ No newline at end of file diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/dtl_query_result_service_impl.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/dtl_query_result_service_impl.kt new file mode 100644 index 00000000..a42427b5 --- /dev/null +++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/dtl_query_result_service_impl.kt @@ -0,0 +1,27 @@ +package com.supwisdom.dlpay.api.service.impl + +import com.supwisdom.dlpay.api.dao.DtlQueryDao +import com.supwisdom.dlpay.api.domain.TDtlQuery +import com.supwisdom.dlpay.api.service.DtlQueryResultService +import com.supwisdom.dlpay.framework.tenant.TenantContext +import com.supwisdom.dlpay.util.ConstantUtil +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Service + +@Service +class DtlQueryResultServiceImpl : DtlQueryResultService { + @Autowired + private lateinit var dtlQueryDao: DtlQueryDao + + override fun saveOrUpdateDtlQuery(dtlQuery: TDtlQuery): TDtlQuery { + if (null == dtlQuery.tenantId) { + dtlQuery.tenantId = TenantContext.getTenantSchema() + } + return dtlQueryDao.save(dtlQuery) + } + + override fun getNeedQueryRecords(accdate: String, maxCount: Int): List { + return dtlQueryDao.getNeedQueryDtls(accdate, ConstantUtil.QUERYTYPE_NEED_QUERY, maxCount) + ?: ArrayList(0) + } +} \ No newline at end of file diff --git a/payapi/src/main/resources/application.properties b/payapi/src/main/resources/application.properties index 17217f90..5ca4e24f 100644 --- a/payapi/src/main/resources/application.properties +++ b/payapi/src/main/resources/application.properties @@ -30,8 +30,9 @@ spring.http.encoding.enabled=true server.tomcat.uri-encoding=UTF-8 ################################################## ## quartz task scheduler -shopbalance.updater.cron=10/* * * * * +shopbalance.updater.cron=10/* * * * * ? dayend.settletask.cron=0 3/30 2-3 * * ? +query.third.transdtl.result.cron=7 0/3 * * * ? #dayend.settletask.cron = 0 0/2 * * * ? ################################################ # user password