修改商户更新逻辑,改进业务模式
diff --git a/src/main/java/com/supwisdom/dlpay/api/dao/ShopdtlDao.java b/src/main/java/com/supwisdom/dlpay/api/dao/ShopdtlDao.java
index d8dda28..611d3cb 100644
--- a/src/main/java/com/supwisdom/dlpay/api/dao/ShopdtlDao.java
+++ b/src/main/java/com/supwisdom/dlpay/api/dao/ShopdtlDao.java
@@ -3,8 +3,13 @@
 import com.supwisdom.dlpay.api.domain.TShopdtl;
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Lock;
 import org.springframework.stereotype.Repository;
 
+import javax.persistence.LockModeType;
+
 @Repository
-public interface ShopdtlDao extends JpaRepository<TShopdtl, String>,JpaSpecificationExecutor<TShopdtl> {
+public interface ShopdtlDao extends JpaRepository<TShopdtl, String>, JpaSpecificationExecutor<TShopdtl> {
+  @Lock(LockModeType.OPTIMISTIC)
+  TShopdtl findTShopdtlByRefno(String refno);
 }
diff --git a/src/main/java/com/supwisdom/dlpay/api/domain/TAccount.java b/src/main/java/com/supwisdom/dlpay/api/domain/TAccount.java
index b7dac86..2a89feb 100644
--- a/src/main/java/com/supwisdom/dlpay/api/domain/TAccount.java
+++ b/src/main/java/com/supwisdom/dlpay/api/domain/TAccount.java
@@ -2,12 +2,11 @@
 
 import com.supwisdom.dlpay.framework.util.MD5;
 import com.supwisdom.dlpay.framework.util.MoneyUtil;
-import com.supwisdom.dlpay.system.common.DictPool;
 import org.hibernate.annotations.GenericGenerator;
-import org.springframework.beans.factory.annotation.Autowired;
 
 import javax.persistence.*;
 import java.io.Serializable;
+import java.sql.Timestamp;
 
 @Entity
 @Table(name = "TB_ACCOUNT",
@@ -54,8 +53,8 @@
   @Column(name = "MAX_BAL", precision = 15, scale = 2)
   private Double maxbal; // 最大余额限制
 
-  @Column(name = "LAST_TRANSDATE", length = 8)
-  private String lasttransdate; //最后交易日期
+  @Column(name = "LAST_TRANSTIME", length = 8)
+  private Timestamp lasttranstime; //最后交易日期
 
   @Column(name = "LASTDAY_TRANSAMT", precision = 9, scale = 2)
   private Double lastdayTransamt; //最后一天消费金额
@@ -72,10 +71,6 @@
   @Column(name = "CLOSEDATE", length = 8)
   private String closedate;
 
-  @Version
-  @Column(name = "optlock", columnDefinition = "integer DEFAULT 0", nullable = false)
-  private Long version;
-
   @OneToOne
   @JoinColumn(name = "USERID", insertable = false, updatable = false)
   private TPerson person;
@@ -83,7 +78,7 @@
   public TAccount() {
   }
 
-  public TAccount(String accname, String subjno, String userid, String status, Double balance, Double availbal, Double frozebal, Boolean lowfreeFlag, Double lowfreeLimit, Double daylimit, Double maxbal, String lasttransdate, Double lastdayTransamt, Double lastdayDpsamt, String tac, String opendate, String closedate) {
+  public TAccount(String accname, String subjno, String userid, String status, Double balance, Double availbal, Double frozebal, Boolean lowfreeFlag, Double lowfreeLimit, Double daylimit, Double maxbal, Timestamp lasttranstime, Double lastdayTransamt, Double lastdayDpsamt, String tac, String opendate, String closedate) {
     this.accname = accname;
     this.subjno = subjno;
     this.userid = userid;
@@ -95,7 +90,7 @@
     this.lowfreeLimit = lowfreeLimit;
     this.daylimit = daylimit;
     this.maxbal = maxbal;
-    this.lasttransdate = lasttransdate;
+    this.lasttranstime = lasttranstime;
     this.lastdayTransamt = lastdayTransamt;
     this.lastdayDpsamt = lastdayDpsamt;
     this.tac = tac;
@@ -199,12 +194,12 @@
     this.maxbal = maxbal;
   }
 
-  public String getLasttransdate() {
-    return lasttransdate;
+  public Timestamp getLasttranstime() {
+    return lasttranstime;
   }
 
-  public void setLasttransdate(String lasttransdate) {
-    this.lasttransdate = lasttransdate;
+  public void setLasttranstime(Timestamp lasttranstime) {
+    this.lasttranstime = lasttranstime;
   }
 
   public Double getLastdayTransamt() {
@@ -297,11 +292,4 @@
     this.person = person;
   }
 
-  public Long getVersion() {
-    return version;
-  }
-
-  public void setVersion(Long version) {
-    this.version = version;
-  }
 }
diff --git a/src/main/java/com/supwisdom/dlpay/api/domain/TShopdtl.java b/src/main/java/com/supwisdom/dlpay/api/domain/TShopdtl.java
index 76f97a4..aeae783 100644
--- a/src/main/java/com/supwisdom/dlpay/api/domain/TShopdtl.java
+++ b/src/main/java/com/supwisdom/dlpay/api/domain/TShopdtl.java
@@ -6,7 +6,8 @@
 @Table(name = "TB_SHOPDTL",
     indexes = {@Index(name = "shopdtl_accdate", columnList = "accdate"),
         @Index(name = "shopdtl_shopaccno", columnList = "shopaccno"),
-        @Index(name = "shopdtl_transdate", columnList = "transdate")})
+        @Index(name = "shopdtl_transdate", columnList = "transdate"),
+        @Index(name = "shopdtl_updateflag", columnList = "updatebala")})
 public class TShopdtl {
   @Id
   @Column(name = "REFNO", length = 32, nullable = false)
@@ -51,6 +52,9 @@
   @Column(name = "STATUS", length = 20)
   private String status;
 
+  @Column(name = "updatebala")
+  private Boolean updateBala;
+
   @Column(name = "OPPOSITEACCNO", length = 64)
   private String oppositeAccNo;
 
@@ -195,4 +199,12 @@
   public void setRemark(String remark) {
     this.remark = remark;
   }
+
+  public Boolean getUpdateBala() {
+    return updateBala;
+  }
+
+  public void setUpdateBala(Boolean updateBala) {
+    this.updateBala = updateBala;
+  }
 }
diff --git a/src/main/java/com/supwisdom/dlpay/framework/util/DateUtil.java b/src/main/java/com/supwisdom/dlpay/framework/util/DateUtil.java
index 3a7e013..fd18771 100644
--- a/src/main/java/com/supwisdom/dlpay/framework/util/DateUtil.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/util/DateUtil.java
@@ -3,6 +3,7 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.sql.Timestamp;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.Calendar;
@@ -324,4 +325,21 @@
   public static String getUTCTime() {
     return getUTCTime(System.currentTimeMillis());
   }
+
+  public static int compareDay(Timestamp d1, Timestamp d2) {
+    Calendar cd1 = Calendar.getInstance();
+    cd1.setTimeInMillis(d1.getTime());
+    Calendar cd2 = Calendar.getInstance();
+    cd2.setTimeInMillis(d2.getTime());
+
+    if (cd1.get(Calendar.YEAR) != cd2.get(Calendar.YEAR)) {
+      return cd1.compareTo(cd2);
+    }
+
+    return Integer.compare(cd1.get(Calendar.DAY_OF_YEAR), cd2.get(Calendar.DAY_OF_YEAR));
+  }
+
+  public static Boolean sameDay(Timestamp d1, Timestamp d2) {
+    return (compareDay(d1, d2) == 0);
+  }
 }
diff --git a/src/main/java/com/supwisdom/dlpay/system/service/impl/UserDataServiceImpl.java b/src/main/java/com/supwisdom/dlpay/system/service/impl/UserDataServiceImpl.java
index 54694f5..06def11 100644
--- a/src/main/java/com/supwisdom/dlpay/system/service/impl/UserDataServiceImpl.java
+++ b/src/main/java/com/supwisdom/dlpay/system/service/impl/UserDataServiceImpl.java
@@ -110,7 +110,6 @@
             account.setFrozebal(0.0);
             account.setLowfreeFlag(false);
             account.setMaxbal(systemUtilService.getSysparaValueAsDouble(SysparaUtil.SYSPARAID_NO1, SysparaUtil.SYSPARA_NO1_DEFAULT));
-            account.setLasttransdate(systemDateTime.getHostdate());
             account.setLastdayDpsamt(0.0);
             account.setLastdayTransamt(0.0);
             account.setOpendate(systemDateTime.getHostdate());
diff --git a/src/main/kotlin/com/supwisdom/dlpay/account_process_async.kt b/src/main/kotlin/com/supwisdom/dlpay/account_process_async.kt
new file mode 100644
index 0000000..a1bd2f0
--- /dev/null
+++ b/src/main/kotlin/com/supwisdom/dlpay/account_process_async.kt
@@ -0,0 +1,70 @@
+package com.supwisdom.dlpay
+
+import com.supwisdom.dlpay.api.dao.ShopdtlDao
+import com.supwisdom.dlpay.api.dao.TransactionMainDao
+import com.supwisdom.dlpay.api.repositories.ShopaccService
+import mu.KotlinLogging
+import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.context.annotation.Bean
+import org.springframework.context.annotation.Configuration
+import org.springframework.scheduling.annotation.Async
+import org.springframework.scheduling.annotation.AsyncConfigurer
+import org.springframework.scheduling.annotation.EnableAsync
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
+import org.springframework.stereotype.Component
+import java.lang.reflect.Method
+import java.util.concurrent.Executor
+
+@Configuration
+@EnableAsync
+class SpringAsyncConfig : AsyncConfigurer {
+    @Bean("shopAccBalanceUpdater")
+    fun threadPoolExecutor(): Executor {
+        return ThreadPoolTaskExecutor().apply {
+            corePoolSize = 10
+            maxPoolSize = 30
+            setWaitForTasksToCompleteOnShutdown(true)
+        }
+    }
+
+    override fun getAsyncUncaughtExceptionHandler(): AsyncUncaughtExceptionHandler? {
+        return MyAsyncUncaughtExceptionHandler()
+    }
+}
+
+class MyAsyncUncaughtExceptionHandler : AsyncUncaughtExceptionHandler {
+    private val logger = KotlinLogging.logger { }
+    override fun handleUncaughtException(ex: Throwable, method: Method, vararg params: Any?) {
+        logger.error { "Async Task execute error: <${method.name}>, exception <${ex.message}>" }
+    }
+}
+
+
+@Component
+class ShopAccBalanceAsyncTask {
+    private val logger = KotlinLogging.logger { }
+
+    @Autowired
+    private lateinit var transactionMainDao: TransactionMainDao
+
+    @Autowired
+    lateinit var shopdltDao: ShopdtlDao
+
+    @Autowired
+    private lateinit var shopaccService: ShopaccService
+
+    @Async("shopAccBalanceUpdater")
+    fun updateShopBalance(shopdtlRefno: String) {
+        shopdltDao.findTShopdtlByRefno(shopdtlRefno)?.also {
+            if (it.updateBala) {
+                logger.warn { "shop balance update refno <$shopdtlRefno> has been updated" }
+                return
+            }
+        }?.also {
+            shopaccService.recalcShopBalance(it, it.amount, true)
+            it.updateBala = true
+            shopdltDao.save(it)
+        } ?: logger.warn { "shop balance updater refno<$shopdtlRefno> not found" }
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/supwisdom/dlpay/api/controller/shop_api_controller.kt b/src/main/kotlin/com/supwisdom/dlpay/api/controller/shop_api_controller.kt
index d7f333b..ef9b194 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/api/controller/shop_api_controller.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/api/controller/shop_api_controller.kt
@@ -44,9 +44,6 @@
                         .data("shopaccno", it.shopaccno ?: "")
                         .success("注册成功"))
             }
-
-            return ResponseEntity.ok(ResponseBodyBuilder.create()
-                    .fail(TradeErrorCode.BUSINESS_DEAL_ERROR, "商户注册失败"))
         } catch (ex: RequestParamCheckException) {
             return ResponseEntity.ok(ResponseBodyBuilder.create()
                     .requestException(ex, "请求参数错误"))
diff --git a/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/account_service_impl.kt b/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/account_service_impl.kt
index 9622f61..b7b4604 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/account_service_impl.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/account_service_impl.kt
@@ -6,6 +6,8 @@
 import com.supwisdom.dlpay.exception.TransactionProcessException
 import com.supwisdom.dlpay.framework.domain.TShopacc
 import com.supwisdom.dlpay.framework.service.SystemUtilService
+import com.supwisdom.dlpay.framework.util.DateUtil
+import com.supwisdom.dlpay.framework.util.TradeDict
 import com.supwisdom.dlpay.framework.util.TradeErrorCode
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.stereotype.Repository
@@ -58,14 +60,25 @@
                     doRecalcAccountBalance(dtl, account)
                     account.availbal += dtl.amount
                     account.balance += dtl.amount
-                    account.lasttransdate = dtl.accdate
+
+                    val sameDay = DateUtil.sameDay(account.lasttranstime,
+                            systemUtilServcie.sysdatetime.currentTimestamp) ?: false
+
+                    if (!sameDay) {
+                        account.lastdayTransamt = 0.0
+                        account.lastdayDpsamt = 0.0
+                    }
+                    if (dtl.tradeflag == TradeDict.TRADE_FLAG_OUT) {
+                        account.lastdayTransamt += amount
+                    } else {
+                        account.lastdayDpsamt += amount
+                    }
                     try {
                         entityManager.persist(account)
                     } catch (ex: OptimisticLockException) {
                         throw TransactionProcessException(TradeErrorCode.ACCOUNT_TRADE_BUSY,
                                 "个人账户被被更新")
                     }
-
                 } ?: throw TransactionProcessException(TradeErrorCode.BUSINESS_DEAL_ERROR,
                 "交易流水<${dtl.refno}>未找到指定个人账户")
     }
diff --git a/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/transaction_service_impl.kt b/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/transaction_service_impl.kt
index ab253c0..17b45f0 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/transaction_service_impl.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/transaction_service_impl.kt
@@ -1,5 +1,6 @@
 package com.supwisdom.dlpay.api.service.impl
 
+import com.supwisdom.dlpay.ShopAccBalanceAsyncTask
 import com.supwisdom.dlpay.api.TransactionBuilder
 import com.supwisdom.dlpay.api.dao.PersondtlDao
 import com.supwisdom.dlpay.api.dao.TransactionMainDao
@@ -46,6 +47,9 @@
     @Autowired
     private lateinit var sourceTypeService: SourceTypeService
 
+    @Autowired
+    private lateinit var shopAccBalanceAsyncTask: ShopAccBalanceAsyncTask
+
     private fun preCheck(builder: TransactionBuilder) {
         builder.preCheck()
 
@@ -384,10 +388,11 @@
                     transaction.shopDtl.shopaccno, Subject.SUBJNO_MACHANT_INCOME,
                     SHOP_BALANCE_FLAG, "both")
             if (amount.compareTo(0.0) != 0) {
-                transaction.shopDtl?.let {
-                    shopaccService.recalcShopBalance(it, it.amount, overdraft)
-                } ?: throw TransactionProcessException(TradeErrorCode.TRANSACTION_NOT_EXISTS,
-                        "商户流水<${transaction.refno}>不存在")
+//                transaction.shopDtl?.let {
+//                    shopaccService.recalcShopBalance(it, amount, overdraft)
+//                } ?: throw TransactionProcessException(TradeErrorCode.TRANSACTION_NOT_EXISTS,
+//                        "商户流水<${transaction.refno}>不存在")
+//                shopAccBalanceAsyncTask.updateShopBalance(transaction.shopDtl.refno)
             }
             transaction.shopDtl.status = TradeDict.DTL_STATUS_SUCCESS
             transaction.shopDtl.accdate = transaction.accdate
diff --git a/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/user_service_impl.kt b/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/user_service_impl.kt
index 91fef26..1049c26 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/user_service_impl.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/user_service_impl.kt
@@ -69,7 +69,7 @@
                 lowfreeLimit = lowfreeLimit
                 daylimit = daylimit
                 maxbal = systemUtilService.getSysparaValueAsDouble(SysparaUtil.SYSPARAID_NO1, SysparaUtil.SYSPARA_NO1_DEFAULT)
-                lasttransdate = systemdatetime.hostdate
+                lasttranstime = systemdatetime.currentTimestamp
                 lastdayTransamt = 0.0
                 lastdayDpsamt = 0.0
                 opendate = systemdatetime.hostdate
diff --git a/src/main/resources/templates/system/user/account.html b/src/main/resources/templates/system/user/account.html
index 2475cf9..db0e644 100644
--- a/src/main/resources/templates/system/user/account.html
+++ b/src/main/resources/templates/system/user/account.html
@@ -51,7 +51,7 @@
                     {field: 'availbal', title: '可用余额', width: 100,fixed: 'left', sort: true},
                     {field: 'balance', title: '总余额', width: 100,fixed: 'left', sort: true},
                     {field: 'frozebal', title: '冻结余额', width: 100,fixed: 'left', sort: true},
-                    {field: 'lasttransdate', title: '最后交易日期', width: 120,fixed: 'left', sort: true},
+                    {field: 'lasttranstime', title: '最后交易日期', width: 120,fixed: 'left', sort: true},
                     {field: 'opendate', title: '开户日期', width: 100,fixed: 'left', sort: true},
                     {
                         field: 'accno', align: 'center', title: '操作', fixed: 'right', templet: function (item) {