public static final String CODE_SUCCESS = "0000"; //成功
public static final String CODE_NOT_EXISTS = "0401"; //流水不存在
public static final String CODE_EXCEPTION = "10000"; //异常
+ public static final String NO_RECORDS_TODAY = "0406"; //当日无交易明细
//查询接口返回的流水状态
public static final String DTL_STATUS_SUCCESS = "0"; //成功
public static final int QUERY_MAX_COUNT = 3; //最大查询次数
+ public static final String YNRCC_BILLS_DOWNLOAD_LASTDATE = "ynrcc.download.bills.lastdate";
+
public static final List<Pair<AgentCode, YnrccRespCode>> errcode = new ArrayList<>(0);
static {
public interface DtlQueryDao extends JpaRepository<TDtlQuery, String> {
- @Query("from TDtlQuery t where t.accdate=?1 and t.status=?2 and t.qcnt<=?3 order by t.lastsaved desc ")
+ @Query("from TDtlQuery t where t.accdate=?1 and t.status=?2 and t.qcnt<=?3 order by t.lastsaved ")
List<TDtlQuery> getNeedQueryDtls(String accdate, String status, int maxQcnt);
}
@Query("select t from TTransactionMain t where t.outTradeNo=?1 and t.outId=?2")
TTransactionMain findByBillno(String billno, String outid);
+
+ @Query("select min(t.accdate) from TTransactionMain t where t.sourceType=?1 ")
+ String findMinAccdateBySourcetype(String sourcetype);
}
private static final Logger logger = LoggerFactory.getLogger(DayendSettleTask.class);
@Scheduled(cron = "${dayend.settletask.cron}")
- @SchedulerLock(name = "DayendSettleTask")
+ @SchedulerLock(name = "DayendSettleTask", lockAtMostForString = "PT30M")
public void doSettleTask() {
if (logger.isDebugEnabled()) logger.debug("进入日结算任务!");
settleLog = dayendSettleService.doCreateSettleLog(); //记录日志
}
@Scheduled(cron = "\${shopbalance.updater.cron:-}")
- @SchedulerLock(name = "dealShopUnupdatedDtl")
+ @SchedulerLock(name = "dealShopUnupdatedDtl", lockAtMostForString = "PT10M")
fun dealShopUnupdatedDtl() {
- shopaccService.findUnupdatedShopDtl(100).forEach {
- doShopBlanceUpdate(it)
+ try {
+ shopaccService.findUnupdatedShopDtl(100).forEach {
+ doShopBlanceUpdate(it)
+ }
+ } catch (ex: Exception) {
+ ex.printStackTrace()
}
}
}
private lateinit var applicationContext: ApplicationContext
@Scheduled(cron = "\${query.third.transdtl.result.cron:-}")
- @SchedulerLock(name = "DtlQueryResultSchedulerTask")
+ @SchedulerLock(name = "DtlQueryResultSchedulerTask", lockAtMostForString = "PT10M")
fun queryThirdTransdtlResult() {
- //仅查询当天数据,查询次数在规定次数之下
- dtlQueryResultService.getNeedQueryRecords(systemUtilService.accdate, ConstantUtil.QUERY_MAX_COUNT).forEach {
- try {
- doQuery(it)
- } catch (exp: Exception) {
- it.qcnt = it.qcnt + 1
- dtlQueryResultService.saveOrUpdateDtlQuery(it) //次数加一
+ try {
+ //仅查询当天数据,查询次数在规定次数之下
+ 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()
}
}
--- /dev/null
+package com.supwisdom.dlpay.api
+
+import com.supwisdom.dlpay.agent.citizencard.YnrccUtil
+import com.supwisdom.dlpay.agent.service.CitizencardPayService
+import com.supwisdom.dlpay.api.service.YnrccBusinessService
+import com.supwisdom.dlpay.framework.service.SystemUtilService
+import com.supwisdom.dlpay.framework.util.DateUtil
+import mu.KotlinLogging
+import net.javacrumbs.shedlock.core.SchedulerLock
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.scheduling.annotation.Scheduled
+import org.springframework.stereotype.Component
+
+/**
+ * 第三方对账任务
+ * */
+@Component
+class DownloadYnrccChkfileTask {
+ @Autowired
+ private lateinit var systemUtilService: SystemUtilService
+ @Autowired
+ private lateinit var ynrccBusinessService: YnrccBusinessService
+ @Autowired
+ private lateinit var citizencardPayService: CitizencardPayService
+
+ private val logger = KotlinLogging.logger { }
+
+
+ @Scheduled(cron = "\${download.ynrcc.chkfile.cron:-}")
+ @SchedulerLock(name = "DownloadYnrccChkfileSchedulerTask", lockAtMostForString = "PT10M")
+ fun doDownloadYnrccChkfile() {
+ try {
+ //下载对账单逻辑
+ val hostdate = systemUtilService.sysdatetime.hostdate
+ val downloadLastdate = ynrccBusinessService.getLastDownloadBillDate()
+ val diffDays = DateUtil.getIntervalDay(downloadLastdate, hostdate).toInt()
+ logger.info("大理农商行对账单下载:downloadLastdate=$downloadLastdate, hostdate=$hostdate, diffDays=$diffDays ")
+
+ for (i in 1 until diffDays) {
+ val billDate = DateUtil.getNewDay(downloadLastdate, i) //要取对账单的日期
+
+ val resp = citizencardPayService.getChkfilename(billDate, null)
+ if (YnrccUtil.CODE_SUCCESS == resp.code) {
+ val chkfilename = resp.filename
+ //根据filename 取文件数据
+
+
+ } else if (YnrccUtil.NO_RECORDS_TODAY == resp.code) {
+ //当日无交易明细,也创建空记录
+
+ } else {
+ //报错,退出对账单拉取
+ logger.error("大理农商行对账单下载[$billDate]报错:${resp.message}")
+ break
+ }
+ }
+
+ } catch (ex: Exception) {
+ ex.printStackTrace()
+ }
+ }
+
+}
\ No newline at end of file
--- /dev/null
+package com.supwisdom.dlpay.api.service.impl
+
+import com.supwisdom.dlpay.agent.citizencard.YnrccUtil
+import com.supwisdom.dlpay.api.dao.TransactionMainDao
+import com.supwisdom.dlpay.api.service.YnrccBusinessService
+import com.supwisdom.dlpay.framework.dao.BusinessparaDao
+import com.supwisdom.dlpay.framework.domain.TBusinesspara
+import com.supwisdom.dlpay.framework.service.SystemUtilService
+import com.supwisdom.dlpay.framework.tenant.TenantContext
+import com.supwisdom.dlpay.framework.util.DateUtil
+import com.supwisdom.dlpay.framework.util.TradeDict
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.stereotype.Service
+
+@Service
+class YnrccBusinessServiceImpl : YnrccBusinessService {
+ @Autowired
+ private lateinit var businessparaDao: BusinessparaDao
+ @Autowired
+ private lateinit var systemUtilService: SystemUtilService
+ @Autowired
+ private lateinit var transactionMainDao: TransactionMainDao
+
+
+ override fun getLastDownloadBillDate(): String {
+ var businesspara = businessparaDao.findByParakeyForUpdate(YnrccUtil.YNRCC_BILLS_DOWNLOAD_LASTDATE)
+ if (null != businesspara && DateUtil.checkDatetimeValid(businesspara.paraval, DateUtil.DATE_FMT)) {
+ return businesspara.paraval
+ }
+ val startdate = transactionMainDao.findMinAccdateBySourcetype(TradeDict.PAYTYPE_CITIZEN_CARD)
+ ?: systemUtilService.sysdatetime.hostdate
+
+ if (null != businesspara) {
+ businesspara.paraval = DateUtil.getNewDay(startdate, -1)
+ } else {
+ businesspara = TBusinesspara().apply {
+ this.parakey = YnrccUtil.YNRCC_BILLS_DOWNLOAD_LASTDATE
+ this.paraval = DateUtil.getNewDay(startdate, -1)
+ this.tenantId = TenantContext.getTenantSchema()
+ }
+ }
+ businesspara = businessparaDao.save(businesspara)
+ return businesspara.paraval
+ }
+
+}
\ No newline at end of file
--- /dev/null
+package com.supwisdom.dlpay.api.service
+
+import org.springframework.transaction.annotation.Transactional
+
+interface YnrccBusinessService {
+ @Transactional(rollbackFor = [Exception::class])
+ fun getLastDownloadBillDate(): String
+
+}
\ No newline at end of file
shopbalance.updater.cron=10/* * * * * ?
dayend.settletask.cron=0 3/30 2-3 * * ?
query.third.transdtl.result.cron=7 0/3 * * * ?
+download.ynrcc.chkfile.cron =3 0/10 1 * * ?
#dayend.settletask.cron = 0 0/2 * * * ?
################################################
# user password
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'
+ implementation 'commons-net:commons-net:3.6'
implementation project(':payapi-common')
fileHeader.setPayCount(fileHeader.getPayCount() - 1);
fileHeader.setPayAmount(fileHeader.getPayAmount() - record.getAmount());
} else if (FLAG_REFUND.equals(record.getFlag())) {
- amount = +record.getAmount();
+ amount = -record.getAmount();
flag = Constant.FLAG_REFUND;
fileHeader.setRefundCount(fileHeader.getRefundCount() - 1);
fileHeader.setRefundAmount(fileHeader.getRefundAmount() - record.getAmount());
}
@GetMapping("/download")
- public void downloadFile(@RequestParam("file") String file, HttpServletResponse response) throws IOException {
+ public void downloadFile(@RequestParam("filename") String filename, HttpServletResponse response) throws IOException {
try {
- parseFile(file, response.getOutputStream());
+ String loaclfile = ynrccApiService.getChkfilePath(filename);
+ parseFile(loaclfile, response.getOutputStream());
} catch (Exception e) {
e.printStackTrace();
response.sendError(HttpStatus.SERVICE_UNAVAILABLE.value(), e.getMessage());
public interface YnrccApiService {
DlpayResp sendToYnrcc(String optype, DlpayReq req) throws Exception;
+
+ String getChkfilePath(String filename) throws Exception;
}
import com.supwisdom.agent.api.bean.DlpayResp;
import com.supwisdom.agent.api.service.YnrccApiService;
import com.supwisdom.agent.config.YnrccSocketConfig;
+import org.apache.commons.net.ftp.FTP;
+import org.apache.commons.net.ftp.FTPClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
+import java.io.*;
+
@Service
public class YnrccApiServiceImpl implements YnrccApiService {
@Autowired
}
}
+ @Override
+ public String getChkfilePath(String filename) throws Exception {
+ //本地服务器上
+ if (!ynrccSocketConfig.getChkfileIsftp()) {
+ String localFilePath = ynrccSocketConfig.getChkfilePath();
+ if (localFilePath.endsWith("/")) {
+ return localFilePath + filename;
+ } else {
+ return localFilePath + "/" + filename;
+ }
+ }
+
+ //ftp取对账文件
+ String ftpIp = ynrccSocketConfig.getFtpIp();
+ Integer ftpPort = ynrccSocketConfig.getFtpPort();
+ String ftpUsername = ynrccSocketConfig.getFtpUsername();
+ String ftpUserpwd = ynrccSocketConfig.getFtpPassword();
+ String targetPath = ynrccSocketConfig.getFtpTargetPath();
+ String localFilePath = ynrccSocketConfig.getChkfilePath();
+ if (StringUtil.isEmpty(ftpIp) || null == ftpPort || StringUtil.isEmpty(ftpUsername) || StringUtil.isEmpty(ftpUserpwd) || StringUtil.isEmpty(targetPath)) {
+ throw new Exception("ftp参数未配置");
+ }
+
+ FTPClient ftpClient = new FTPClient();
+ try {
+ ftpClient.connect(ftpIp, ftpPort);
+ ftpClient.login(ftpUsername, ftpUserpwd);
+ ftpClient.enterLocalPassiveMode();
+ ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
+
+ String savePath = localFilePath.endsWith("/") ? (localFilePath + filename) : (localFilePath + "/" + filename);
+ String targetFile = targetPath.endsWith("/") ? (targetPath + filename) : (targetPath + "/" + filename);
+ //本地文件
+ File localFile = new File(savePath);
+ File parentDir = localFile.getParentFile();
+ if (!parentDir.exists()) {
+ parentDir.mkdir();
+ }
+
+ OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(localFile));
+ boolean success = ftpClient.retrieveFile(targetFile, outputStream);
+ outputStream.close();
+
+ if (success) {
+ return savePath;
+ }
+ } catch (IOException ex) {
+ ex.printStackTrace();
+ }
+
+ throw new Exception("获取对账文件失败!");
+ }
+
}
public class YnrccSocketConfig {
@Value("${ynrcc.socket.ip}")
private String ip;
+
@Value("${ynrcc.socket.port}")
private Integer port;
+
@Value("${ynrcc.socket.timeout}")
private int timeout = 10;
+
@Value("${ynrcc.md5.key}")
private String md5Key;
+ @Value("${ynrcc.chkfile.ftp.enabled}")
+ private Boolean chkfileIsftp;
+
+ @Value("${ynrcc.chkfile.ftp.ip}")
+ private String ftpIp;
+
+ @Value("${ynrcc.chkfile.ftp.port}")
+ private Integer ftpPort;
+
+ @Value("${ynrcc.chkfile.local.path}")
+ private String chkfilePath;
+
+ @Value("${ynrcc.chkfile.ftp.username}")
+ private String ftpUsername;
+
+ @Value("${ynrcc.chkfile.ftp.userpwd}")
+ private String ftpPassword;
+
+ @Value("${ynrcc.chkfile.ftp.targetpath}")
+ private String ftpTargetPath;
+
public String getIp() {
return ip;
}
public String getMd5Key() {
return md5Key;
}
+
+ public Boolean getChkfileIsftp() {
+ return chkfileIsftp;
+ }
+
+ public String getFtpIp() {
+ return ftpIp;
+ }
+
+ public Integer getFtpPort() {
+ return ftpPort;
+ }
+
+ public String getChkfilePath() {
+ return chkfilePath;
+ }
+
+ public String getFtpUsername() {
+ return ftpUsername;
+ }
+
+ public String getFtpPassword() {
+ return ftpPassword;
+ }
+
+ public String getFtpTargetPath() {
+ return ftpTargetPath;
+ }
}
#spring.redis.port=16379
#spring.redis.password=kingstar
#spring.redis.database=0
-
# logging
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n
logging.level.org.hibernate.SQL=debug
##################################################
## quartz task scheduler
#dayend.settletask.cron = 0 0/2 * * * ?
-
############# YNRCC SOCKET ###############
ynrcc.socket.ip=127.0.0.1
ynrcc.socket.port=8089
## 超时时间(分钟)
-ynrcc.socket.timeout = 10
+ynrcc.socket.timeout=10
ynrcc.md5.key=80816b7947ed016bff8079557735006e
+ynrcc.chkfile.ftp.enabled=false
+ynrcc.chkfile.local.path=/opt/supwisdom/chkfile
+ynrcc.chkfile.ftp.ip=
+ynrcc.chkfile.ftp.port=
+ynrcc.chkfile.ftp.username=
+ynrcc.chkfile.ftp.userpwd=
+ynrcc.chkfile.ftp.targetpath=/
+
+