清算确认任务
diff --git a/config/application-devel-pg-xkx.properties b/config/application-devel-pg-xkx.properties
index 16830f5..e03fe08 100644
--- a/config/application-devel-pg-xkx.properties
+++ b/config/application-devel-pg-xkx.properties
@@ -45,6 +45,7 @@
 #send.delay.notice.task.cron=29 0/1 * * * ?
 #points.outdate.cron=0 0 0 * * ?
 #points.consume.cron=0 0 0 * * ?
+citizencard.confirm.chkdtl.cron=*/30 * * * * ?
 #############################################
 spring.cloud.consul.enabled=false
 spring.cloud.consul.host=172.28.201.70
@@ -76,3 +77,4 @@
 # \u6307\u5B9A\u6D88\u606Fkey\u548C\u6D88\u606F\u4F53\u7684\u7F16\u89E3\u7801\u65B9\u5F0F
 spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer
 spring.kafka.consumer.value-deserializer=org.apache.kafka.common.serialization.StringDeserializer
+
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/api/dao/PersondtlDao.java b/payapi/src/main/java/com/supwisdom/dlpay/api/dao/PersondtlDao.java
index 3be4457..e91b882 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/api/dao/PersondtlDao.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/api/dao/PersondtlDao.java
@@ -2,7 +2,6 @@
 
 import com.supwisdom.dlpay.api.domain.TPersondtl;
 import com.supwisdom.dlpay.framework.data.CountAmountBean;
-import com.supwisdom.dlpay.framework.domain.TPointsdtl;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.Pageable;
 import org.springframework.data.jpa.repository.JpaRepository;
@@ -27,4 +26,8 @@
     List<TPersondtl> findAllByTransdateAndReverseFlagAndStatusAndTradeflag(String transdate,String reverseFlag,String status,String tradeflag);
 
     TPersondtl findTopByUseridAndStatusAndTradeflag(String userid, String status, String tradeFlag);
+
+    @Query(value = "select sum(case when t.amount<=0 then 1 else -1 end) as totalcnt,sum(-1*t.amount) as totalamt from TPersondtl t where t.status='success' and t.accdate=?1 and t.sourceType=?2 ")
+    CountAmountBean getChkClearSumInfo(String accdate, String sourcetype);
+
 }
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/citizencard/service/CitizencardManagerService.java b/payapi/src/main/java/com/supwisdom/dlpay/citizencard/service/CitizencardManagerService.java
index c799ee2..779e6dd 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/citizencard/service/CitizencardManagerService.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/citizencard/service/CitizencardManagerService.java
@@ -19,4 +19,7 @@
 
   @Transactional(rollbackFor = Exception.class)
   TCitizencardLossApply doFinishCitizencardLoss(TCitizencardLossApply lossApply);
+
+  @Transactional(rollbackFor = Exception.class)
+  boolean doConfirmCitizencardCheckProcess(String checkdate) throws Exception;
 }
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/citizencard/service/impl/CitizencardManagerServiceImpl.java b/payapi/src/main/java/com/supwisdom/dlpay/citizencard/service/impl/CitizencardManagerServiceImpl.java
index c628015..c19bc54 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/citizencard/service/impl/CitizencardManagerServiceImpl.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/citizencard/service/impl/CitizencardManagerServiceImpl.java
@@ -1,14 +1,26 @@
 package com.supwisdom.dlpay.citizencard.service.impl;
 
+import com.google.gson.Gson;
+import com.supwisdom.dlpay.agent.citizencard.DlpayResp;
+import com.supwisdom.dlpay.agent.citizencard.YnrccUtil;
+import com.supwisdom.dlpay.agent.service.CitizencardPayService;
 import com.supwisdom.dlpay.api.dao.CardDao;
+import com.supwisdom.dlpay.api.dao.PersondtlDao;
 import com.supwisdom.dlpay.api.domain.TCard;
 import com.supwisdom.dlpay.citizencard.dao.CitizencardLossApplyDao;
 import com.supwisdom.dlpay.citizencard.domain.TCitizencardLossApply;
 import com.supwisdom.dlpay.citizencard.service.CitizencardManagerService;
+import com.supwisdom.dlpay.framework.dao.BusinessparaDao;
+import com.supwisdom.dlpay.framework.data.CountAmountBean;
+import com.supwisdom.dlpay.framework.domain.TBusinesspara;
 import com.supwisdom.dlpay.framework.service.SystemUtilService;
+import com.supwisdom.dlpay.framework.util.DateUtil;
 import com.supwisdom.dlpay.framework.util.StringUtil;
 import com.supwisdom.dlpay.framework.util.TradeDict;
 import com.supwisdom.dlpay.util.ConstantUtil;
+import com.supwisdom.dlpay.util.WebCheckException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -22,8 +34,17 @@
   @Autowired
   private CardDao cardDao;
   @Autowired
+  private BusinessparaDao businessparaDao;
+  @Autowired
+  private PersondtlDao persondtlDao;
+
+  @Autowired
+  private CitizencardPayService citizencardPayService;
+  @Autowired
   private SystemUtilService systemUtilService;
 
+  private static final Logger logger = LoggerFactory.getLogger(CitizencardManagerServiceImpl.class);
+
   @Override
   public List<TCitizencardLossApply> getNewApplyCitizencardLossRecords() {
     List<TCitizencardLossApply> list = citizencardLossApplyDao.findCardlossApplyRecordsByStatus(ConstantUtil.CITIZENCARD_LOSSAPPLY_STATUS_APPLY);
@@ -58,4 +79,32 @@
     }
     return citizencardLossApplyDao.save(lossApply);
   }
+
+  @Override
+  public boolean doConfirmCitizencardCheckProcess(String checkdate) throws Exception {
+    TBusinesspara param = businessparaDao.findByParakeyForUpdate(ConstantUtil.BUSINESS_CITIZENCARD_CLEARDATE);
+    if (null == param || !DateUtil.checkDatetimeValid(param.getParaval(), "yyyyMMdd") || !DateUtil.checkDatetimeValid(checkdate, "yyyyMMdd")) {
+      throw new WebCheckException("确认清算参数错误!");
+    }
+    if (!checkdate.trim().equals(DateUtil.getNewDay(param.getParaval(), 1))) {
+      throw new WebCheckException("非连续清算确认!!! 上次清算确认日期【" + checkdate + "】,本次清算确认日期【" + checkdate + "】!");
+    }
+
+    CountAmountBean sumInfo = persondtlDao.getChkClearSumInfo(checkdate.trim(), TradeDict.PAYTYPE_CITIZEN_CARD);
+    if (null == sumInfo) throw new Exception("确认清算:统计本地流水信息异常!");
+    final int totalcnt = sumInfo.getTotalcnt() == null ? 0 : sumInfo.getTotalcnt().intValue();
+    final long totalamt = sumInfo.getTotalamt() == null ? 0 : Math.round(100 * sumInfo.getTotalamt());
+
+    logger.info("【" + checkdate + "】请求清算确认:jnlcount=[" + totalcnt + "],stlamt=[" + totalamt + "]");
+    DlpayResp resp = citizencardPayService.makeSureCheckResult(checkdate.trim(), totalcnt, totalamt);
+    if (YnrccUtil.CODE_SUCCESS.equals(resp.getCode())) {
+      logger.info("【" + checkdate + "】确认清算成功!");
+      param.setParaval(checkdate);
+      businessparaDao.save(param);
+      return true;
+    }
+
+    logger.error("【" + checkdate + "】确认清算失败:" + new Gson().toJson(resp));
+    throw new WebCheckException(resp.getMessage());
+  }
 }
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/citizencard/task/CitizencardCheckConfirmTask.java b/payapi/src/main/java/com/supwisdom/dlpay/citizencard/task/CitizencardCheckConfirmTask.java
new file mode 100644
index 0000000..3cb0417
--- /dev/null
+++ b/payapi/src/main/java/com/supwisdom/dlpay/citizencard/task/CitizencardCheckConfirmTask.java
@@ -0,0 +1,84 @@
+package com.supwisdom.dlpay.citizencard.task;
+
+import com.supwisdom.dlpay.api.domain.TSourceTypeCheckStatus;
+import com.supwisdom.dlpay.api.service.SourceTypeService;
+import com.supwisdom.dlpay.citizencard.service.CitizencardManagerService;
+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.Constants;
+import com.supwisdom.dlpay.framework.util.DateUtil;
+import com.supwisdom.dlpay.framework.util.TradeDict;
+import com.supwisdom.dlpay.util.ConstantUtil;
+import com.supwisdom.dlpay.util.WebCheckException;
+import net.javacrumbs.shedlock.core.SchedulerLock;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+/**
+ * 市民卡代扣对账成功后向银行确认任务
+ */
+@Component
+public class CitizencardCheckConfirmTask {
+  @Autowired
+  private CitizencardManagerService citizencardManagerService;
+  @Autowired
+  private SystemUtilService systemUtilService;
+  @Autowired
+  private SourceTypeService sourceTypeService;
+
+  private static final Logger logger = LoggerFactory.getLogger(CitizencardCheckConfirmTask.class);
+
+  @Scheduled(cron = "${citizencard.confirm.chkdtl.cron}")
+  @SchedulerLock(name = "CitizencardChkClearConfirmTask", lockAtMostForString = "PT10M")
+  public void doConfirmCitizenCardChkdtlTask() {
+    try { long t1 = System.currentTimeMillis();
+      if (null == TenantContext.getTenantSchema()) TenantContext.setTenantSchema(Constants.DEFAULT_TENANTID);
+
+      TBusinesspara businessParam = systemUtilService.getBusinessValueForUpdateNowait(ConstantUtil.BUSINESS_CITIZENCARD_CLEARDATE);
+      if (null == businessParam || !DateUtil.checkDatetimeValid(businessParam.getParaval(), "yyyyMMdd")) {
+        logger.error("市民卡代扣对账清算确认:未找到上次清算确认日期!");
+        return;
+      }
+
+      final String lastChkDate = businessParam.getParaval().trim(); //已确认清算的日期
+
+      TSourceTypeCheckStatus checkStatus = sourceTypeService.getSourceTypeCheckStatus(TradeDict.PAYTYPE_CITIZEN_CARD);
+      if (null == checkStatus) {
+        logger.error("市民卡代扣对账清算确认:未找到【市民卡代扣】对账状态!!!");
+        return;
+      }
+      final String canChkDate = checkStatus.getSettleStatus() ? checkStatus.getCheckAccdate() : DateUtil.getNewDay(checkStatus.getCheckAccdate(), -1);
+
+      long diffDays = DateUtil.getIntervalDay(lastChkDate, canChkDate);
+      if (diffDays > 0) logger.info("执行市民卡代扣对账清算确认任务开始:");
+
+      for (int i = 1; i <= diffDays; i++) {
+        final String clearDate = DateUtil.getNewDay(lastChkDate, i);
+        try {
+          citizencardManagerService.doConfirmCitizencardCheckProcess(clearDate);
+        } catch (WebCheckException be) {
+          logger.error("市民卡代扣对账清算确认【" + clearDate + "】失败! " + be.getMessage());
+          break;
+        } catch (Exception e) {
+          logger.error("市民卡代扣对账清算确认【" + clearDate + "】失败! " + e.getMessage());
+          e.printStackTrace();
+          break;
+        }
+      }
+
+      if (diffDays > 0) {
+        long t2 = System.currentTimeMillis();
+        logger.info("执行市民卡代扣对账清算确认结束,耗时 " + (t2 - t1) + " ms");
+      }
+
+    } catch (Exception ex) {
+      logger.error("执行市民卡代扣对账确认任务报错!");
+      ex.printStackTrace();
+    }
+  }
+}
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 4f6d410..8efd374 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/util/ConstantUtil.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/util/ConstantUtil.java
@@ -104,4 +104,6 @@
    * */
   public static final String KAFKA_MAGTYPE_NOTICE = "dlsmk_phone_notice";
   public static final String KAFKA_MAGTYPE_CONSUME = "dlsmk_card_consume";
+
+  public static final String BUSINESS_CITIZENCARD_CLEARDATE = "citizencard.check.clear.lastdate";
 }
diff --git a/payapi/src/main/resources/application.properties b/payapi/src/main/resources/application.properties
index 0881a1c..6e19153 100644
--- a/payapi/src/main/resources/application.properties
+++ b/payapi/src/main/resources/application.properties
@@ -1,9 +1,9 @@
-#######################################springboot配置 start#################################
+#######################################springboot\u914D\u7F6E start#################################
 spring.application.name=supwisdom.payapi
 spring.cloud.consul.discovery.health-check-path=${management.context-path}/api/common/version
 spring.cloud.consul.discovery.health-check-interval=10s
 spring.cloud.consul.discovery.instanceId=${spring.application.name}:${spring.application.instance_id:${random.value}}
-# 单库数据库配置
+# \u5355\u5E93\u6570\u636E\u5E93\u914D\u7F6E
 spring.jpa.show-sql=true
 spring.datasource.hikari.connection-timeout=60000
 spring.datasource.hikari.maximum-pool-size=5
@@ -23,7 +23,7 @@
 spring.thymeleaf.mode=HTML5
 spring.thymeleaf.cache=false
 spring.thymeleaf.enabled=true
-################## 全局字符编码设置 ######################
+################## \u5168\u5C40\u5B57\u7B26\u7F16\u7801\u8BBE\u7F6E ######################
 spring.http.encoding.force=true
 spring.http.encoding.charset=UTF-8
 spring.http.encoding.enabled=true
@@ -38,6 +38,7 @@
 send.delay.notice.task.cron=29 0/1 * * * ?
 points.outdate.cron=0 0 0 * * ?
 points.consume.cron=0 0 0 * * ?
+citizencard.confirm.chkdtl.cron=* */30 * * * ?
 ################################################
 # user password
 auth.password.bcrypt.length=10
diff --git a/payapi/src/main/resources/templates/system/param/busparaform.html b/payapi/src/main/resources/templates/system/param/busparaform.html
index 39dd9de..daccbb1 100644
--- a/payapi/src/main/resources/templates/system/param/busparaform.html
+++ b/payapi/src/main/resources/templates/system/param/busparaform.html
@@ -2,7 +2,7 @@
     <div class="layui-form-item">
         <label class="layui-form-label">参数名</label>
         <div class="layui-input-block">
-            <input name="parakey" placeholder="请输入参数名" type="text" class="layui-input" maxlength="30"
+            <input name="parakey" placeholder="请输入参数名" type="text" class="layui-input" maxlength="50"
                    lay-verify="required|businame" required/>
         </div>
     </div>