增加了异步扣费及定时任务扣费功能
diff --git a/build.gradle b/build.gradle
index a2789f4..7c8ec76 100644
--- a/build.gradle
+++ b/build.gradle
@@ -85,20 +85,22 @@
     implementation group: 'com.sun.jersey', name: 'jersey-client', version: '1.19'
     implementation group: 'javax.servlet', name: 'jstl', version: '1.2'
     implementation group: 'taglibs', name: 'standard', version: '1.1.2'
-    implementation group: 'commons-codec', name: 'commons-codec', version: '1.6'
+    implementation group: 'commons-codec', name: 'commons-codec', version: '1.13'
+    implementation 'net.javacrumbs.shedlock:shedlock-spring:2.5.0'
+    implementation 'net.javacrumbs.shedlock:shedlock-provider-redis-spring:2.5.0'
     implementation files('libs/ojdbc6.jar')
 
     annotationProcessor 'org.projectlombok:lombok:1.18.8'
     compileOnly 'org.projectlombok:lombok:1.18.8'
     annotationProcessor "org.springframework.boot:spring-boot-configuration-processor"
     
-    compile 'com.supwisdom:payapi-sdk:b5eceda'
+    compile 'com.supwisdom:payapi-sdk:a315360'
     
 //    providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
     testImplementation 'org.springframework.boot:spring-boot-starter-test'
     testImplementation 'io.rest-assured:rest-assured:3.3.0'
     testImplementation 'io.rest-assured:spring-mock-mvc:3.3.0'
-    testImplementation 'org.hamcrest:hamcrest:2.1'
+    implementation 'org.hamcrest:hamcrest:2.1'
 }
 
 compileKotlin {
diff --git a/src/main/java/com/supwisdom/dlpay/api/domain/TPersonIdentity.java b/src/main/java/com/supwisdom/dlpay/api/domain/TPersonIdentity.java
index f1e89d7..b61b293 100644
--- a/src/main/java/com/supwisdom/dlpay/api/domain/TPersonIdentity.java
+++ b/src/main/java/com/supwisdom/dlpay/api/domain/TPersonIdentity.java
@@ -31,10 +31,32 @@
   @Column(name = "CREATETIME", length = 14)
   private String createtime;
 
+  @Column(name = "COAMOUNT",precision = 10, scale = 2)
+  private Double coamount;
+
+  @Column(name = "ACCAMOUNT",precision = 10, scale = 2)
+  private Double accamount;
+
+  public Double getCoamount() {
+    return coamount;
+  }
+
+  public void setCoamount(Double coamount) {
+    this.coamount = coamount;
+  }
+
+  public Double getAccamount() {
+    return accamount;
+  }
+
+  public void setAccamount(Double accamount) {
+    this.accamount = accamount;
+  }
+
   public TPersonIdentity() {
   }
 
-  public TPersonIdentity(String thirdUid, TPerson person, String status, Integer lossflag, Integer lockflag, String createtime,String cardphyId) {
+  public TPersonIdentity(String thirdUid, TPerson person, String status, Integer lossflag, Integer lockflag, String createtime,String cardphyId,Double coamount,Double accamount) {
     this.thirdUid = thirdUid;
     this.person = person;
     this.status = status;
@@ -42,6 +64,8 @@
     this.lockflag = lockflag;
     this.createtime = createtime;
     this.cardphyId = cardphyId;
+    this.coamount = coamount;
+    this.accamount = accamount;
   }
 
   public String getCardphyId() {
diff --git a/src/main/java/com/supwisdom/dlpay/framework/util/Constants.java b/src/main/java/com/supwisdom/dlpay/framework/util/Constants.java
index 17dd6bc..25cecd0 100644
--- a/src/main/java/com/supwisdom/dlpay/framework/util/Constants.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/util/Constants.java
@@ -8,4 +8,5 @@
   public static final String JWT_CLAIM_TENANTID = "tenantId";
   public static final String JWT_CLAIM_UID = "uid";
   public static final String JWT_CLAIM_AUTHORITIES = "authorities";
+  public static final String DTLTYPE_WATER = "water";
 }
diff --git a/src/main/java/com/supwisdom/dlpay/framework/util/Dictionary.java b/src/main/java/com/supwisdom/dlpay/framework/util/Dictionary.java
index 46377e9..6566a76 100644
--- a/src/main/java/com/supwisdom/dlpay/framework/util/Dictionary.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/util/Dictionary.java
@@ -7,6 +7,7 @@
   public static final String IDTYPE = "idtypeList";
   public static final String SEX = "sexList";
   public static final String ACCOUNT_STATUS = "accountStatusList";
+  public final static String WATER_DEVICE_STATUS = "device_status";
 
   /////////////////////////////////////
   public static final String SOURCE_TYPE = "sourcetypeList";
diff --git a/src/main/java/com/supwisdom/dlpay/framework/util/TradeErrorCode.java b/src/main/java/com/supwisdom/dlpay/framework/util/TradeErrorCode.java
index 3740b9a..b554784 100644
--- a/src/main/java/com/supwisdom/dlpay/framework/util/TradeErrorCode.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/util/TradeErrorCode.java
@@ -134,4 +134,6 @@
 
   public static final int REQUEST_PARAM_EEROR = 300003; //请求参数错误
 
+  public static final int WAIT_QUERY_RESULT = 55555; //查询结果
+
 }
diff --git a/src/main/java/com/supwisdom/dlpay/framework/util/WaterBudinessConstants.java b/src/main/java/com/supwisdom/dlpay/framework/util/WaterBudinessConstants.java
index 1f24d3d..c7aa81c 100644
--- a/src/main/java/com/supwisdom/dlpay/framework/util/WaterBudinessConstants.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/util/WaterBudinessConstants.java
@@ -3,5 +3,5 @@
 public class WaterBudinessConstants {
     public final static String waterAuthUrl = "water_auth_url";
     public final static String waterSinaShortUrl = "water_sina_shorturl";
-    public final static String waterDeviceStatus = "device_status";
+    public final static String WATER_SHOP_ACCNO = "water_shopaccno";
 }
diff --git a/src/main/java/com/supwisdom/dlpay/framework/util/WaterDeviceParam.java b/src/main/java/com/supwisdom/dlpay/framework/util/WaterDeviceParam.java
index 22534a9..8ad1e25 100644
--- a/src/main/java/com/supwisdom/dlpay/framework/util/WaterDeviceParam.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/util/WaterDeviceParam.java
@@ -18,7 +18,7 @@
     //  单位扣费流量
     public static final String feeUnit = "feeunit";
     //  交易号
-    public static final String billNo = "billno";
+    public static final String cobillNo = "cobillno";
     //  从第多少百毫升开始计费
     public static final String feestart = "feestart";
     //  二维码失效时间
@@ -31,4 +31,6 @@
     public static final String payStatus = "paystatus";
     //  订单已支付金额
     public static final String paidAmount = "paidAmount";
+    //  立即扣费阈值
+    public static final String imdDecThreshold = "imdDecThreshold";
 }
diff --git a/src/main/java/com/supwisdom/dlpay/system/service/UserDataService.java b/src/main/java/com/supwisdom/dlpay/system/service/UserDataService.java
index 0c067dc..b146230 100644
--- a/src/main/java/com/supwisdom/dlpay/system/service/UserDataService.java
+++ b/src/main/java/com/supwisdom/dlpay/system/service/UserDataService.java
@@ -42,4 +42,10 @@
 
     @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class,readOnly = true)
     TPersonIdentity getPersonIdentityByThirdUid(String thirdUid);
+
+    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
+    TPersonIdentity updateCoamount(String thirdUid,Double amount);
+
+    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
+    TPersonIdentity updateAccamount(String thirdUid,Double amount);
 }
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 e7f8fd5..a43a761 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
@@ -25,163 +25,185 @@
 
 @Service
 public class UserDataServiceImpl implements UserDataService {
-  @Autowired
-  private PersonDao personDao;
-  @Autowired
-  private AccountDao accountDao;
-  @Autowired
-  private PointsAccountDao pointsAccountDao;
-  @Autowired
-  private SystemUtilService systemUtilService;
-  @Autowired
-  private PersonIdentityDao personIdentityDao;
+    @Autowired
+    private PersonDao personDao;
+    @Autowired
+    private AccountDao accountDao;
+    @Autowired
+    private PointsAccountDao pointsAccountDao;
+    @Autowired
+    private SystemUtilService systemUtilService;
+    @Autowired
+    private PersonIdentityDao personIdentityDao;
 
-  @Override
-  public PageResult<TPerson> getPersonsByKey(PersonParamBean param) {
-    Pageable pageable = PageRequest.of(param.getPageNo() - 1, param.getPageSize()
-            , Sort.by(Sort.Direction.DESC, "lastsaved"));
-    if (!StringUtil.isEmpty(param.getName())) {
-      return new PageResult<>(personDao.findAllByNameContaining(param.getName(), pageable));
-    }
-    return new PageResult<>(personDao.findAll(pageable));
-  }
-
-  @Override
-  public PageResult<TAccount> getAccountsByKey(PersonParamBean param) {
-    Pageable pageable = PageRequest.of(param.getPageNo() - 1, param.getPageSize());
-    if (!StringUtil.isEmpty(param.getName())) {
-      return new PageResult<>(accountDao.findAllByAccnameContaining(param.getName(), pageable));
-    }
-    return new PageResult<>(accountDao.findAll(pageable));
-  }
-
-  @Override
-  public PageResult<TPointsAccount> getPointsByKey(PersonParamBean param) {
-    Pageable pageable = PageRequest.of(param.getPageNo() - 1, param.getPageSize());
-    if (!StringUtil.isEmpty(param.getName())) {
-      return new PageResult<>(pointsAccountDao.findAllByNameContaining(param.getName(), pageable));
-    }
-    return new PageResult<>(pointsAccountDao.findAll(pageable));
-  }
-
-  @Override
-  public JsonResult saveUser(TPerson person) {
-    if (!StringUtil.isEmpty(person.getUserid())) {
-      Optional<TPerson> temp = personDao.findById(person.getUserid());
-      if (!temp.isPresent()) {
-        return JsonResult.error("参数错误");
-      }
-      TPerson it = temp.get();
-      if (!person.getIdno().equals(it.getIdno())
-              || !person.getIdtype().equals(it.getIdtype())) {
-        TPerson has = personDao.findByIdentity(person.getIdtype(), person.getIdno());
-        if (has != null && !has.getUserid().equals(person.getUserid())) {
-          return JsonResult.error("证件类型、证件号已存在");
+    @Override
+    public PageResult<TPerson> getPersonsByKey(PersonParamBean param) {
+        Pageable pageable = PageRequest.of(param.getPageNo() - 1, param.getPageSize()
+                , Sort.by(Sort.Direction.DESC, "lastsaved"));
+        if (!StringUtil.isEmpty(param.getName())) {
+            return new PageResult<>(personDao.findAllByNameContaining(param.getName(), pageable));
         }
-      }
-      if (!person.getName().equals(it.getName())) {
-        TAccount account = accountDao.findByUserid(person.getUserid());
+        return new PageResult<>(personDao.findAll(pageable));
+    }
+
+    @Override
+    public PageResult<TAccount> getAccountsByKey(PersonParamBean param) {
+        Pageable pageable = PageRequest.of(param.getPageNo() - 1, param.getPageSize());
+        if (!StringUtil.isEmpty(param.getName())) {
+            return new PageResult<>(accountDao.findAllByAccnameContaining(param.getName(), pageable));
+        }
+        return new PageResult<>(accountDao.findAll(pageable));
+    }
+
+    @Override
+    public PageResult<TPointsAccount> getPointsByKey(PersonParamBean param) {
+        Pageable pageable = PageRequest.of(param.getPageNo() - 1, param.getPageSize());
+        if (!StringUtil.isEmpty(param.getName())) {
+            return new PageResult<>(pointsAccountDao.findAllByNameContaining(param.getName(), pageable));
+        }
+        return new PageResult<>(pointsAccountDao.findAll(pageable));
+    }
+
+    @Override
+    public JsonResult saveUser(TPerson person) {
+        if (!StringUtil.isEmpty(person.getUserid())) {
+            Optional<TPerson> temp = personDao.findById(person.getUserid());
+            if (!temp.isPresent()) {
+                return JsonResult.error("参数错误");
+            }
+            TPerson it = temp.get();
+            if (!person.getIdno().equals(it.getIdno())
+                    || !person.getIdtype().equals(it.getIdtype())) {
+                TPerson has = personDao.findByIdentity(person.getIdtype(), person.getIdno());
+                if (has != null && !has.getUserid().equals(person.getUserid())) {
+                    return JsonResult.error("证件类型、证件号已存在");
+                }
+            }
+            if (!person.getName().equals(it.getName())) {
+                TAccount account = accountDao.findByUserid(person.getUserid());
+                if (account != null) {
+                    account.setAccname(person.getName());
+                    accountDao.save(account);
+                }
+            }
+            if (StringUtil.isEmpty(person.getStatus())) {
+                person.setStatus(TradeDict.STATUS_NORMAL);
+            }
+            personDao.save(person);
+        } else {
+            TPerson has = personDao.findByIdentity(person.getIdtype(), person.getIdno());
+            if (has != null) {
+                return JsonResult.error("证件类型、证件号已存在");
+            }
+            SystemDateTime systemDateTime = systemUtilService.getSysdatetime();
+            person.setStatus(TradeDict.STATUS_NORMAL);
+            person.setLastsaved(systemDateTime.getHostdatetime());
+            person = personDao.save(person);
+
+            TAccount account = new TAccount();
+            account.setAccname(person.getName());
+            account.setSubjno(Subject.SUBJNO_PERSONAL_DEPOSIT);
+            account.setUserid(person.getUserid());
+            account.setStatus(person.getStatus());
+            account.setBalance(0.0);
+            account.setAvailbal(0.0);
+            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());
+            account.setTac(account.generateTac());
+            accountDao.save(account);
+        }
+        return JsonResult.ok("添加成功");
+    }
+
+    @Override
+    public JsonResult deleteUser(String userid) {
+        TAccount account = accountDao.findByUserid(userid);
         if (account != null) {
-          account.setAccname(person.getName());
-          accountDao.save(account);
+            if (!TradeDict.STATUS_CLOSED.equals(account.getStatus()) && account.getBalance() != 0) {
+                return JsonResult.error("该用户账户未注销且余额不为0,无法删除");
+            } else {
+                accountDao.delete(account);
+            }
         }
-      }
-      if (StringUtil.isEmpty(person.getStatus())) {
-        person.setStatus(TradeDict.STATUS_NORMAL);
-      }
-      personDao.save(person);
-    } else {
-      TPerson has = personDao.findByIdentity(person.getIdtype(), person.getIdno());
-      if (has != null) {
-        return JsonResult.error("证件类型、证件号已存在");
-      }
-      SystemDateTime systemDateTime = systemUtilService.getSysdatetime();
-      person.setStatus(TradeDict.STATUS_NORMAL);
-      person.setLastsaved(systemDateTime.getHostdatetime());
-      person = personDao.save(person);
-
-      TAccount account = new TAccount();
-      account.setAccname(person.getName());
-      account.setSubjno(Subject.SUBJNO_PERSONAL_DEPOSIT);
-      account.setUserid(person.getUserid());
-      account.setStatus(person.getStatus());
-      account.setBalance(0.0);
-      account.setAvailbal(0.0);
-      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());
-      account.setTac(account.generateTac());
-      accountDao.save(account);
+        TPointsAccount pointsAccount = pointsAccountDao.findByUserid(userid);
+        if (pointsAccount != null) {
+            if (pointsAccount.getPoints() != 0) {
+                return JsonResult.error("该用户账户积分不为0,无法删除,若要删除请先删除积分账户");
+            } else {
+                pointsAccountDao.delete(pointsAccount);
+            }
+        }
+        personDao.deleteById(userid);
+        return JsonResult.ok("操作成功");
     }
-    return JsonResult.ok("添加成功");
-  }
 
-  @Override
-  public JsonResult deleteUser(String userid) {
-    TAccount account = accountDao.findByUserid(userid);
-    if (account != null) {
-      if (!TradeDict.STATUS_CLOSED.equals(account.getStatus()) && account.getBalance() != 0) {
-        return JsonResult.error("该用户账户未注销且余额不为0,无法删除");
-      } else {
-        accountDao.delete(account);
-      }
+    @Override
+    public JsonResult closeAccount(String accno) {
+        Optional<TAccount> opt = accountDao.findById(accno);
+        if (opt.isPresent()) {
+            TAccount acc = opt.get();
+            acc.setStatus(TradeDict.STATUS_CLOSED);
+            accountDao.save(acc);
+            return JsonResult.ok("操作成功");
+        } else {
+            return JsonResult.error("参数错误");
+        }
     }
-    TPointsAccount pointsAccount = pointsAccountDao.findByUserid(userid);
-    if (pointsAccount != null) {
-      if (pointsAccount.getPoints() != 0) {
-        return JsonResult.error("该用户账户积分不为0,无法删除,若要删除请先删除积分账户");
-      } else {
-        pointsAccountDao.delete(pointsAccount);
-      }
+
+    @Override
+    public JsonResult deletePoint(String userid) {
+        Optional<TPointsAccount> pointsAccount = pointsAccountDao.findById(userid);
+        if (pointsAccount.isPresent()) {
+            pointsAccountDao.delete(pointsAccount.get());
+            return JsonResult.ok("操作成功");
+        } else {
+            return JsonResult.error("参数错误");
+        }
     }
-    personDao.deleteById(userid);
-    return JsonResult.ok("操作成功");
-  }
 
-  @Override
-  public JsonResult closeAccount(String accno) {
-    Optional<TAccount> opt = accountDao.findById(accno);
-    if (opt.isPresent()) {
-      TAccount acc = opt.get();
-      acc.setStatus(TradeDict.STATUS_CLOSED);
-      accountDao.save(acc);
-      return JsonResult.ok("操作成功");
-    } else {
-      return JsonResult.error("参数错误");
+    @Override
+    public List<TPersonIdentity> getPersonIdentity(String userid) {
+        return null;
     }
-  }
 
-  @Override
-  public JsonResult deletePoint(String userid) {
-    Optional<TPointsAccount> pointsAccount = pointsAccountDao.findById(userid);
-    if (pointsAccount.isPresent()) {
-      pointsAccountDao.delete(pointsAccount.get());
-      return JsonResult.ok("操作成功");
-    }else {
-      return JsonResult.error("参数错误");
+    @Override
+    public PageResult<TPointsAccount> getUserPointDTL(PersonParamBean param) {
+        return null;
     }
-  }
 
-  @Override
-  public List<TPersonIdentity> getPersonIdentity(String userid) {
-    return null;
-  }
-
-  @Override
-  public PageResult<TPointsAccount> getUserPointDTL(PersonParamBean param) {
-    return null;
-  }
-
-  @Override
-  public TPersonIdentity getPersonIdentityByThirdUid(String thirdUid) {
-    TPersonIdentity personIdentity = personIdentityDao.getByThirdUid(thirdUid);
-    if (personIdentity != null) {
-      return personIdentity;
+    @Override
+    public TPersonIdentity getPersonIdentityByThirdUid(String thirdUid) {
+        TPersonIdentity personIdentity = personIdentityDao.getByThirdUid(thirdUid);
+        if (personIdentity != null) {
+            return personIdentity;
+        }
+        return null;
     }
-    return null;
-  }
+
+    @Override
+    public TPersonIdentity updateCoamount(String thirdUid, Double amount) {
+        TPersonIdentity personIdentity = personIdentityDao.getByThirdUid(thirdUid);
+        if (null == personIdentity) {
+            throw new RuntimeException("未找到用户id为" + thirdUid + "的用户");
+        }
+        personIdentity.setCoamount(personIdentity.getCoamount() == null ? amount : personIdentity.getCoamount() + amount);
+        personIdentityDao.save(personIdentity);
+        return personIdentity;
+    }
+
+    @Override
+    public TPersonIdentity updateAccamount(String thirdUid, Double amount) {
+        TPersonIdentity personIdentity = personIdentityDao.getByThirdUid(thirdUid);
+        if (null == personIdentity) {
+            throw new RuntimeException("未找到用户id为" + thirdUid + "的用户");
+        }
+        personIdentity.setAccamount(personIdentity.getAccamount() == null ? amount : personIdentity.getAccamount() + amount);
+        personIdentityDao.save(personIdentity);
+        return personIdentity;
+    }
 }
diff --git a/src/main/java/com/supwisdom/dlpay/water/dao/AccdtlDao.java b/src/main/java/com/supwisdom/dlpay/water/dao/AccdtlDao.java
new file mode 100644
index 0000000..0a1d624
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/water/dao/AccdtlDao.java
@@ -0,0 +1,21 @@
+package com.supwisdom.dlpay.water.dao;
+
+import com.supwisdom.dlpay.water.domain.TAccdtl;
+import org.springframework.data.jpa.repository.Lock;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.jpa.repository.QueryHints;
+import org.springframework.data.repository.CrudRepository;
+import org.springframework.stereotype.Repository;
+
+import javax.persistence.LockModeType;
+import javax.persistence.QueryHint;
+
+@Repository
+public interface AccdtlDao extends CrudRepository<TAccdtl, String> {
+    @Lock(LockModeType.PESSIMISTIC_WRITE)
+    @Query("select t from TAccdtl t where t.billno=?1")
+    @QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value = "0")})
+    TAccdtl findByBillnoForUpdate(String billno);
+
+    TAccdtl findByBillno(String billno);
+}
\ No newline at end of file
diff --git a/src/main/java/com/supwisdom/dlpay/water/dao/CollectdtlDao.java b/src/main/java/com/supwisdom/dlpay/water/dao/CollectdtlDao.java
new file mode 100644
index 0000000..f30cad3
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/water/dao/CollectdtlDao.java
@@ -0,0 +1,33 @@
+package com.supwisdom.dlpay.water.dao;
+
+import com.supwisdom.dlpay.water.domain.TCollectdtl;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.jpa.repository.Lock;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.jpa.repository.QueryHints;
+import org.springframework.data.repository.CrudRepository;
+import org.springframework.stereotype.Repository;
+
+import javax.persistence.LockModeType;
+import javax.persistence.QueryHint;
+import java.util.List;
+
+@Repository
+public interface CollectdtlDao extends CrudRepository<TCollectdtl, Integer> {
+    @Lock(LockModeType.PESSIMISTIC_WRITE)
+    @Query("select t from TCollectdtl t where t.cobillno=?1")
+    @QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value = "0")})
+    TCollectdtl findByCobillnoForUpdate(Integer cobillno);
+
+    @Lock(LockModeType.PESSIMISTIC_WRITE)
+    @Query("select t from TCollectdtl t where t.entryno=?1")
+    @QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value = "0")})
+    TCollectdtl findByEntrynoForUpdate(String entryno);
+
+    @Lock(LockModeType.PESSIMISTIC_WRITE)
+    @Query("select t from TCollectdtl  t where t.status='wip'")
+    @QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value = "0")})
+    List<TCollectdtl> findWipCollectdtl(Pageable pageable);
+
+    TCollectdtl findByCobillnoAndDeviceno(Integer cobillno, String deviceno);
+}
diff --git a/src/main/java/com/supwisdom/dlpay/water/dao/TransdtlDao.java b/src/main/java/com/supwisdom/dlpay/water/dao/TransdtlDao.java
deleted file mode 100644
index 3945100..0000000
--- a/src/main/java/com/supwisdom/dlpay/water/dao/TransdtlDao.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.supwisdom.dlpay.water.dao;
-
-import com.supwisdom.dlpay.water.domain.TTransdtl;
-import org.springframework.data.jpa.repository.Lock;
-import org.springframework.data.jpa.repository.Query;
-import org.springframework.data.jpa.repository.QueryHints;
-import org.springframework.data.repository.CrudRepository;
-import org.springframework.stereotype.Repository;
-
-import javax.persistence.LockModeType;
-import javax.persistence.QueryHint;
-
-@Repository
-public interface TransdtlDao extends CrudRepository<TTransdtl, String> {
-  @Lock(LockModeType.PESSIMISTIC_WRITE)
-  @Query("select t from TTransdtl t where t.billno=?1")
-  @QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value = "0")})
-  TTransdtl findByBillnoForUpdate(String billno);
-
-  TTransdtl findByBillnoAndDeviceno(String billno, String deviceno);
-}
diff --git a/src/main/java/com/supwisdom/dlpay/water/domain/TAccdtl.java b/src/main/java/com/supwisdom/dlpay/water/domain/TAccdtl.java
new file mode 100644
index 0000000..88265bb
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/water/domain/TAccdtl.java
@@ -0,0 +1,160 @@
+package com.supwisdom.dlpay.water.domain;
+
+import javax.persistence.*;
+import javax.validation.constraints.NotNull;
+
+@Entity
+@Table(name = "tb_accentrydtl",
+        indexes = {@Index(name = "accdtl_userid", columnList = "userid"),
+                @Index(name = "accdtl_status", columnList = "status"),
+                @Index(name = "accdtl_acc", columnList = "accdate")})
+public class TAccdtl {
+    @Id
+    @Column(name = "billno", length = 32)
+    private String billno;
+
+    @Column(length = 16)
+    private String status;
+
+    @Column(name = "transdate", length = 14)
+    @NotNull
+    private String transDate;
+
+    @Column(name = "transtime", length = 6)
+    @NotNull
+    private String transTime;
+
+    @Column(length = 8)
+    @NotNull
+    private String deviceno;
+
+    @Column(length = 32)
+    private String userid;
+
+    @Column(name = "bankcardno", length = 32)
+    private String citizenCardno;
+
+    @Column(length = 20)
+    @NotNull
+    private String mode;
+
+    @Column(precision = 10, scale = 2)
+    private Double amount;
+
+    @Column(name = "water_in_100ml", precision = 10)
+    private Integer waterSumHundredLitre;
+
+    @Column(name = "accdate", length = 8)
+    private String accdate;
+
+    @Column(name = "cardphyid",length = 60)
+    private String cardPhyId;
+
+    @Column(name = "refno", length = 32)
+    private String refno;
+
+
+    public String getRefno() {
+        return refno;
+    }
+
+    public void setRefno(String refno) {
+        this.refno = refno;
+    }
+
+    public String getBillno() {
+        return billno;
+    }
+
+    public void setBillno(String billno) {
+        this.billno = billno;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public String getTransDate() {
+        return transDate;
+    }
+
+    public void setTransDate(String transDate) {
+        this.transDate = transDate;
+    }
+
+    public String getTransTime() {
+        return transTime;
+    }
+
+    public void setTransTime(String transTime) {
+        this.transTime = transTime;
+    }
+
+    public String getDeviceno() {
+        return deviceno;
+    }
+
+    public void setDeviceno(String deviceno) {
+        this.deviceno = deviceno;
+    }
+
+    public String getUserid() {
+        return userid;
+    }
+
+    public void setUserid(String userid) {
+        this.userid = userid;
+    }
+
+    public String getCitizenCardno() {
+        return citizenCardno;
+    }
+
+    public void setCitizenCardno(String citizenCardno) {
+        this.citizenCardno = citizenCardno;
+    }
+
+    public String getMode() {
+        return mode;
+    }
+
+    public void setMode(String mode) {
+        this.mode = mode;
+    }
+
+    public Double getAmount() {
+        return amount;
+    }
+
+    public void setAmount(Double amount) {
+        this.amount = amount;
+    }
+
+    public Integer getWaterSumHundredLitre() {
+        return waterSumHundredLitre;
+    }
+
+    public void setWaterSumHundredLitre(Integer waterSumHundredLitre) {
+        this.waterSumHundredLitre = waterSumHundredLitre;
+    }
+
+    public String getAccdate() {
+        return accdate;
+    }
+
+    public void setAccdate(String accdate) {
+        this.accdate = accdate;
+    }
+
+    public String getCardPhyId() {
+        return cardPhyId;
+    }
+
+    public void setCardPhyId(String cardPhyId) {
+        this.cardPhyId = cardPhyId;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/supwisdom/dlpay/water/domain/TTransdtl.java b/src/main/java/com/supwisdom/dlpay/water/domain/TCollectdtl.java
similarity index 71%
rename from src/main/java/com/supwisdom/dlpay/water/domain/TTransdtl.java
rename to src/main/java/com/supwisdom/dlpay/water/domain/TCollectdtl.java
index f8e4b79..09c43f2 100644
--- a/src/main/java/com/supwisdom/dlpay/water/domain/TTransdtl.java
+++ b/src/main/java/com/supwisdom/dlpay/water/domain/TCollectdtl.java
@@ -4,16 +4,18 @@
 import javax.validation.constraints.NotNull;
 
 @Entity
-@Table(name = "tb_transdtl",
-    indexes = {@Index(name = "trasndtl_userid", columnList = "userid"),
-        @Index(name = "transdtl_status", columnList = "transdate, status"),
-        @Index(name = "transdtl_acc", columnList = "accdate")})
-public class TTransdtl {
+@Table(name = "tb_collectdtl",
+    indexes = {@Index(name = "collectdtl_userid", columnList = "userid"),
+        @Index(name = "collectdtl_status", columnList = "transdate, status"),
+        @Index(name = "collectdtl_acc", columnList = "accdate")})
+@SequenceGenerator(name = "SEQ_COLLECT_BILLNO", sequenceName = "SEQ_COLLECT_BILLNO", allocationSize = 1)
+public class TCollectdtl {
   @Id
-  @Column(name = "billno", length = 32)
-  private String billno;
+  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_COLLECT_BILLNO")
+  @Column(name = "cobillno", nullable = false)
+  private Integer cobillno;
 
-  @Column(name = "transdate", length = 8)
+  @Column(name = "transdate", length = 14)
   @NotNull
   private String transDate;
 
@@ -28,8 +30,8 @@
   @Column(length = 32)
   private String userid;
 
-  @Column(name = "bankcardno", length = 32)
-  private String bankCardNo;
+  @Column(name = "citizencardno", length = 32)
+  private String citizenCardno;
 
   @Column(length = 20)
   @NotNull
@@ -51,11 +53,8 @@
   @Column(name = "accdate", length = 8)
   private String accdate;
 
-  @Column(name = "refno", length = 32)
-  private String refno;
-
-  @Column(name = "accstatus", length = 10)
-  private String accStatus;
+  @Column(name = "entryno", length = 32)
+  private String entryno;
 
   @Column(name = "authstatus")
   private Boolean authStatus;
@@ -90,12 +89,12 @@
     this.authStatus = authStatus;
   }
 
-  public String getBillno() {
-    return billno;
+  public Integer getCobillno() {
+    return cobillno;
   }
 
-  public void setBillno(String billno) {
-    this.billno = billno;
+  public void setCobillno(Integer cobillno) {
+    this.cobillno = cobillno;
   }
 
   public String getDeviceno() {
@@ -130,12 +129,12 @@
     this.userid = userid;
   }
 
-  public String getBankCardNo() {
-    return bankCardNo;
+  public String getCitizenCardno() {
+    return citizenCardno;
   }
 
-  public void setBankCardNo(String bankCardNo) {
-    this.bankCardNo = bankCardNo;
+  public void setCitizenCardno(String citizenCardno) {
+    this.citizenCardno = citizenCardno;
   }
 
   public String getMode() {
@@ -186,19 +185,12 @@
     this.accdate = accdate;
   }
 
-  public String getRefno() {
-    return refno;
+  public String getEntryno() {
+    return entryno;
   }
 
-  public void setRefno(String refno) {
-    this.refno = refno;
+  public void setEntryno(String entryno) {
+    this.entryno = entryno;
   }
 
-  public String getAccStatus() {
-    return accStatus;
-  }
-
-  public void setAccStatus(String accStatus) {
-    this.accStatus = accStatus;
-  }
 }
diff --git a/src/main/java/com/supwisdom/dlpay/water/domain/TTransdtlCount.java b/src/main/java/com/supwisdom/dlpay/water/domain/TTransdtlCount.java
index 21204c5..598b0ad 100644
--- a/src/main/java/com/supwisdom/dlpay/water/domain/TTransdtlCount.java
+++ b/src/main/java/com/supwisdom/dlpay/water/domain/TTransdtlCount.java
@@ -7,7 +7,8 @@
 @Table(name = "tb_transdtl_count",
         indexes = {@Index(name = "trasndtl_count_accdate", columnList = "accdate"),
                 @Index(name = "transdtl_count_areano", columnList = "areano"),
-                @Index(name = "transdtl_count_devicename", columnList = "devicename")})
+                @Index(name = "transdtl_count_devicename", columnList = "devicename"),
+                @Index(name = "transdtl_count_idx", columnList = "accdate, areano, deviceno", unique = true)})
 @SequenceGenerator(name = "SEQ_TRANSDTL_COUNT", sequenceName = "SEQ_TRANSDTL_COUNT", allocationSize = 1, initialValue = 1000)
 public class TTransdtlCount {
     @Id
diff --git a/src/main/java/com/supwisdom/dlpay/water/init/PayInit.java b/src/main/java/com/supwisdom/dlpay/water/init/PayInit.java
deleted file mode 100644
index 1389880..0000000
--- a/src/main/java/com/supwisdom/dlpay/water/init/PayInit.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.supwisdom.dlpay.water.init;
-
-import com.supwisdom.dlpay.paysdk.ApiLoginHelper;
-import com.supwisdom.dlpay.paysdk.proxy.ApiLoginProxy;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.cloud.openfeign.EnableFeignClients;
-import org.springframework.context.annotation.ComponentScan;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.PostConstruct;
-
-@Component
-@EnableFeignClients(basePackages = "com.supwisdom.dlpay.paysdk")
-@ComponentScan(basePackages = {"com.supwisdom.dlpay.paysdk"})
-public class PayInit {
-
-    private final static String appid = "700001";
-    private final static String secret = "5f788ce433ec44f299351cdf7f137e81";
-
-    @Autowired
-    private ApiLoginProxy apiLoginProxy;
-
-//    @PostConstruct
-//    public void login() {
-//        ApiLoginHelper helper = new ApiLoginHelper(apiLoginProxy);
-//        helper.login(appid,secret);
-//    }
-}
diff --git a/src/main/java/com/supwisdom/dlpay/water/pay/PayInit.java b/src/main/java/com/supwisdom/dlpay/water/pay/PayInit.java
new file mode 100644
index 0000000..c99b406
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/water/pay/PayInit.java
@@ -0,0 +1,44 @@
+package com.supwisdom.dlpay.water.pay;
+
+import com.supwisdom.dlpay.api.bean.ApiVersionResponse;
+import com.supwisdom.dlpay.paysdk.ApiLoginHelper;
+import com.supwisdom.dlpay.paysdk.proxy.ApiCommonProxy;
+import com.supwisdom.dlpay.paysdk.proxy.ApiLoginProxy;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.notNullValue;
+
+@Component
+@EnableFeignClients(basePackages = "com.supwisdom.dlpay.paysdk")
+@ComponentScan(basePackages = {"com.supwisdom.dlpay.paysdk"})
+public class PayInit {
+    @Value("${water.appid}")
+    private  String appid;
+
+    @Value("${water.secret}")
+    private  String secret;
+
+    @Autowired
+    private ApiLoginProxy apiLoginProxy;
+
+    @Autowired
+    private ApiCommonProxy apiCommonProxy;
+
+    @PostConstruct
+    public void login() {
+        ApiLoginHelper helper = new ApiLoginHelper(apiLoginProxy);
+        helper.login(appid,secret);
+        ApiVersionResponse version = apiCommonProxy.apiVersion();
+        assertThat("get version error " + version.getException(),
+                version.getVersion(), notNullValue());
+    }
+
+    //TODO:刷新TOKEN
+}
diff --git a/src/main/java/com/supwisdom/dlpay/water/pay/WaterPayAsyncTask.java b/src/main/java/com/supwisdom/dlpay/water/pay/WaterPayAsyncTask.java
new file mode 100644
index 0000000..1eeb82f
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/water/pay/WaterPayAsyncTask.java
@@ -0,0 +1,202 @@
+package com.supwisdom.dlpay.water.pay;
+
+import com.supwisdom.dlpay.api.bean.*;
+import com.supwisdom.dlpay.framework.service.BusinessparaService;
+import com.supwisdom.dlpay.framework.service.SystemUtilService;
+import com.supwisdom.dlpay.framework.util.Constants;
+import com.supwisdom.dlpay.framework.util.TradeDict;
+import com.supwisdom.dlpay.framework.util.TradeErrorCode;
+import com.supwisdom.dlpay.framework.util.WaterBudinessConstants;
+import com.supwisdom.dlpay.paysdk.proxy.CitizenCardPayProxy;
+import com.supwisdom.dlpay.paysdk.proxy.TransactionProxy;
+import com.supwisdom.dlpay.system.service.UserDataService;
+import com.supwisdom.dlpay.water.domain.TAccdtl;
+import com.supwisdom.dlpay.water.domain.TCollectdtl;
+import com.supwisdom.dlpay.water.service.AccdtlService;
+import com.supwisdom.dlpay.water.service.CollectdtlService;
+import org.hamcrest.MatcherAssert;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Component;
+
+import static org.hamcrest.Matchers.equalTo;
+
+
+@Component
+public class WaterPayAsyncTask {
+
+    private static final Logger logger = LoggerFactory.getLogger(WaterPayAsyncTask.class);
+
+    @Autowired
+    private CitizenCardPayProxy citizenCardPayProxy;
+
+    @Autowired
+    private TransactionProxy transactionProxy;
+
+    @Autowired
+    private SystemUtilService systemUtilService;
+
+    @Autowired
+    private AccdtlService accdtlService;
+
+    @Autowired
+    private UserDataService userDataService;
+
+    @Autowired
+    private CollectdtlService collectdtlService;
+
+    @Autowired
+    private BusinessparaService businessparaService;
+
+    @Async("waterPay")
+    public void waterPay(Integer cobillno) {
+        TCollectdtl collectdtl = collectdtlService.findByCobillnoForUpdate(cobillno);
+        //  是否已生成入账流水
+        if (collectdtl.getEntryno() != null) {
+            TAccdtl accdtl = accdtlService.findByBillno(collectdtl.getEntryno());
+            String accStatus = accdtl.getStatus();
+            if (null == accStatus) {
+                //  入账流水状态为空,需查询是否已初始化
+                QueryDtlResultParam queryParam = new QueryDtlResultParam();
+                queryParam.setBillno(accdtl.getBillno());
+                queryParam.setShopaccno(businessparaService.findByParakey(WaterBudinessConstants.WATER_SHOP_ACCNO).getParaval());
+                QueryTransDtlResponse queryResult = transactionProxy.queryDtlResult(queryParam);
+                if (0 == queryResult.getRetcode()) {
+                    //  流水已初始化,进行确认
+                    TAccdtl initAccdtl = initAcc(queryResult.getOutTradeNo(), queryResult.getRefno());
+                    payConfirm(initAccdtl);
+                } else if (TradeErrorCode.TRANSACTION_NOT_EXISTS == queryResult.getRetcode()) {
+                    //  流水尚未初始化,可直接扣费
+                    waterPay(accdtl);
+                }
+            } else if (TradeDict.DTL_STATUS_FAIL.equals(accStatus)) {
+                //  入账流水扣费失败,重新生成入账流水扣费
+                TAccdtl newAccdtl = buildAccdtl(collectdtl);
+                newAccdtl = accdtlService.creatNewAccdtl(newAccdtl,collectdtl.getCobillno());
+                waterPay(newAccdtl);
+            } else if (TradeDict.DTL_STATUS_INIT.equals(accStatus) ||
+                    TradeDict.DTL_STATUS_WIP.equals(accStatus)) {
+                //  入账流水状态为init,需查询是否已确认
+                QueryDtlResultParam queryParam = new QueryDtlResultParam();
+                queryParam.setRefno(accdtl.getRefno());
+                QueryTransDtlResponse queryResult = transactionProxy.queryDtlResult(queryParam);
+                if (0 == queryResult.getRetcode()) {
+                    //  查询得到状态为init
+                    if (TradeDict.DTL_STATUS_INIT.equals(queryResult.getStatus())) {
+                        //  进行消费确认
+                        payConfirm(accdtl);
+                    } else if (TradeDict.DTL_STATUS_SUCCESS.equals(queryResult.getStatus())) {
+                        //  查询得到状态为success或fail,记录下状态
+                        userDataService.updateAccamount(accdtl.getCitizenCardno(), accdtl.getAmount());
+                        cofirmAcc(queryResult.getStatus(), accdtl.getBillno(), accdtl.getRefno());
+                    } else if (TradeDict.DTL_STATUS_FAIL.equals(queryResult.getStatus())) {
+                        cofirmAcc(queryResult.getStatus(), accdtl.getBillno(), accdtl.getRefno());
+                    }
+                } else if (TradeErrorCode.TRANSACTION_NOT_EXISTS == queryResult.getRetcode()) {
+                    logger.error("入账流水:" + accdtl.getBillno() + "的refno:" + accdtl.getRefno() + "未找到");
+                }
+            }
+        } else {
+            //  未生成入账流水
+            //  生成一条入账流水,并将其billno存入对应的采集流水
+            TAccdtl accdtl = buildAccdtl(collectdtl);
+            accdtl = accdtlService.creatNewAccdtl(accdtl, collectdtl.getCobillno());
+            if (null == accdtl) {
+                return;
+            }
+            //  支付中心初始化并确认入账流水
+            waterPay(accdtl);
+        }
+    }
+
+    private void waterPay(TAccdtl accdtl) {
+        //  支付中心初始化入账流水
+        CitizenCardPayinitParam initParam = buildPayInitParam(accdtl);
+        CitizenPayResponse payInit = citizenCardPayProxy.citizencardPayinit(initParam);
+        MatcherAssert.assertThat("pay initialized " + payInit.getRetmsg() + payInit.getException(),
+                payInit.getRetcode(), equalTo(0));
+        //  初始化成功记录下refno,并修改入账流水状态为init
+        TAccdtl initAccdtl = initAcc(payInit.getBillno(), payInit.getRefno());
+        //  支付中心确认入账流水
+        payConfirm(initAccdtl);
+    }
+
+    private TAccdtl initAcc(String billno, String refno) {
+        InitAccParam initAccParam = new InitAccParam();
+        initAccParam.setBillno(billno);
+        initAccParam.setRefno(refno);
+        return accdtlService.initAcc(initAccParam);
+    }
+
+    private TAccdtl buildAccdtl(TCollectdtl collectdtl) {
+        TAccdtl accdtl = new TAccdtl();
+        accdtl.setDeviceno(collectdtl.getDeviceno());
+        accdtl.setUserid(collectdtl.getUserid());
+        accdtl.setCitizenCardno(collectdtl.getCitizenCardno());
+        accdtl.setMode(TradeDict.PAY_MODE_CARD);//TODO: 二维码消费
+        accdtl.setAmount(collectdtl.getAmount());
+        accdtl.setWaterSumHundredLitre(collectdtl.getWaterSumHundredLitre());
+        accdtl.setCardPhyId(collectdtl.getCardPhyId());
+        accdtl.setTransTime(collectdtl.getTransTime());
+        accdtl.setTransDate(collectdtl.getTransDate());
+        return accdtl;
+    }
+
+    private CitizenCardPayinitParam buildPayInitParam(TAccdtl accdtl) {
+        CitizenCardPayinitParam initParam = new CitizenCardPayinitParam();
+        initParam.setBillno(accdtl.getBillno());
+        initParam.setCardNo(accdtl.getCitizenCardno());
+        Double amount = (accdtl.getAmount() * 100);
+        initParam.setAmount(amount.intValue());
+        initParam.setDtltype(Constants.DTLTYPE_WATER);
+        initParam.setTransdate(accdtl.getTransDate());
+        initParam.setTranstime(accdtl.getTransTime());
+        initParam.setShopaccno(businessparaService.findByParakey(WaterBudinessConstants.WATER_SHOP_ACCNO).getParaval());
+        return initParam;
+    }
+
+    private void payConfirm(TAccdtl initAccdtl) {
+        CitizenCardPayfinishParam finishParam = new CitizenCardPayfinishParam();
+        finishParam.setRefno(initAccdtl.getRefno());
+        CitizenPayResponse payFinish = citizenCardPayProxy.citizencardPayFinish(finishParam);
+        //2.1   处理消费确认响应结果
+        int finishRetcode = payFinish.getRetcode();
+        String accStatus;
+        if (finishRetcode == 0) {
+            accStatus = TradeDict.DTL_STATUS_SUCCESS;
+            //  更新用户已入账金额
+            userDataService.updateAccamount(initAccdtl.getCitizenCardno(), initAccdtl.getAmount());
+        } else if (finishRetcode == TradeErrorCode.WAIT_QUERY_RESULT) {
+            QueryDtlResultParam queryParam = new QueryDtlResultParam();
+            queryParam.setRefno(payFinish.getRefno());
+            QueryTransDtlResponse queryResult = transactionProxy.queryDtlResult(queryParam);
+            if (0 == queryResult.getRetcode()) {
+                accStatus = queryResult.getStatus();
+                if (TradeDict.DTL_STATUS_SUCCESS.equals(accStatus)) {
+                    userDataService.updateAccamount(initAccdtl.getCitizenCardno(), initAccdtl.getAmount());
+                }
+            } else {
+                accStatus = TradeDict.DTL_STATUS_WIP;
+                logger.error("查询确认结果失败:" + queryResult.getRetcode() + "," + queryResult.getRetmsg());
+            }
+        } else if (finishRetcode == TradeErrorCode.BUSINESS_DEAL_ERROR) {
+            accStatus = TradeDict.DTL_STATUS_FAIL;
+        } else {
+            accStatus = TradeDict.DTL_STATUS_WIP;
+            logger.error("未知的确认状态码:" + finishRetcode + "," + payFinish.getRetmsg());
+        }
+        //2.2   记录消费确认
+        cofirmAcc(accStatus, payFinish.getBillno(), payFinish.getRefno());
+    }
+
+    private void cofirmAcc(String accStatus, String billno, String refno) {
+        ConfirmAccParam accParam = new ConfirmAccParam();
+        accParam.setAccdate(systemUtilService.getSysdatetime().getHostdate());
+        accParam.setAccstatus(accStatus);
+        accParam.setBillno(billno);
+        accParam.setRefno(refno);
+        accdtlService.confirmAcc(accParam);
+    }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/water/service/AccdtlService.java b/src/main/java/com/supwisdom/dlpay/water/service/AccdtlService.java
new file mode 100644
index 0000000..8580f45
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/water/service/AccdtlService.java
@@ -0,0 +1,21 @@
+package com.supwisdom.dlpay.water.service;
+
+
+import com.supwisdom.dlpay.api.bean.ConfirmAccParam;
+import com.supwisdom.dlpay.api.bean.InitAccParam;
+import com.supwisdom.dlpay.water.domain.TAccdtl;
+import org.springframework.transaction.annotation.Transactional;
+
+public interface AccdtlService {
+    @Transactional(rollbackFor = Exception.class)
+    TAccdtl initAcc(InitAccParam param);
+
+    @Transactional(rollbackFor = Exception.class)
+    TAccdtl confirmAcc(ConfirmAccParam param);
+
+    @Transactional(rollbackFor = Exception.class)
+    TAccdtl creatNewAccdtl(TAccdtl accdtl, Integer cobillno);
+
+    @Transactional(rollbackFor = Exception.class)
+    TAccdtl findByBillno(String billno);
+}
diff --git a/src/main/java/com/supwisdom/dlpay/water/service/TransdtlService.java b/src/main/java/com/supwisdom/dlpay/water/service/CollectdtlService.java
similarity index 65%
rename from src/main/java/com/supwisdom/dlpay/water/service/TransdtlService.java
rename to src/main/java/com/supwisdom/dlpay/water/service/CollectdtlService.java
index acb1a9b..9a38e4c 100644
--- a/src/main/java/com/supwisdom/dlpay/water/service/TransdtlService.java
+++ b/src/main/java/com/supwisdom/dlpay/water/service/CollectdtlService.java
@@ -5,31 +5,37 @@
 import com.supwisdom.dlpay.water.UploadRecordRequest;
 import com.supwisdom.dlpay.water.UserAuthRequest;
 import com.supwisdom.dlpay.water.bean.TransdtlCountSearchBean;
-import com.supwisdom.dlpay.water.domain.TTransdtl;
+import com.supwisdom.dlpay.water.domain.TCollectdtl;
 import com.supwisdom.dlpay.water.domain.TTransdtlCount;
 import com.supwisdom.dlpay.water.pojo.TTransdtlDTO;
 import com.supwisdom.dlpay.water.bean.TransdtlSearchBean;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.util.List;
 
-public interface TransdtlService {
+
+public interface CollectdtlService {
     @Transactional(rollbackFor = Exception.class)
-    TTransdtl createNewTransdtl(TTransdtl dtl);
+    TCollectdtl createNewTransdtl(TCollectdtl dtl);
 
     @Transactional(rollbackFor = Exception.class)
-    TTransdtl saveDeviceDtlData(UploadRecordRequest record);
+    TCollectdtl saveDeviceDtlData(UploadRecordRequest record);
 
     @Transactional(rollbackFor = Exception.class)
-    TTransdtl queryTrans(QrcodeQueryRequest param);
+    TCollectdtl queryTrans(Integer cobillno);
 
     @Transactional(rollbackFor = Exception.class)
-    TTransdtl userAuth(UserAuthRequest param);
+    TCollectdtl userAuth(UserAuthRequest param);
 
     @Transactional(rollbackFor = Exception.class)
     PageResult<TTransdtlDTO> queryTransdtlDTOByParam(TransdtlSearchBean param);
 
-    @Transactional(rollbackFor = Exception.class)
+    @Transactional(rollbackFor = Exception.class,readOnly = true)
     PageResult<TTransdtlCount> queryTransdtlCountByParam(TransdtlCountSearchBean param);
 
+    @Transactional(rollbackFor = Exception.class)
+    List<TCollectdtl> queryTransdtlNotEntry();
 
+    @Transactional(rollbackFor = Exception.class)
+    TCollectdtl findByCobillnoForUpdate(Integer cobillno);
 }
diff --git a/src/main/java/com/supwisdom/dlpay/water/service/impl/AccdtlServiceImpl.java b/src/main/java/com/supwisdom/dlpay/water/service/impl/AccdtlServiceImpl.java
new file mode 100644
index 0000000..54033bc
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/water/service/impl/AccdtlServiceImpl.java
@@ -0,0 +1,106 @@
+package com.supwisdom.dlpay.water.service.impl;
+
+import com.supwisdom.dlpay.api.bean.ConfirmAccParam;
+import com.supwisdom.dlpay.api.bean.InitAccParam;
+import com.supwisdom.dlpay.framework.service.SystemUtilService;
+import com.supwisdom.dlpay.framework.util.TradeDict;
+import com.supwisdom.dlpay.water.dao.AccdtlDao;
+import com.supwisdom.dlpay.water.dao.CollectdtlDao;
+import com.supwisdom.dlpay.water.domain.TAccdtl;
+import com.supwisdom.dlpay.water.domain.TCollectdtl;
+import com.supwisdom.dlpay.water.service.AccdtlService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+
+@Service
+public class AccdtlServiceImpl implements AccdtlService {
+
+    private static final Logger logger = LoggerFactory.getLogger(AccdtlServiceImpl.class);
+
+    @Autowired
+    private CollectdtlDao collectdtlDao;
+
+    @Autowired
+    private AccdtlDao accdtlDao;
+
+    @Autowired
+    private SystemUtilService systemUtilService;
+
+    @Override
+    public TAccdtl initAcc(InitAccParam param) {
+        TAccdtl accdtl = accdtlDao.findByBillnoForUpdate(param.getBillno());
+        if (null == accdtl) {
+            logger.error("入账流水:" + param.getBillno() + "未找到");
+            return null;
+        }
+        accdtl.setRefno(param.getRefno());
+        accdtl.setStatus(TradeDict.DTL_STATUS_INIT);
+        accdtlDao.save(accdtl);
+        return accdtl;
+    }
+
+    @Override
+    public TAccdtl confirmAcc(ConfirmAccParam param) {
+        String billno = param.getBillno();
+        TAccdtl accdtl = accdtlDao.findByBillnoForUpdate(billno);
+        if (null == accdtl) {
+            logger.error("确认入账后,未找到流水号为:" + billno + "的入账流水");
+            return null;
+        }
+        if (!param.getRefno().equals(accdtl.getRefno())) {
+            logger.error("确认入账时,支付中心确认流水号:"+param.getRefno()+"与初始化流水号:"+accdtl.getRefno()+"不相等");
+            return null;
+        }
+        if (TradeDict.DTL_STATUS_SUCCESS.equals(param.getAccstatus())) {
+            TCollectdtl collectdtl = collectdtlDao.findByEntrynoForUpdate(billno);
+            if (null == collectdtl) {
+                logger.error("确认入账后,未找到入账流水为:" + billno + "对应的采集流水");
+                return null;
+            }
+            collectdtl.setAccdate(param.getAccdate());
+            collectdtl.setStatus(TradeDict.DTL_STATUS_SUCCESS);
+            accdtl.setAccdate(param.getAccdate());
+            collectdtlDao.save(collectdtl);
+        }
+        accdtl.setStatus(param.getAccstatus());
+        accdtlDao.save(accdtl);
+        return accdtl;
+    }
+
+    @Override
+    public TAccdtl creatNewAccdtl(TAccdtl accdtl,Integer cobillno) {
+        TCollectdtl collectdtl = collectdtlDao.findByCobillnoForUpdate(cobillno);
+        if (null == collectdtl) {
+            throw new RuntimeException("采集流水号:" + cobillno + "未找到");
+        }
+        if (null == collectdtl.getEntryno()) {
+            accdtl.setBillno(systemUtilService.getRefno());
+            accdtlDao.save(accdtl);
+            collectdtl.setEntryno(accdtl.getBillno());
+            collectdtlDao.save(collectdtl);
+            return accdtl;
+        } else {
+            TAccdtl oldAccdtl = accdtlDao.findByBillno(collectdtl.getEntryno());
+            if (TradeDict.DTL_STATUS_FAIL.equals(oldAccdtl.getStatus())) {
+                accdtl.setBillno(systemUtilService.getRefno());
+                collectdtl.setEntryno(accdtl.getBillno());
+                accdtlDao.save(accdtl);
+                collectdtlDao.save(collectdtl);
+                return accdtl;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public TAccdtl findByBillno(String billno) {
+        TAccdtl accdtl = accdtlDao.findByBillno(billno);
+        if (null == accdtl) {
+            throw new RuntimeException("入账流水号:" + billno + "未找到");
+        }
+        return accdtl;
+    }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/water/service/impl/DeviceServiceImpl.java b/src/main/java/com/supwisdom/dlpay/water/service/impl/DeviceServiceImpl.java
index 5df271b..043e561 100644
--- a/src/main/java/com/supwisdom/dlpay/water/service/impl/DeviceServiceImpl.java
+++ b/src/main/java/com/supwisdom/dlpay/water/service/impl/DeviceServiceImpl.java
@@ -2,9 +2,9 @@
 
 import com.supwisdom.dlpay.framework.dao.DictionaryDao;
 import com.supwisdom.dlpay.framework.domain.TDictionary;
+import com.supwisdom.dlpay.framework.util.Dictionary;
 import com.supwisdom.dlpay.framework.util.PageResult;
 import com.supwisdom.dlpay.framework.util.StringUtil;
-import com.supwisdom.dlpay.framework.util.WaterBudinessConstants;
 import com.supwisdom.dlpay.framework.util.WaterDeviceParam;
 import com.supwisdom.dlpay.water.DeviceLineCheckParam;
 import com.supwisdom.dlpay.water.DeviceLoginParam;
@@ -53,7 +53,7 @@
     @PersistenceContext
     private EntityManager entityManager;
 
-    private static String paraSql = "select p.* from tb_device d left join " +
+    private final static String paraSql = "select p.* from tb_device d left join " +
             "tb_areapara_bind b on d.areano = b.areano left join " +
             "tb_areapara p on b.groupid = p.groupid where d.deviceno = ?";
 
@@ -164,7 +164,7 @@
 
     @Override
     public List<TDictionary> groupStatus() {
-        return dictionaryDao.findAllByDicttype(WaterBudinessConstants.waterDeviceStatus);
+        return dictionaryDao.findAllByDicttype(Dictionary.WATER_DEVICE_STATUS);
     }
 
     @Override
diff --git a/src/main/kotlin/com/supwisdom/dlpay/api/bean/api_request_param.kt b/src/main/kotlin/com/supwisdom/dlpay/api/bean/api_request_param.kt
index 6e06756..af9581b 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/api/bean/api_request_param.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/api/bean/api_request_param.kt
@@ -160,11 +160,11 @@
 
 class QueryDtlResultParam : APIRequestParam() {
     @Sign
-    var refno:String?=null //二选一
+    var refno: String? = null //二选一
     @Sign
-    var billno:String?=null //二选一 (billno+shopaccno) 传billno时,shopaccno必传
+    var billno: String? = null //二选一 (cobillno+shopaccno) 传billno时,shopaccno必传
     @Sign
-    var shopaccno: String?=null
+    var shopaccno: String? = null
 
     override fun checkParam(): Boolean {
         if (StringUtil.isEmpty(refno) && (StringUtil.isEmpty(billno) || StringUtil.isEmpty(shopaccno))) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "流水唯一号不能为空")
@@ -188,6 +188,8 @@
     var transdate: String = "" //必传
     @Sign
     var transtime: String = "" //必传
+    @Sign
+    var dtltype: String = ""
 
     override fun checkParam(): Boolean {
         if (StringUtil.isEmpty(cardNo)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "卡唯一号不能为空")
@@ -203,7 +205,7 @@
 
 class CitizenCardPayfinishParam : APIRequestParam() {
     @Sign
-    var refno:String=""
+    var refno: String = ""
 
     override fun checkParam(): Boolean {
         if (StringUtil.isEmpty(refno)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "交易参考号不能为空")
@@ -242,12 +244,44 @@
         if (!DateUtil.checkDatetimeValid(transdate, DateUtil.DATE_FMT)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "交易日期错误[yyyyMMdd]")
         if (!DateUtil.checkDatetimeValid(transtime, DateUtil.TIME_FMT)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "交易时间错误[HHmmss]")
         if (StringUtil.isEmpty(stuempno)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "一卡通唯一号不能为空")
-        if(!StringUtil.isEmpty(yktshopid) && !NumberUtil.isDigits(yktshopid)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "一卡通商户号非整数")
+        if (!StringUtil.isEmpty(yktshopid) && !NumberUtil.isDigits(yktshopid)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "一卡通商户号非整数")
 
         return true
     }
 }
 
+class ConfirmAccParam : APIRequestParam() {
+    @Sign
+    var accdate: String = ""
+    @Sign
+    var accstatus: String = ""
+    @Sign
+    var refno: String = ""
+    @Sign
+    var billno: String = ""
+
+    override fun checkParam(): Boolean {
+        if (StringUtil.isEmpty(accdate)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "入账日期不能为空")
+        if (StringUtil.isEmpty(accstatus)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "入账确认状态不能为空")
+        if (StringUtil.isEmpty(refno)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "入账确认流水号不能为空")
+        if (StringUtil.isEmpty(billno)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "本地流水号不能为空")
+        return true
+    }
+}
+
+class InitAccParam : APIRequestParam() {
+    @Sign
+    var refno: String = ""
+    @Sign
+    var billno: String = ""
+
+    override fun checkParam(): Boolean {
+        if (StringUtil.isEmpty(refno)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "入账确认流水号不能为空")
+        if (StringUtil.isEmpty(billno)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "本地流水号不能为空")
+        return true
+    }
+}
+
 
 
 
diff --git a/src/main/kotlin/com/supwisdom/dlpay/water/api_request_param.kt b/src/main/kotlin/com/supwisdom/dlpay/water/api_request_param.kt
index e408e60..ef6476c 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/water/api_request_param.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/water/api_request_param.kt
@@ -79,19 +79,19 @@
         if (deviceno.length != 8 || deviceno.any { it !in '0'..'9' }) {
             throw RequestParamCheckException(TradeErrorCode.INPUT_DATA_ERROR, "设备ID号长度不符")
         }
-
+        if (citizenCardno.length != 8 || citizenCardno.any { it !in '0'..'9' }) {
+            throw RequestParamCheckException(TradeErrorCode.INPUT_DATA_ERROR, "市民卡号长度不符")
+        }
         if (!DateUtil.checkDatetimeValid(termdate, DateUtil.DATE_FMT)
                 || !DateUtil.checkDatetimeValid(termtime, DateUtil.TIME_FMT)) {
             throw RequestParamCheckException(TradeErrorCode.INPUT_DATA_ERROR, "设备日期时间错误")
         }
 
         if (citizenCardno.isEmpty()) {
-            throw RequestParamCheckException(TradeErrorCode.INPUT_DATA_ERROR,
-                    "市民卡号长度错误")
+            throw RequestParamCheckException(TradeErrorCode.INPUT_DATA_ERROR, "市民卡号长度错误")
         }
         if (cardphyid.isEmpty()) {
-            throw RequestParamCheckException(TradeErrorCode.INPUT_DATA_ERROR,
-                    "物理卡号长度错误")
+            throw RequestParamCheckException(TradeErrorCode.INPUT_DATA_ERROR, "物理卡号长度错误")
         }
         return true
     }
@@ -126,7 +126,7 @@
     var deviceno: String = ""
 
     @Sign
-    var billno: String = ""
+    var cobillno: Int = 0
 
 
     override fun checkParam(): Boolean {
@@ -148,7 +148,7 @@
     var transtime: String = ""
 
     @Sign
-    var billno: String = ""
+    var cobillno: Int = 0
 
     @Sign
     var amount: Int = 0
@@ -175,14 +175,64 @@
 class UserAuthRequest : APIRequestParam() {
 
     @Sign
-    var billno: String = ""
+    var cobillno: Int = 0
 
     @Sign
     var userid: String = ""
 
     override fun checkParam(): Boolean {
-        if (billno.length != 20 || billno.any { it !in '0'..'9' }) {
-            throw RequestParamCheckException(TradeErrorCode.INPUT_DATA_ERROR, "流水号长度不符")
+        return true
+    }
+}
+
+class AccdtlParam : APIRequestParam() {
+
+    @Sign
+    var deviceno: String = ""
+
+    @Sign
+    var cobillno: Int = 0
+
+    @Sign
+    var transdate: String = ""
+
+    @Sign
+    var transtime: String = ""
+
+    @Sign
+    var amount: Double = 0.0
+
+    @Sign
+    var flowsensors: Int = 0
+
+    @Sign
+    var userid: String = ""
+
+    @Sign
+    var citizenCardno: String = ""
+
+    @Sign
+    var mode: String = ""
+
+    @Sign
+    var cardPhyId: String = ""
+
+    override fun checkParam(): Boolean {
+        if (deviceno.length != 8 || deviceno.any { it !in '0'..'9' }) {
+            throw RequestParamCheckException(TradeErrorCode.INPUT_DATA_ERROR, "设备ID号长度不符")
+        }
+        if (!DateUtil.checkDatetimeValid(transdate, DateUtil.DATE_FMT)
+                || !DateUtil.checkDatetimeValid(transtime, DateUtil.TIME_FMT)) {
+            throw RequestParamCheckException(TradeErrorCode.INPUT_DATA_ERROR, "交易日期时间错误")
+        }
+        if (citizenCardno.isEmpty()) {
+            throw RequestParamCheckException(TradeErrorCode.INPUT_DATA_ERROR, "市民卡号长度错误")
+        }
+        if (cardPhyId.isEmpty()) {
+            throw RequestParamCheckException(TradeErrorCode.INPUT_DATA_ERROR, "物理卡号长度错误")
+        }
+        if (cobillno==0) {
+            throw RequestParamCheckException(TradeErrorCode.INPUT_DATA_ERROR, "采集流水号不能为空")
         }
         return true
     }
diff --git a/src/main/kotlin/com/supwisdom/dlpay/water/async_tasks.kt b/src/main/kotlin/com/supwisdom/dlpay/water/async_tasks.kt
new file mode 100644
index 0000000..2f27350
--- /dev/null
+++ b/src/main/kotlin/com/supwisdom/dlpay/water/async_tasks.kt
@@ -0,0 +1,35 @@
+package com.supwisdom.dlpay.water
+
+import mu.KotlinLogging
+import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler
+import org.springframework.context.annotation.Bean
+import org.springframework.context.annotation.Configuration
+import org.springframework.scheduling.annotation.AsyncConfigurer
+import org.springframework.scheduling.annotation.EnableAsync
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
+import java.lang.reflect.Method
+import java.util.concurrent.Executor
+
+@Configuration
+@EnableAsync
+class SpringAsyncConfig : AsyncConfigurer {
+    @Bean(value = ["waterPay"])
+    fun threadPoolExecutor(): Executor {
+        return ThreadPoolTaskExecutor().apply {
+            corePoolSize = 5
+            maxPoolSize = 10
+            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}>" }
+    }
+}
diff --git a/src/main/kotlin/com/supwisdom/dlpay/water/controller/api_controller.kt b/src/main/kotlin/com/supwisdom/dlpay/water/controller/api_controller.kt
index 55772db..67345a9 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/water/controller/api_controller.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/water/controller/api_controller.kt
@@ -1,15 +1,18 @@
 package com.supwisdom.dlpay.water.controller
 
+import com.supwisdom.dlpay.api.bean.CitizenCardPayinitParam
 import com.supwisdom.dlpay.framework.ResponseBodyBuilder
-import com.supwisdom.dlpay.framework.dao.BusinessparaDao
 import com.supwisdom.dlpay.framework.service.BusinessparaService
 import com.supwisdom.dlpay.framework.service.SystemUtilService
 import com.supwisdom.dlpay.framework.util.*
 import com.supwisdom.dlpay.system.service.UserDataService
 import com.supwisdom.dlpay.water.*
-import com.supwisdom.dlpay.water.domain.TTransdtl
+import com.supwisdom.dlpay.water.domain.TAccdtl
+import com.supwisdom.dlpay.water.domain.TCollectdtl
+import com.supwisdom.dlpay.water.pay.WaterPayAsyncTask
+import com.supwisdom.dlpay.water.service.AccdtlService
 import com.supwisdom.dlpay.water.service.DeviceService
-import com.supwisdom.dlpay.water.service.TransdtlService
+import com.supwisdom.dlpay.water.service.CollectdtlService
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.http.ResponseEntity
 import org.springframework.web.bind.annotation.*
@@ -30,7 +33,7 @@
     private lateinit var userDataService: UserDataService
 
     @Autowired
-    private lateinit var transdtlService: TransdtlService
+    private lateinit var collectdtlService: CollectdtlService
 
     @Autowired
     private lateinit var shortURLUtil: ShortURLUtil
@@ -38,6 +41,12 @@
     @Autowired
     private lateinit var businessparaService: BusinessparaService
 
+    @Autowired
+    private lateinit var waterPayAsyncTask: WaterPayAsyncTask
+
+    @Autowired
+    private lateinit var accdtlService: AccdtlService
+
     @PostMapping("/devicelogin")
     fun deviceLogin(param: DeviceLoginParam): ResponseEntity<Any> {
         try {
@@ -89,14 +98,13 @@
             //2. 通过 deviceno 查询设备费率参数
             val deviceParam = deviceService.getParaMapByDeviceno(param.deviceno)
             //3. 创建 transdtl 记录初始流水
-            val trans = TTransdtl().apply {
-                billno = systemUtilService.refno
+            val trans = TCollectdtl().apply {
                 mode = TradeDict.PAY_MODE_CARD
                 transDate = param.termdate
                 transTime = param.termtime
                 deviceno = param.deviceno
                 userid = personIdentity.person.userid
-                bankCardNo = param.citizenCardno
+                citizenCardno = param.citizenCardno
                 cardPhyId = param.cardphyid
                 amount = 0.0
                 waterSumHundredLitre = 0
@@ -104,10 +112,10 @@
                 authStatus = true
                 uploadStatus = false
             }
-            val savedTrans = transdtlService.createNewTransdtl(trans)
-            //4. 将流水 billno 和费率信息返回给终端
+            val savedTrans = collectdtlService.createNewTransdtl(trans)
+            //4. 将流水 cobillno 和费率信息返回给终端
             return ResponseEntity.ok(ResponseBodyBuilder.create()
-                    .data(WaterDeviceParam.billNo, savedTrans.billno)
+                    .data(WaterDeviceParam.cobillNo, savedTrans.cobillno)
                     .data(WaterDeviceParam.feeAmount, deviceParam[WaterDeviceParam.feeAmount]!!)
                     .data(WaterDeviceParam.waterLimit, deviceParam[WaterDeviceParam.waterLimit]!!)
                     .data(WaterDeviceParam.feestart, deviceParam[WaterDeviceParam.feestart]!!)
@@ -124,8 +132,7 @@
         try {
             val deviceParam = deviceService.getParaMapByDeviceno(param.deviceno)
             //1. 创建并记录初始流水
-            val trans = TTransdtl().apply {
-                billno = systemUtilService.refno
+            val trans = TCollectdtl().apply {
                 mode = TradeDict.PAY_MODE_QRCODE
                 transDate = param.termdate
                 transTime = param.termtime
@@ -136,13 +143,13 @@
                 authStatus = false
                 uploadStatus = false
             }
-            val savedTrans = transdtlService.createNewTransdtl(trans)
+            val savedTrans = collectdtlService.createNewTransdtl(trans)
             //2.将流水号及认证地址返回给终端
             //将认证url转为短码
             val url = shortURLUtil.doGetSinaShortUrl(
-                    businessparaService.findByParakey(WaterBudinessConstants.waterAuthUrl).paraval + savedTrans.billno)
+                    businessparaService.findByParakey(WaterBudinessConstants.waterAuthUrl).paraval + savedTrans.cobillno)
             return ResponseEntity.ok(ResponseBodyBuilder.create()
-                    .data(WaterDeviceParam.billNo, savedTrans.billno)
+                    .data(WaterDeviceParam.cobillNo, savedTrans.cobillno)
                     .data(WaterDeviceParam.url, url)
                     .data(WaterDeviceParam.validTime, deviceParam[WaterDeviceParam.validTime]!!)
                     .success())
@@ -156,13 +163,13 @@
     fun qrcodeQuery(param: QrcodeQueryRequest): ResponseEntity<Any> {
         try {
             val deviceParam = deviceService.getParaMapByDeviceno(param.deviceno)
-            val trans = transdtlService.queryTrans(param)
+            val trans = collectdtlService.queryTrans(param.cobillno)
             var authStatus = 0
             if (trans.authStatus) {
                 authStatus = 1
             }
             return ResponseEntity.ok(ResponseBodyBuilder.create()
-                    .data(WaterDeviceParam.billNo, trans.billno)
+                    .data(WaterDeviceParam.cobillNo, trans.cobillno)
                     .data(WaterDeviceParam.authStatus, authStatus)
                     //2为代扣模式
                     .data(WaterDeviceParam.payStatus, 2)
@@ -187,7 +194,7 @@
     @ResponseBody
     fun auth(@RequestBody param: UserAuthRequest): ResponseEntity<Any> {
         return try {
-            transdtlService.userAuth(param)
+            collectdtlService.userAuth(param)
             ResponseEntity.ok(ResponseBodyBuilder.create().success())
         } catch (ex: Exception) {
             ResponseEntity.ok(ResponseBodyBuilder.create()
@@ -197,9 +204,26 @@
 
     @PostMapping("/uploadrecord")
     fun transdtlUpload(param: UploadRecordRequest): ResponseEntity<Any> {
-        // 1. 根据 billno 查询 transdtl , 并加锁
-        val dtl = transdtlService.saveDeviceDtlData(param)
-        return ResponseEntity.ok(ResponseBodyBuilder.create().data(WaterDeviceParam.billNo, dtl.billno)
-                .success())
+        // 1. 根据 cobillno 查询 transdtl , 并加锁
+            val querycodtl = collectdtlService.queryTrans(param.cobillno)
+                ?: return ResponseEntity.ok(ResponseBodyBuilder.create()
+                        .fail(WaterErrorCode.DATA_NOTFOUND_ERROR, "采集流水号未找到"))
+            //  流水是否重复上传
+            if (!querycodtl.uploadStatus) {
+                val dtl = collectdtlService.saveDeviceDtlData(param)
+                userDataService.updateCoamount(dtl.citizenCardno, param.amount/100.0)
+                //  是否立即扣费
+                if (param.amount >= deviceService.getParaMapByDeviceno(param.deviceno)[WaterDeviceParam.imdDecThreshold]!!.toInt()) {
+                    //  刷卡消费
+                    if (TradeDict.PAY_MODE_CARD == dtl.mode) {
+                        //  立即异步扣费
+                        waterPayAsyncTask.waterPay(querycodtl.cobillno)
+                    }
+                }
+                return ResponseEntity.ok(ResponseBodyBuilder.create().data(WaterDeviceParam.cobillNo, dtl.cobillno)
+                        .success())
+            }
+            return ResponseEntity.ok(ResponseBodyBuilder.create().data(WaterDeviceParam.cobillNo, querycodtl.cobillno)
+                    .success())
     }
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/supwisdom/dlpay/water/controller/water_controller.kt b/src/main/kotlin/com/supwisdom/dlpay/water/controller/water_controller.kt
index c7abfc8..4cf3e21 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/water/controller/water_controller.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/water/controller/water_controller.kt
@@ -10,7 +10,7 @@
 import com.supwisdom.dlpay.water.pojo.TTransdtlDTO
 import com.supwisdom.dlpay.water.service.DeviceService
 import com.supwisdom.dlpay.water.service.AreaService
-import com.supwisdom.dlpay.water.service.TransdtlService
+import com.supwisdom.dlpay.water.service.CollectdtlService
 import com.supwisdom.dlpay.water.domain.TAreaparaGroup
 import com.supwisdom.dlpay.water.domain.TTransdtlCount
 import com.supwisdom.dlpay.water.pojo.TAreaparaBindDTO
@@ -362,7 +362,7 @@
 @Controller
 class TransdtlController {
     @Autowired
-    private lateinit var transdtlService: TransdtlService
+    private lateinit var collectdtlService: CollectdtlService
 
     @GetMapping("/transdtl/index")
     fun dtlIndexView() = "system/transdtl/index"
@@ -395,7 +395,7 @@
                 this.username = username
                 this.transtime = transtime
             }
-            transdtlService.queryTransdtlDTOByParam(searchBean)?.let {
+            collectdtlService.queryTransdtlDTOByParam(searchBean)?.let {
                 return it
             }
             return PageResult(WaterErrorCode.DATA_NOTFOUND_ERROR, "设备未找到")
@@ -431,7 +431,7 @@
                 this.areano = areano
                 this.transtime = transtime
             }
-            transdtlService.queryTransdtlCountByParam(searchBean)?.let {
+            collectdtlService.queryTransdtlCountByParam(searchBean)?.let {
                 return it
             }
             return PageResult(WaterErrorCode.DATA_NOTFOUND_ERROR, "流水统计未找到")
diff --git a/src/main/kotlin/com/supwisdom/dlpay/water/scheduler_task.kt b/src/main/kotlin/com/supwisdom/dlpay/water/scheduler_task.kt
new file mode 100644
index 0000000..60c2dd8
--- /dev/null
+++ b/src/main/kotlin/com/supwisdom/dlpay/water/scheduler_task.kt
@@ -0,0 +1,35 @@
+package com.supwisdom.dlpay.water
+
+import com.supwisdom.dlpay.water.pay.WaterPayAsyncTask
+import com.supwisdom.dlpay.water.service.CollectdtlService
+import mu.KotlinLogging
+import net.javacrumbs.shedlock.core.SchedulerLock
+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
+@EnableScheduling
+class CollectdtlQueryResultSchedulerTask {
+
+    private val logger = KotlinLogging.logger { }
+
+    @Autowired
+    private lateinit var collectdtlService: CollectdtlService
+
+    @Autowired
+    private lateinit var waterPayAsyncTask: WaterPayAsyncTask
+
+    @Scheduled(cron = "*/30 * * * * ?")
+    @SchedulerLock(name = "dealCollectdtlAccountEntry", lockAtMostForString = "PT10M")
+    fun queryCollectdtlResult() {
+        val collectdtlList = collectdtlService.queryTransdtlNotEntry()
+        if (null == collectdtlList || 0 == collectdtlList.size) {
+            return
+        }
+        for (collectdtl in collectdtlList) {
+            waterPayAsyncTask.waterPay(collectdtl.cobillno)
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/supwisdom/dlpay/water/service/transdtl_service.kt b/src/main/kotlin/com/supwisdom/dlpay/water/service/collectdtl_service.kt
similarity index 80%
rename from src/main/kotlin/com/supwisdom/dlpay/water/service/transdtl_service.kt
rename to src/main/kotlin/com/supwisdom/dlpay/water/service/collectdtl_service.kt
index 482aaf0..7799cc5 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/water/service/transdtl_service.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/water/service/collectdtl_service.kt
@@ -5,34 +5,33 @@
 import com.supwisdom.dlpay.framework.util.StringUtil
 import com.supwisdom.dlpay.framework.util.TradeDict
 import com.supwisdom.dlpay.framework.util.WaterErrorCode
-import com.supwisdom.dlpay.water.QrcodeQueryRequest
 import com.supwisdom.dlpay.water.UploadRecordRequest
 import com.supwisdom.dlpay.water.UserAuthRequest
 import com.supwisdom.dlpay.water.bean.TransdtlCountSearchBean
-import com.supwisdom.dlpay.water.dao.TransdtlDao
-import com.supwisdom.dlpay.water.domain.TTransdtl
+import com.supwisdom.dlpay.water.dao.CollectdtlDao
+import com.supwisdom.dlpay.water.domain.TCollectdtl
 import com.supwisdom.dlpay.water.pojo.TTransdtlDTO
 import com.supwisdom.dlpay.water.bean.TransdtlSearchBean
+import com.supwisdom.dlpay.water.dao.AccdtlDao
 import com.supwisdom.dlpay.water.dao.TransdtlCountDao
 import com.supwisdom.dlpay.water.domain.TTransdtlCount
+import mu.KotlinLogging
 import org.springframework.beans.factory.annotation.Autowired
-import org.springframework.data.domain.Example
-import org.springframework.data.domain.ExampleMatcher
 import org.springframework.data.domain.PageRequest
 import org.springframework.data.jpa.domain.Specification
 import org.springframework.stereotype.Service
+import java.lang.RuntimeException
 import java.util.ArrayList
 import javax.persistence.EntityManager
-import javax.persistence.Query
-import javax.persistence.criteria.CriteriaBuilder
-import javax.persistence.criteria.CriteriaQuery
 import javax.persistence.criteria.Predicate
-import javax.persistence.criteria.Root
 
 @Service
-class TransdtlServiceImpl : TransdtlService {
+class CollectdtlServiceImpl : CollectdtlService {
+
+    private val logger = KotlinLogging.logger { }
+
     @Autowired
-    private lateinit var transdtlDao: TransdtlDao
+    private lateinit var collectdtlDao: CollectdtlDao
 
     @Autowired
     private lateinit var em: EntityManager
@@ -40,13 +39,14 @@
     @Autowired
     private lateinit var transdtlCountDao: TransdtlCountDao
 
-    override fun createNewTransdtl(dtl: TTransdtl): TTransdtl {
-        transdtlDao.save(dtl)
+
+    override fun createNewTransdtl(dtl: TCollectdtl): TCollectdtl {
+        collectdtlDao.save(dtl)
         return dtl
     }
 
-    override fun saveDeviceDtlData(record: UploadRecordRequest): TTransdtl {
-        val dtl = transdtlDao.findByBillnoForUpdate(record.billno)
+    override fun saveDeviceDtlData(record: UploadRecordRequest): TCollectdtl {
+        val dtl = collectdtlDao.findByCobillnoForUpdate(record.cobillno)
                 ?: throw TransactionProcessException(WaterErrorCode.DATA_NOTFOUND_ERROR,
                         "交易订单号不存在")
         if (record.transtatus == "2") {
@@ -58,32 +58,30 @@
         dtl.waterSumHundredLitre = record.flowsensors
         dtl.uploadTime = record.transdate + record.transtime
         dtl.uploadStatus = true
-        transdtlDao.save(dtl)
+        collectdtlDao.save(dtl)
         return dtl
     }
 
-    override fun queryTrans(param: QrcodeQueryRequest): TTransdtl {
-        return transdtlDao.findByBillnoAndDeviceno(param.billno, param.deviceno)
-                ?: throw TransactionProcessException(WaterErrorCode.DATA_NOTFOUND_ERROR,
-                        "交易订单号不存在")
+    override fun queryTrans(cobillno: Int?): TCollectdtl {
+        return collectdtlDao.findByCobillnoForUpdate(cobillno)
     }
 
-    override fun userAuth(param: UserAuthRequest): TTransdtl {
-        val dtl = transdtlDao.findById(param.billno).orElse(null)
+    override fun userAuth(param: UserAuthRequest): TCollectdtl {
+        val dtl = collectdtlDao.findByCobillnoForUpdate(param.cobillno)
                 ?: throw TransactionProcessException(WaterErrorCode.DATA_NOTFOUND_ERROR,
                         "交易订单号不存在")
         dtl.userid = param.userid
         dtl.authStatus = true
-        transdtlDao.save(dtl)
+        collectdtlDao.save(dtl)
         return dtl
     }
 
     override fun queryTransdtlDTOByParam(param: TransdtlSearchBean): PageResult<TTransdtlDTO>? {
-        val sql = StringBuffer("select t1.billno,t1.amount,t1.bankcardno,t1.cardphyid,t1.deviceno,t1.mode,t1.status,t1.transdate,t1.transtime,t1.water_in_100ml water_sum_hundred_litre,t1.name username,t2.devicename,t2.areaname,t2.areano  " +
+        val sql = StringBuffer("select t1.cobillno,t1.amount,t1.bankcardno,t1.cardphyid,t1.deviceno,t1.mode,t1.status,t1.transdate,t1.transtime,t1.water_in_100ml water_sum_hundred_litre,t1.name username,t2.devicename,t2.areaname,t2.areano  " +
                 "from (select dtl.*,person.name from tb_transdtl dtl left join tb_person person on dtl.userid = person.userid) t1," +
                 "(select device.deviceno,device.devicename,area.areaname,area.areano from tb_device device,tb_area area where device.areano = area.areano) t2 " +
                 "where t1.deviceno = t2.deviceno")
-        val countSql = StringBuffer("select count(billno) " +
+        val countSql = StringBuffer("select count(cobillno) " +
                 "from (select dtl.*,person.name from tb_transdtl dtl left join tb_person person on dtl.userid = person.userid) t1," +
                 "(select device.deviceno,device.devicename,area.areaname,area.areano from tb_device device,tb_area area where device.areano = area.areano) t2 " +
                 "where t1.deviceno = t2.deviceno")
@@ -118,7 +116,7 @@
             countSql.append(" and areano  =?")
             map.put("areano", position++)
         }
-        sql.append(" order by billno desc limit " + param.pageSize + " offset " + (param.pageNo - 1) * param.pageSize)
+        sql.append(" order by cobillno desc limit " + param.pageSize + " offset " + (param.pageNo - 1) * param.pageSize)
         val query = em.createNativeQuery(sql.toString(), TTransdtlDTO::class.java)
         val countQuery = em.createNativeQuery(countSql.toString())
         map["devicename"]?.let {
@@ -177,4 +175,12 @@
         val dtlCountPage = transdtlCountDao.findAll(specification, pageable)
         return PageResult<TTransdtlCount>(dtlCountPage)
     }
+
+    override fun queryTransdtlNotEntry(): List<TCollectdtl>? {
+        return collectdtlDao.findWipCollectdtl(PageRequest.of(0,10))
+    }
+
+    override fun findByCobillnoForUpdate(cobillno: Int?): TCollectdtl {
+        return collectdtlDao.findByCobillnoForUpdate(cobillno) ?: throw RuntimeException("采集流水号:" + cobillno + "未找到")
+    }
 }
\ No newline at end of file
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 992c6c6..28dbe72 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -25,4 +25,7 @@
 ################################################
 # user password
 auth.password.bcrypt.length=10
-payapi.url=http://localhost:9000/payapi
+payapi.url=https://yy.dlsmk.cn/payapi
+#appid secret
+water.appid=700001
+water.secret=5f788ce433ec44f299351cdf7f137e81
\ No newline at end of file
diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql
index 79bc39c..ea6e5d8 100644
--- a/src/main/resources/data.sql
+++ b/src/main/resources/data.sql
@@ -1,5 +1,5 @@
-insert into tb_apiclient(appid, secret, status, roles)
-values ('100001', 'oUw2NmA09ficiVWD4TUQLDOkPyzQa3VzbjjsW0B2qTk=', 'normal', 'ROLE_THIRD_ADMIN');
+insert into tb_apiclient(appid, secret,bcrypt_secret, status, roles,thirdurl)
+values ('100001', 'oUw2NmA09ficiVWD4TUQLDOkPyzQa3VzbjjsW0B2qTk=',1, 'normal', 'ROLE_THIRD_ADMIN',1);
 INSERT INTO tb_operator(
 	operid, closedate, opendate, opercode, opername, operpwd, opertype, status,thirdadmin)
 	VALUES ('LOR2IwRkbOjp+sVG9KR2BpHZbwGKepS4', '20500101', '20190101', 'system', '系统管理员', '$2a$10$Ex9xp11.vCaD8D0a7ahiUOKqDij1TcCUBwRAmrqXeDvAkmzLibn4.', 'oper', 'normal','1');
@@ -109,12 +109,20 @@
 
 INSERT INTO "tb_devicefeeconfig"("areano", "feecfgversion", "feeconfig") VALUES (1, NULL, 1);
 INSERT INTO "tb_feeconfig"("id", "amount", "max_water_litre", "cfg_version") VALUES (1, 1, 50, NULL);
-INSERT INTO "tb_person_identity"("third_uid", "createtime", "lockflag", "lossflag", "status", "userid", "cardphyid") VALUES ('000000000000000000000000', NULL, 0, 0, '1', 'd1yctWs5+ks0iQN3m9bUvRHus6HbKbrs', '6655ec27');
+INSERT INTO "tb_person_identity"("third_uid", "createtime", "lockflag", "lossflag", "status", "userid", "cardphyid","coamount","accamount") VALUES ('25002882', NULL, 0, 0, '1', 'd1yctWs5+ks0iQN3m9bUvRHus6HbKbrs', '6655ec27',0,0);
+INSERT INTO "tb_person_identity"("third_uid", "accamount", "cardphyid", "coamount", "createtime", "lockflag", "lossflag", "status", "userid") VALUES ('25002885', 0, '6655ec27', 0, NULL, 0, 0, '1', 'f3yctKs5+bs1iMU4m8JUvPOus7SbDbrd');
 INSERT INTO "tb_person"("userid", "addr", "country", "email", "idno", "idtype", "lastsaved", "mobile", "name", "nation", "sex", "status", "tel", "zipcode") VALUES ('d1yctWs5+ks0iQN3m9bUvRHus6HbKbrs', NULL, NULL, NULL, NULL, NULL, NULL, NULL, '王富贵', NULL, NULL, '1', NULL, NULL);
-INSERT INTO "tb_businesspara"("parakey", "paraval") VALUES ('water_auth_url', 'http://172.28.43.20:8080/water/api/device/confirm?billno=');
-INSERT INTO "tb_businesspara"("parakey", "paraval") VALUES ('water_sina_shorturl', 'http://api.t.sina.com.cn/short_url/shorten.json?source=2223392143');
+INSERT INTO "tb_person"("userid", "addr", "country", "email", "idno", "idtype", "lastsaved", "mobile", "name", "nation", "sex", "status", "tel", "zipcode") VALUES ('f3yctKs5+bs1iMU4m8JUvPOus7SbDbrd', NULL, NULL, NULL, NULL, NULL, NULL, NULL, '蔡程应', NULL, NULL, '1', NULL, NULL);
 
 
+INSERT INTO "tb_businesspara"("parakey", "paraval") VALUES ('water_auth_url', 'http://172.28.43.20:8080/water/api/device/confirm?cobillno=');
+INSERT INTO "tb_businesspara"("parakey", "paraval") VALUES ('water_sina_shorturl', 'http://api.t.sina.com.cn/short_url/shorten.json?source=2223392143');
+INSERT INTO "tb_businesspara"("parakey", "paraval") VALUES ('water_shopaccno', '2000000010');
+
+INSERT INTO "tb_area"("areano", "address", "areaname", "available", "arealevel", "parentid", "remarks") VALUES (1, '测试路1号', '测试区域', 1, 1, 0, '测试');
+INSERT INTO "tb_device"("deviceid", "areano", "linecheck", "devistatus", "devicename", "deviceno", "soft_verno") VALUES (1, 1, '20190813143440', 'normal', '测试POS01', '10000001', NULL);
+INSERT INTO "tb_areapara_bind"("areano", "groupid", "lastsaved") VALUES (1, 1, '20190813143615');
+
 INSERT INTO "tb_dictionary"("dictval", "dicttype", "dictcaption", "dicttypename") VALUES ('正常', 'device_status', 'normal', '设备状态');
 INSERT INTO "tb_dictionary"("dictval", "dicttype", "dictcaption", "dicttypename") VALUES ('注销', 'device_status', 'closed', '设备状态');
 INSERT INTO "tb_dictionary"("dictval", "dicttype", "dictcaption", "dicttypename") VALUES ('签出', 'device_status', 'logout', '设备状态');
@@ -132,6 +140,8 @@
 INSERT INTO "tb_areapara"("paraname", "groupid", "maxval", "minval", "paradesc", "paraval", "valtype") VALUES ('pulseInHML', 1, '100', '1', '每百毫升流量计的脉冲数(单位:个)', '40', 'N');
 INSERT INTO "tb_areapara"("paraname", "groupid", "maxval", "minval", "paradesc", "paraval", "valtype") VALUES ('waterlimit', 1, '500', '1', '单次用水上限(单位:百毫升)', '300', 'N');
 INSERT INTO "tb_areapara"("paraname", "groupid", "maxval", "minval", "paradesc", "paraval", "valtype") VALUES ('validtime', 1, '240', '60', '二维码有效时间(单位:秒)', '180', 'N');
+INSERT INTO "tb_areapara"("paraname", "groupid", "maxval", "minval", "paradesc", "paraval", "valtype") VALUES ('imdDecThreshold', 1, '500', '1', '流水上传立即扣费阈值(单位:分)', '50', 'N');
+
 
 
 commit;
\ No newline at end of file
diff --git a/src/main/resources/templates/system/confirm/confirm.html b/src/main/resources/templates/system/confirm/confirm.html
index 6562948..5e66269 100644
--- a/src/main/resources/templates/system/confirm/confirm.html
+++ b/src/main/resources/templates/system/confirm/confirm.html
@@ -26,7 +26,7 @@
         return "d1yctWs5+ks0iQN3m9bUvRHus6HbKbrs"
     }
     var allData = {
-        billno:GetUrlRefnoPara(),
+        cobillno:GetUrlRefnoPara(),
         userid:GetUserid()
     }
     $("#button-auth").click(function () {
diff --git a/src/main/resources/templates/system/transdtl/index.html b/src/main/resources/templates/system/transdtl/index.html
index fefeb56..475a84d 100644
--- a/src/main/resources/templates/system/transdtl/index.html
+++ b/src/main/resources/templates/system/transdtl/index.html
@@ -111,7 +111,7 @@
             page: true,
             cols: [
                 [
-                    {field: 'billno', align: 'center', title: '流水号'},
+                    {field: 'cobillno', align: 'center', title: '流水号'},
                     {field: 'deviceno', align: 'center', title: '设备号'},
                     {field: 'devicename', align: 'center', title: '设备名称'},
                     {field: 'areaname', align: 'center', title: '区域'},