市民卡代扣逻辑
diff --git a/src/main/java/com/supwisdom/dlpay/api/dao/PersonIdentityDao.java b/src/main/java/com/supwisdom/dlpay/api/dao/PersonIdentityDao.java
index 26fe874..6ee3e99 100644
--- a/src/main/java/com/supwisdom/dlpay/api/dao/PersonIdentityDao.java
+++ b/src/main/java/com/supwisdom/dlpay/api/dao/PersonIdentityDao.java
@@ -1,14 +1,10 @@
 package com.supwisdom.dlpay.api.dao;
 
 import com.supwisdom.dlpay.api.domain.TPersonIdentity;
-import com.supwisdom.dlpay.api.domain.TPersonIdentityPK;
 import org.springframework.data.jpa.repository.JpaRepository;
-import org.springframework.data.jpa.repository.Query;
-import org.springframework.data.repository.query.Param;
 import org.springframework.stereotype.Repository;
 
 @Repository
-public interface PersonIdentityDao extends JpaRepository<TPersonIdentity, TPersonIdentityPK> {
-  @Query(value = "from TPersonIdentity t where t.thirdUserid=:thirdUserid and t.thirdSyscode=:thirdSyscode ")
-  TPersonIdentity getPersonIdentityById(@Param("thirdUserid") String thirdUserid, @Param("thirdSyscode") String thirdSyscode);
+public interface PersonIdentityDao extends JpaRepository<TPersonIdentity, String> {
+  TPersonIdentity getByThirdUid(String thirdUid);
 }
diff --git a/src/main/java/com/supwisdom/dlpay/api/dao/UserdtlDao.java b/src/main/java/com/supwisdom/dlpay/api/dao/UserdtlDao.java
index 4eb1196..72181db 100644
--- a/src/main/java/com/supwisdom/dlpay/api/dao/UserdtlDao.java
+++ b/src/main/java/com/supwisdom/dlpay/api/dao/UserdtlDao.java
@@ -22,4 +22,9 @@
   @QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value ="0")})
   @Query("select dtl from TUserdtl  dtl where dtl.refno = ?1")
   TUserdtl findByRefnoForUpdateNowait(String refno);
+
+  @Lock(LockModeType.PESSIMISTIC_WRITE)
+  @QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value ="0")})
+  @Query("select dtl from TUserdtl dtl where dtl.outtradeno = ?1 and dtl.shopaccno=?2 ")
+  TUserdtl findByBillnoForUpdateNowait(String billno,String shopaccno);
 }
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 73a8126..1125f8e 100644
--- a/src/main/java/com/supwisdom/dlpay/api/domain/TPersonIdentity.java
+++ b/src/main/java/com/supwisdom/dlpay/api/domain/TPersonIdentity.java
@@ -4,43 +4,45 @@
 
 @Entity
 @Table(name = "TB_PERSON_IDENTITY")
-@IdClass(TPersonIdentityPK.class)
 public class TPersonIdentity {
   @Id
-  @Column(name = "THIRD_USERID", nullable = false, length = 60)
-  private String thirdUserid;
-
-  @Id
-  @Column(name = "THIRD_SYSCODE", nullable = false, length = 20)
-  private String thirdSyscode;
+  @Column(name = "THIRD_UID", nullable = false, length = 60)
+  private String thirdUid;
 
   @ManyToOne(fetch = FetchType.LAZY)
   @JoinColumn(name = "USERID")
   private TPerson person; //绑定的系统用户
 
+  @Column(name = "STATUS", nullable = false, length = 20)
+  private String status;
+
+  @Column(name = "LOSSFLAG",nullable = false, precision = 1)
+  private Integer lossflag=0;
+
+  @Column(name = "LOCKFLAG", nullable = false, precision = 1)
+  private Integer lockflag=0;
+
+  @Column(name = "CREATETIME", length = 14)
+  private String createtime;
+
   public TPersonIdentity() {
   }
 
-  public TPersonIdentity(String thirdUserid, String thirdSyscode, TPerson person) {
-    this.thirdUserid = thirdUserid;
-    this.thirdSyscode = thirdSyscode;
+  public TPersonIdentity(String thirdUid, TPerson person, String status, Integer lossflag, Integer lockflag, String createtime) {
+    this.thirdUid = thirdUid;
     this.person = person;
+    this.status = status;
+    this.lossflag = lossflag;
+    this.lockflag = lockflag;
+    this.createtime = createtime;
   }
 
-  public String getThirdUserid() {
-    return thirdUserid;
+  public String getThirdUid() {
+    return thirdUid;
   }
 
-  public void setThirdUserid(String thirdUserid) {
-    this.thirdUserid = thirdUserid;
-  }
-
-  public String getThirdSyscode() {
-    return thirdSyscode;
-  }
-
-  public void setThirdSyscode(String thirdSyscode) {
-    this.thirdSyscode = thirdSyscode;
+  public void setThirdUid(String thirdUid) {
+    this.thirdUid = thirdUid;
   }
 
   public TPerson getPerson() {
@@ -50,4 +52,37 @@
   public void setPerson(TPerson person) {
     this.person = person;
   }
+
+  public String getStatus() {
+    return status;
+  }
+
+  public void setStatus(String status) {
+    this.status = status;
+  }
+
+  public Integer getLossflag() {
+    return lossflag;
+  }
+
+  public void setLossflag(Integer lossflag) {
+    this.lossflag = lossflag;
+  }
+
+  public Integer getLockflag() {
+    return lockflag;
+  }
+
+  public void setLockflag(Integer lockflag) {
+    this.lockflag = lockflag;
+  }
+
+  public String getCreatetime() {
+    return createtime;
+  }
+
+  public void setCreatetime(String createtime) {
+    this.createtime = createtime;
+  }
+
 }
diff --git a/src/main/java/com/supwisdom/dlpay/api/domain/TPersonIdentityPK.java b/src/main/java/com/supwisdom/dlpay/api/domain/TPersonIdentityPK.java
deleted file mode 100644
index 8ce1bfb..0000000
--- a/src/main/java/com/supwisdom/dlpay/api/domain/TPersonIdentityPK.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package com.supwisdom.dlpay.api.domain;
-
-import javax.persistence.Column;
-import javax.persistence.Embeddable;
-import javax.persistence.Id;
-import java.io.Serializable;
-
-@Embeddable
-public class TPersonIdentityPK implements Serializable {
-  @Id
-  @Column(name="THIRD_USERID", nullable = false, length = 60)
-  private String thirdUserid;
-
-  @Id
-  @Column(name="THIRD_SYSCODE", nullable = false, length = 20)
-  private String thirdSyscode;
-
-  public TPersonIdentityPK() {
-  }
-
-  public TPersonIdentityPK(String thirdUserid, String thirdSyscode) {
-    this.thirdUserid = thirdUserid;
-    this.thirdSyscode = thirdSyscode;
-  }
-
-  public String getThirdUserid() {
-    return thirdUserid;
-  }
-
-  public void setThirdUserid(String thirdUserid) {
-    this.thirdUserid = thirdUserid;
-  }
-
-  public String getThirdSyscode() {
-    return thirdSyscode;
-  }
-
-  public void setThirdSyscode(String thirdSyscode) {
-    this.thirdSyscode = thirdSyscode;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (this == o) return true;
-    if (o == null || getClass() != o.getClass()) return false;
-    TPersonIdentityPK tPersonIdentityPK = (TPersonIdentityPK) o;
-    if (thirdUserid != null ? !thirdUserid.equals(tPersonIdentityPK.getThirdUserid()) : thirdUserid != null)
-      return false;
-    if (thirdSyscode != null ? !thirdSyscode.equals(tPersonIdentityPK.getThirdSyscode()) : thirdSyscode != null)
-      return false;
-
-    return true;
-  }
-
-  @Override
-  public int hashCode() {
-    int result = thirdUserid != null ? thirdUserid.hashCode() : 0;
-    result = 31 * result + (thirdSyscode != null ? thirdSyscode.hashCode() : 0);
-    return result;
-  }
-}
diff --git a/src/main/java/com/supwisdom/dlpay/api/domain/TUserdtl.java b/src/main/java/com/supwisdom/dlpay/api/domain/TUserdtl.java
index 806c430..fc89e32 100644
--- a/src/main/java/com/supwisdom/dlpay/api/domain/TUserdtl.java
+++ b/src/main/java/com/supwisdom/dlpay/api/domain/TUserdtl.java
@@ -52,7 +52,8 @@
   @Column(name = "OUTTRADENO", length = 60)
   private String outtradeno; //第三方流水号
 
-
+  @Column(name = "SHOPACCNO", length = 20)
+  private String shopaccno;
 
   @Column(name = "OPERID", precision = 9)
   private Integer operid; //操作员ID
@@ -187,6 +188,14 @@
     this.outtradeno = outtradeno;
   }
 
+  public String getShopaccno() {
+    return shopaccno;
+  }
+
+  public void setShopaccno(String shopaccno) {
+    this.shopaccno = shopaccno;
+  }
+
   public Integer getOperid() {
     return operid;
   }
diff --git a/src/main/java/com/supwisdom/dlpay/framework/dao/ApiClientDao.java b/src/main/java/com/supwisdom/dlpay/framework/dao/ApiClientDao.java
index 4390368..e5ca834 100644
--- a/src/main/java/com/supwisdom/dlpay/framework/dao/ApiClientDao.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/dao/ApiClientDao.java
@@ -4,4 +4,5 @@
 import org.springframework.data.repository.CrudRepository;
 
 public interface ApiClientDao extends CrudRepository<TApiClient, String> {
+  TApiClient findByAppid(String appid);
 }
diff --git a/src/main/java/com/supwisdom/dlpay/framework/dao/FeetypeConfigDao.java b/src/main/java/com/supwisdom/dlpay/framework/dao/FeetypeConfigDao.java
new file mode 100644
index 0000000..b626087
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/framework/dao/FeetypeConfigDao.java
@@ -0,0 +1,13 @@
+package com.supwisdom.dlpay.framework.dao;
+
+import com.supwisdom.dlpay.framework.domain.TFeetypeConfig;
+import com.supwisdom.dlpay.framework.domain.TFeetypeConfigPK;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface FeetypeConfigDao extends JpaRepository<TFeetypeConfig, TFeetypeConfigPK> {
+  @Query("select a from TFeetypeConfig a where a.feetype=?1 and a.paytype=?2 ")
+  TFeetypeConfig getById(String feetype, String paytype);
+}
diff --git a/src/main/java/com/supwisdom/dlpay/framework/util/Subject.java b/src/main/java/com/supwisdom/dlpay/framework/util/Subject.java
index 8afbaaa..4a46b28 100644
--- a/src/main/java/com/supwisdom/dlpay/framework/util/Subject.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/util/Subject.java
@@ -68,6 +68,11 @@
    */
   public static final String SUBJNO_PAY_YKT = "112233";
 
+  /**
+   * 应收账款 - 市民卡支付款
+   */
+  public static final String SUBJNO_PAY_CITIZEN_CARD = "112234";
+
 
   //======================= 负债类 =====================//
 
diff --git a/src/main/java/com/supwisdom/dlpay/framework/util/TradeCode.java b/src/main/java/com/supwisdom/dlpay/framework/util/TradeCode.java
index c4dde6e..5c51c26 100644
--- a/src/main/java/com/supwisdom/dlpay/framework/util/TradeCode.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/util/TradeCode.java
@@ -4,7 +4,7 @@
  * 交易码、交易类型
  * */
 public class TradeCode {
-  public static final int TRANSCODE_PAY = 6630;
+  public static final int TRANSCODE_PAY = 3000;
   public static final int TRANSCODE_YKTPAY=1000;
   public static final int TRANSCODE_WECHAT=1001;
 
diff --git a/src/main/java/com/supwisdom/dlpay/framework/util/TradeDict.java b/src/main/java/com/supwisdom/dlpay/framework/util/TradeDict.java
index 6b45836..2b392b3 100644
--- a/src/main/java/com/supwisdom/dlpay/framework/util/TradeDict.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/util/TradeDict.java
@@ -44,6 +44,9 @@
    */
   public static final String PAYTYPE_CASH = "cash";
   public static final String PAYTYPE_BALANCE = "balance";
+  public static final String PAYTYPE_ALIPAY = "alipay"; //市民卡
+  public static final String PAYTYPE_WECHAT = "wechat"; //市民卡
+  public static final String PAYTYPE_CITIZEN_CARD = "citizenCard"; //市民卡
 
 
   /**
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 7ef7051..a8139c9 100644
--- a/src/main/java/com/supwisdom/dlpay/framework/util/TradeErrorCode.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/util/TradeErrorCode.java
@@ -84,6 +84,20 @@
    * */
   public static final int LOCK_READ_TIMEOUT = 10015;
 
+  /**
+   *  卡已挂失
+   * */
+  public static final int ACCOUNT_IS_LOSS = 10016;
+
+  /**
+   *  卡已锁定
+   * */
+  public static final int ACCOUNT_IS_LOCKED = 10017;
+
+  /**
+   * 费用类别未定义
+   * */
+  public static final int FEETYPE_NOT_EXISTS = 10018;
 
   /**
    * 请求参数错误
@@ -107,5 +121,8 @@
 
   public static final int BUSINESS_SHOP_EXISTS = 30001; //商户已经存在
 
+  public static final int BUSINESS_APPID_NOTFOUND = 30002; //APPID没找到
+
+  public static final int BUSINESS_PAYTYPE_NOSUPPORT = 30003; //支付方式不支持
 
 }
diff --git a/src/main/java/com/supwisdom/dlpay/util/ConstantUtil.java b/src/main/java/com/supwisdom/dlpay/util/ConstantUtil.java
index 13af83c..1bf5ac2 100644
--- a/src/main/java/com/supwisdom/dlpay/util/ConstantUtil.java
+++ b/src/main/java/com/supwisdom/dlpay/util/ConstantUtil.java
@@ -21,4 +21,9 @@
 
     public static final int SHOPTYPE_GROUP = 0; //商户组
     public static final int SHOPTYPE_LEAF = 1;  //末级商户,独立核算商户
+
+    public static final String FEETYPE_DEFAULT = "none";
+    public static final String FEETYPE_MEALER = "mealer";
+    public static final String FEETYPE_DISCOUNT = "discount";
+    public static final String[] FEETYPE_DICTS = {"none", "mealer", "discount"}; //联动
 }
diff --git a/src/main/kotlin/com/supwisdom/dlpay/api/ThirdPayCall.kt b/src/main/kotlin/com/supwisdom/dlpay/api/ThirdPayCall.kt
index 2b3b6ee..d02ba57 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/api/ThirdPayCall.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/api/ThirdPayCall.kt
@@ -11,9 +11,15 @@
 import com.supwisdom.dlpay.framework.util.*
 import com.supwisdom.dlpay.util.Code
 
-/**
- * Created by shuwei on 2019/4/11.
- */
+class CallBackResp {
+    var retcode: String = "99"
+    var retmsg: String? = null
+    val data = mutableMapOf<String, String>()
+    fun add(key: String, value: String) {
+        this.data.plus(mapOf(key to value))
+    }
+}
+
 class CallService {
 
     companion object {
@@ -227,5 +233,11 @@
                 }
             }
         }
+
+        fun CallCitizenCardPay(config: Map<String, String?>, paydtl: TUserdtl): CallBackResp {
+            val resp = CallBackResp()
+            // TODO: 代扣逻辑
+            return resp
+        }
     }
 }
\ No newline at end of file
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 d1f8c99..9087149 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
@@ -8,7 +8,7 @@
 import com.supwisdom.dlpay.util.ConstantUtil
 
 open class APIRequestParam {
-    open val param_map = mutableMapOf<String, String>()
+    open val param_map = mutableMapOf<String, String?>()
 
     open fun checkSign(key: String): Boolean {
         val sign = param_map["sign"]
@@ -26,11 +26,9 @@
 }
 
 
-
 // ============================ USER ============================ //
 class OpenUserParam : APIRequestParam() {
-    var syscode: String = "" //必传
-    var uid: String = ""    //必传
+    var uid: String = ""    //第三方用户ID,必传
     var name: String = ""   //必传
     var sex: String? = null
     var idtype: String = "" //必传
@@ -44,7 +42,6 @@
     var sign_type: String? = null
 
     fun checkParam(): Boolean {
-        if (StringUtil.isEmpty(syscode)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "子系统注册代码不能为空")
         if (StringUtil.isEmpty(uid)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "用户唯一号不能为空")
         if (StringUtil.isEmpty(name)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "姓名不能为空")
         if (!StringUtil.isEmpty(sex) && ConstantUtil.SEX_MALE != sex && ConstantUtil.SEX_FEMALE != sex) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "性别非法[male|female]")
@@ -54,29 +51,26 @@
         if (!StringUtil.isEmpty(mobile) && !StringUtil.isMobile(mobile)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "手机号格式错误")
         if (!StringUtil.isEmpty(email) && !StringUtil.isEmail(email)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "邮箱格式错误")
 
-        param_map.plus(mapOf("syscode" to syscode, "uid" to uid, "name" to name, "sex" to sex, "idtype" to idtype, "idno" to idno, "mobile" to mobile, "tel" to tel, "email" to email, "address" to address, "zipcode" to zipcode, "sign" to sign, "sign_type" to sign_type))
+        param_map.plus(mapOf("uid" to uid, "name" to name, "sex" to sex, "idtype" to idtype, "idno" to idno, "mobile" to mobile, "tel" to tel, "email" to email, "address" to address, "zipcode" to zipcode, "sign" to sign, "sign_type" to sign_type))
         return true
     }
 }
 
 class QueryUserParam : APIRequestParam() {
-    var syscode: String = "" //必传
     var userid: String? = null  // 用户ID二选一 (两者都传取userid)
     var uid: String? = null    // 用户ID二选一
     var sign: String = "" //必传
     var sign_type: String? = null
 
     fun checkParam(): Boolean {
-        if (StringUtil.isEmpty(syscode)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "子系统注册代码不能为空")
         if (StringUtil.isEmpty(userid) && StringUtil.isEmpty(uid)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "用户唯一号不能为空")
 
-        param_map.plus(mapOf("syscode" to syscode, "userid" to userid, "uid" to uid, "sign" to sign, "sign_type" to sign_type))
+        param_map.plus(mapOf("userid" to userid, "uid" to uid, "sign" to sign, "sign_type" to sign_type))
         return true
     }
 }
 
 class ModifyUserParam : APIRequestParam() {
-    var syscode: String = "" //必传
     var userid: String? = null  // 用户ID二选一 (两者都传取userid)
     var uid: String? = null    // 用户ID二选一
     var name: String? = null
@@ -92,7 +86,6 @@
     var sign_type: String? = null
 
     fun checkParam(): Boolean {
-        if (StringUtil.isEmpty(syscode)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "子系统注册代码不能为空")
         if (StringUtil.isEmpty(userid) && StringUtil.isEmpty(uid)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "用户唯一号不能为空")
         if (!StringUtil.isEmpty(sex) && ConstantUtil.SEX_MALE != sex && ConstantUtil.SEX_FEMALE != sex) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "性别非法[male|female]")
         if (!StringUtil.isEmpty(idtype) && !ConstantUtil.IDTYPE_DICTS.contains(idtype)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "证件类型非法")
@@ -103,16 +96,14 @@
         if (!StringUtil.isEmpty(email) && !StringUtil.isEmail(email)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "邮箱格式错误")
 
 
-        param_map.plus(mapOf("syscode" to syscode, "userid" to userid, "uid" to uid, "name" to name, "sex" to sex, "idtype" to idtype, "idno" to idno, "mobile" to mobile, "tel" to tel, "email" to email, "address" to address, "zipcode" to zipcode, "sign" to sign, "sign_type" to sign_type))
+        param_map.plus(mapOf("userid" to userid, "uid" to uid, "name" to name, "sex" to sex, "idtype" to idtype, "idno" to idno, "mobile" to mobile, "tel" to tel, "email" to email, "address" to address, "zipcode" to zipcode, "sign" to sign, "sign_type" to sign_type))
         return true
     }
 }
 
 
-
 // ============================ SHOP ============================ //
 class OpenShopParam : APIRequestParam() {
-    var syscode: String = "" //必传
     var shopUniqueId: String = "" //必传
     var shoptype: Int = 1
     var fshopid: Int? = null
@@ -128,7 +119,6 @@
     var sign_type: String? = null
 
     fun checkParam(): Boolean {
-        if (StringUtil.isEmpty(syscode)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "子系统注册代码不能为空")
         if (StringUtil.isEmpty(shopUniqueId)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "商户唯一号不能为空")
         if (ConstantUtil.SHOPTYPE_GROUP != shoptype && ConstantUtil.SHOPTYPE_LEAF != shoptype) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "请指定商户类型")
         if (StringUtil.isEmpty(shopname)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "商户名称不能为空")
@@ -138,13 +128,12 @@
         if (!StringUtil.isEmpty(mobile) && !StringUtil.isMobile(mobile)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "手机号格式错误")
         if (!StringUtil.isEmpty(email) && !StringUtil.isEmail(email)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "邮箱格式错误")
 
-        param_map.plus(mapOf("syscode" to syscode, "shopUniqueId" to shopUniqueId, "shoptype" to shoptype, "fshopid" to fshopid, "shopname" to shopname, "contactman" to contactman, "idtype" to idtype, "idno" to idno, "mobile" to mobile, "email" to email, "address" to address, "zipcode" to zipcode, "sign" to sign, "sign_type" to sign_type))
+        param_map.plus(mapOf("shopUniqueId" to shopUniqueId, "shoptype" to shoptype, "fshopid" to fshopid, "shopname" to shopname, "contactman" to contactman, "idtype" to idtype, "idno" to idno, "mobile" to mobile, "email" to email, "address" to address, "zipcode" to zipcode, "sign" to sign, "sign_type" to sign_type))
         return true
     }
 }
 
 class QueryShopParam : APIRequestParam() {
-    var syscode: String = "" //必传
     var shopid: Int? = null  //注册时返回的shopid
     var shopaccno: String? = null  //注册时返回的shopaccno
     var shopUniqueId: String? = null //注册传的商户唯一号
@@ -152,39 +141,69 @@
     var sign_type: String? = null
 
     fun checkParam(): Boolean {
-        if (StringUtil.isEmpty(syscode)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "子系统注册代码不能为空")
         if (StringUtil.isEmpty(shopUniqueId) && null == shopid && StringUtil.isEmpty(shopaccno)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "商户唯一标志不能为空")
 
-        param_map.plus(mapOf("syscode" to syscode, "shopUniqueId" to shopUniqueId, "shopid" to shopid, "shopaccno" to shopaccno, "sign" to sign, "sign_type" to sign_type))
+        param_map.plus(mapOf("shopUniqueId" to shopUniqueId, "shopid" to shopid, "shopaccno" to shopaccno, "sign" to sign, "sign_type" to sign_type))
         return true
     }
 }
 
 
 // ============================ CONSUME ============================ //
-class BankcardPayinitParam :  APIRequestParam() {
-    var syscode: String = "" //必传
-    var cardNo: String = "" //必传
-    var amount: Int = 0 //必传
-    var shopaccno: String = "" //必传
-    var paytype: String ="" //必传
-    var billno: String ="" //必传
-    var transdate: String="" //必传
-    var transtime: String="" //必传
+class ConsumeFeetype {
+    var feetype: String = ""
+    var amount: Int = 0
+}
+
+class QueryDtlResultParam : APIRequestParam() {
+    var refno:String?=null //二选一
+    var billno:String?=null //二选一 (billno+shopaccno) 传billno时,shopaccno必传
+    var shopaccno: String?=null
     var sign: String = "" //必传
     var sign_type: String? = null
 
     fun checkParam(): Boolean {
-        if (StringUtil.isEmpty(syscode)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "子系统注册代码不能为空")
-        if (StringUtil.isEmpty(cardNo)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "卡唯一号不能为空")
-        if (amount <= 0) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "交易金额必须大于零")
-        if(StringUtil.isEmpty(shopaccno)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "请指定交易商户")
-        if(StringUtil.isEmpty(paytype)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "请指定支付方式")
-        if(StringUtil.isEmpty(billno)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "对接系统唯一订单号不能为空")
-        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(refno) && (StringUtil.isEmpty(billno) || StringUtil.isEmpty(shopaccno))) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "流水唯一号不能为空")
 
-        param_map.plus(mapOf("syscode" to syscode, "cardNo" to cardNo, "amount" to amount, "shopaccno" to shopaccno,"paytype" to paytype,"billno" to billno,"transdate" to transdate,"transtime" to transtime, "sign" to sign, "sign_type" to sign_type))
+        param_map.plus(mapOf("refno" to refno, "billno" to billno, "shopaccno" to shopaccno,  "sign" to sign, "sign_type" to sign_type))
+        return true
+    }
+}
+
+class CitizenCardPayinitParam : APIRequestParam() {
+    var cardNo: String = "" //必传
+    var shopaccno: String = "" //必传
+    var amount: Int = 0 //必传
+    var feelist: List<ConsumeFeetype>? = null// 的json字符串
+    var billno: String = "" //必传
+    var transdate: String = "" //必传
+    var transtime: String = "" //必传
+    var extend_data: String? = null //扩展参数,原样返回
+    var sign: String = "" //必传
+    var sign_type: String? = null
+
+    fun checkParam(): Boolean {
+        if (StringUtil.isEmpty(cardNo)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "卡唯一号不能为空")
+        if (StringUtil.isEmpty(shopaccno)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "请指定交易商户")
+        if (amount <= 0) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "交易金额必须大于零")
+        if (StringUtil.isEmpty(billno)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "对接系统唯一订单号不能为空")
+        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]")
+
+        param_map.plus(mapOf("cardNo" to cardNo, "amount" to amount, "feelist" to feelist, "shopaccno" to shopaccno, "billno" to billno, "transdate" to transdate, "transtime" to transtime, "sign" to sign, "sign_type" to sign_type))
+        return true
+    }
+}
+
+class CitizenCardPayfinishParam : APIRequestParam() {
+    var refno:String=""
+    var sign: String = "" //必传
+    var sign_type: String? = null
+
+    fun checkParam(): Boolean {
+        if (StringUtil.isEmpty(refno)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "交易参考号不能为空")
+
+        param_map.plus(mapOf("refno" to refno, "sign" to sign, "sign_type" to sign_type))
         return true
     }
 }
diff --git a/src/main/kotlin/com/supwisdom/dlpay/api/comsume_builder.kt b/src/main/kotlin/com/supwisdom/dlpay/api/comsume_builder.kt
index 4ba03d4..94e5a08 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/api/comsume_builder.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/api/comsume_builder.kt
@@ -6,9 +6,9 @@
 import com.supwisdom.dlpay.api.service.AccountUtilServcie
 import com.supwisdom.dlpay.api.service.PersonBalancePayService
 import com.supwisdom.dlpay.exception.TransactionCheckException
+import com.supwisdom.dlpay.framework.domain.TFeetypeConfig
 import com.supwisdom.dlpay.framework.domain.TShopacc
 import com.supwisdom.dlpay.framework.domain.TSubject
-import com.supwisdom.dlpay.framework.domain.TTranstype
 import com.supwisdom.dlpay.framework.util.*
 
 class AccountHolder<T> private constructor(val accountId: String, val idType: Int) {
@@ -16,7 +16,7 @@
         const val IDTYPE_PERSON = 1
         const val IDTYPE_SHOP = 2
         const val IDTYPE_SUBJECT = 3
-        const val IDTYPE_TRANSTYPE = 4
+        const val IDTYPE_FEETYPE = 4
 
         fun person(userid: String): AccountHolder<TAccount> {
             return AccountHolder(userid, IDTYPE_PERSON)
@@ -30,8 +30,8 @@
             return AccountHolder(subjNo, IDTYPE_SUBJECT)
         }
 
-        fun transType(transType: Int): AccountHolder<TTranstype> {
-            return AccountHolder("$transType", IDTYPE_TRANSTYPE)
+        fun feetype(feetype: String, paytype: String): AccountHolder<TFeetypeConfig> {
+            return AccountHolder("$feetype@$paytype", IDTYPE_FEETYPE)
         }
     }
 
@@ -52,7 +52,7 @@
             IDTYPE_PERSON -> builder.accountUtil.readAccountForUpdateNowait(accountId)
             IDTYPE_SHOP -> builder.accountUtil.readShopAcc(accountId.toInt())
             IDTYPE_SUBJECT -> builder.accountUtil.readSubject(accountId)
-            IDTYPE_TRANSTYPE -> builder.accountUtil.readTranstype(accountId.toInt())
+            IDTYPE_FEETYPE -> builder.accountUtil.readFeetype(accountId.split("@")[0], accountId.split("@")[1])
             else -> throw TransactionCheckException(TradeErrorCode.INPUT_DATA_ERROR, "账户类型未知type<$idType>")
         } as T
     }
@@ -63,7 +63,7 @@
             IDTYPE_PERSON -> builder.accountUtil.readAccountForUpdateNowait(accountId)
             IDTYPE_SHOP -> builder.accountUtil.readShopAcc(accountId.toInt())
             IDTYPE_SUBJECT -> builder.accountUtil.readSubject(accountId)
-            IDTYPE_TRANSTYPE -> builder.accountUtil.readTranstype(accountId.toInt())
+            IDTYPE_FEETYPE -> builder.accountUtil.readFeetype(accountId.split("@")[0], accountId.split("@")[1])
             else -> throw TransactionCheckException(TradeErrorCode.INPUT_DATA_ERROR, "账户类型未知type<$idType>")
         } as T
     }
@@ -83,6 +83,9 @@
     // 以下为输入参数,调用接口时指定的参数值
     lateinit var person: TPerson
     lateinit var tradetype: Tradetype
+    lateinit var refno: String
+    lateinit var status: String
+    val resultMap = mutableMapOf<String, String>() //存调第三方结果数据
 
     var transcode = 0
 
@@ -158,8 +161,18 @@
         return this
     }
 
-    fun setTradeno(outtradeno: String): PersonTransBuilder {
-        this.outtradeno = outtradeno
+    fun setRefno(refno: String): PersonTransBuilder {
+        this.refno = refno
+        return this
+    }
+
+    fun addResult(key: String, value: String): PersonTransBuilder {
+        this.resultMap.plus(mapOf(key to value))
+        return this
+    }
+
+    fun addResult(param: Map<String, String>): PersonTransBuilder {
+        this.resultMap.plus(param)
         return this
     }
 
@@ -276,10 +289,10 @@
         return this
     }
 
-    fun addDetail(accountHolder: AccountHolder<TTranstype>,
+    fun addDetail(accountHolder: AccountHolder<TFeetypeConfig>,
                   amount: Double): PersonTransBuilder {
         accountHolder.builder = this
-        val transtype = accountHolder.get<TTranstype>()
+        val transtype = accountHolder.get<TFeetypeConfig>()
 
         var debitAccNo = ""
         var debitSubjNo = ""
@@ -301,11 +314,11 @@
 
         if (debitAccNo.isEmpty()) {
             throw TransactionCheckException(TradeErrorCode.INPUT_DATA_ERROR,
-                    "交易配置<${transtype.transtype}> 借方账号配置错误")
+                    "交易配置<${transtype.feetype}@${transtype.paytype}> 借方账号配置错误")
         }
         if (creditAccNo.isEmpty()) {
             throw TransactionCheckException(TradeErrorCode.INPUT_DATA_ERROR,
-                    "交易配置<${transtype.transtype}> 贷方账号配置错误")
+                    "交易配置<${transtype.feetype}@${transtype.paytype}> 贷方账号配置错误")
         }
         this.details.add(TransDetail(debitAccNo, debitSubjNo, creditAccNo, creditSubjNo,
                 amount, transtype.summary, this.details.size + 1))
@@ -313,32 +326,37 @@
     }
 
     /**
-     * 单步交易,一次完成交易记账过程
-     * @param service
-     * @param isFinished - true : 完成交易过程,扣除账户余额; false - 完成检查
+     * 一步交易完成
      */
-    fun done(service: PersonBalancePayService, isFinished: Boolean): TUserdtl {
+    fun done(service: PersonBalancePayService): TUserdtl {
         prepareData()
         preCheckAccount()
-        return when (isFinished) {
-            true -> service.process(this)
-            false -> service.init(this)
-        }
+        return service.process(this)
     }
 
-    /**
-     * 两步交易,在 paydtl 基础完成确认过程
-     * @param paydtl
-     * @param status - 完成交易状态,见 TradeDict.DTL_STATUS_FAIL
-     */
-    fun done(paydtl: TUserdtl, status: String, service: PersonBalancePayService): TUserdtl {
-        return service.finish(paydtl, status, null)
+    fun init(service: PersonBalancePayService) : TUserdtl{
+        prepareData()
+        preCheckAccount()
+        return service.init(this)
     }
 
-    fun done(refno: String, status: String, service: PersonBalancePayService): TUserdtl {
-        return service.finish(refno, status, null)
+    fun wip(service: PersonBalancePayService): TUserdtl {
+        if (null == this.refno)
+            throw TransactionCheckException(TradeErrorCode.INPUT_DATA_ERROR, "交易参考号<refno>未指定")
+        return service.wip(this)
     }
-    fun done(refno: String, status: String, businessData: Map<String, String>?,service: PersonBalancePayService): TUserdtl {
-        return service.finish(refno, status, businessData)
+
+    fun finish(service: PersonBalancePayService, status: String): TUserdtl {
+        if (null == this.refno)
+            throw TransactionCheckException(TradeErrorCode.INPUT_DATA_ERROR, "交易参考号<refno>未指定")
+        this.status = status
+        return service.finish(this)
+    }
+
+    fun success(service: PersonBalancePayService): TUserdtl{
+        if (null == this.refno)
+            throw TransactionCheckException(TradeErrorCode.INPUT_DATA_ERROR, "交易参考号<refno>未指定")
+        this.status = TradeDict.DTL_STATUS_SUCCESS
+        return service.finish(this)
     }
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/supwisdom/dlpay/api/controller/consume_api_controller.kt b/src/main/kotlin/com/supwisdom/dlpay/api/controller/consume_api_controller.kt
index 3717a2b..debf0e5 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/api/controller/consume_api_controller.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/api/controller/consume_api_controller.kt
@@ -3,11 +3,14 @@
 import com.supwisdom.dlpay.api.AccountHolder
 import com.supwisdom.dlpay.api.CallService
 import com.supwisdom.dlpay.api.PersonTransBuilder
-import com.supwisdom.dlpay.api.bean.BankcardPayinitParam
+import com.supwisdom.dlpay.api.bean.CitizenCardPayfinishParam
+import com.supwisdom.dlpay.api.bean.CitizenCardPayinitParam
+import com.supwisdom.dlpay.api.bean.QueryDtlResultParam
 import com.supwisdom.dlpay.api.service.*
 import com.supwisdom.dlpay.exception.RequestParamCheckException
 import com.supwisdom.dlpay.exception.TransactionException
 import com.supwisdom.dlpay.framework.ResponseBodyBuilder
+import com.supwisdom.dlpay.framework.service.CommonService
 import com.supwisdom.dlpay.framework.service.SystemUtilService
 import com.supwisdom.dlpay.framework.util.*
 import com.supwisdom.dlpay.util.ConstantUtil
@@ -15,6 +18,8 @@
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.http.ResponseEntity
 import org.springframework.web.bind.annotation.*
+import javax.servlet.http.HttpServletRequest
+import javax.servlet.http.HttpServletResponse
 
 @RestController
 @RequestMapping("/api/consume")
@@ -31,228 +36,352 @@
     lateinit var systemUtilService: SystemUtilService
     @Autowired
     lateinit var consumePayService: ConsumePayService
+    @Autowired
+    lateinit var commonService: CommonService
 
-    @PostMapping("/bankcard/payinit")
-    fun bankcardPayinit(@RequestBody request: BankcardPayinitParam): ResponseEntity<Any> {
-        return try{
-            if (request.checkParam() && request.checkSign(systemUtilService.getSubsystemSignKey(request.syscode))) {
+    /**
+     * 流水结果查询统一接口
+     * */
+    fun queryDtlResult(@RequestBody param: QueryDtlResultParam, request: HttpServletRequest, response: HttpServletResponse): ResponseEntity<Any> {
+        return try {
+            if (param.checkParam() && param.checkSign(commonService.getAppidSecretByRequest(request))) {
                 ResponseEntity.ok(ResponseBodyBuilder.create()
                         .fail(TradeErrorCode.REQUEST_SIGN_ERROR, "参数签名错误"))
             }
-            if (!consumePayService.checkShopPaytype(request.shopaccno, request.paytype)) {
+
+            val dtl = if (StringUtil.isEmpty(param.refno)) {
+                personBalancePayService.getUserdtlForUpdateNowait(param.refno!!)
+            } else {
+                personBalancePayService.getUserdtlByBillnoForUpdateNowait(param.billno!!, param.shopaccno!!)
+            }
+            val person = dtl.userid?.let { userService.findPersonByUserid(dtl.userid) }
+            ResponseEntity.ok(ResponseBodyBuilder.create()
+                    .data("refno", dtl.refno)
+                    .data("amount", dtl.amount)
+                    .data("paytype", dtl.paytype)
+                    .data("payinfo", dtl.payinfo)
+                    .also {
+                        if (null != person) {
+                            it.data("name", person.name)
+                        }
+                    }
+                    .success("查询成功"))
+
+        } catch (ex: RequestParamCheckException) {
+            ResponseEntity.ok(ResponseBodyBuilder.create()
+                    .requestException(ex, "请求参数错误"))
+        } catch (et: TransactionException) {
+            ResponseEntity.ok(ResponseBodyBuilder.create()
+                    .transException(et, "查询错误"))
+        }
+
+    }
+
+    /**
+     * 市民卡交易初始化
+     * */
+    @PostMapping("/citizencard/payinit")
+    fun citizencardPayinit(@RequestBody param: CitizenCardPayinitParam, request: HttpServletRequest, response: HttpServletResponse): ResponseEntity<Any> {
+        return try {
+            if (param.checkParam() && param.checkSign(commonService.getAppidSecretByRequest(request))) {
                 ResponseEntity.ok(ResponseBodyBuilder.create()
-                        .fail(TradeErrorCode.INPUT_DATA_ERROR, "支付方式不支持"))
+                        .fail(TradeErrorCode.REQUEST_SIGN_ERROR, "参数签名错误"))
             }
 
-
-
-
-
+            val person = userService.findPersonByIdentityCheckStatus(param.cardNo)
+            val dtl = PersonTransBuilder.newBuilder(accountUtilServcie)
+                    .chooseTradetype(Tradetype.CONSUME) //消费
+                    .setOwner(person) //记名
+                    .setTransinfo(TradeCode.TRANSCODE_PAY, "支付交易")
+                    .setTransDatetime(param.transdate, param.transtime) //交易时间
+                    .selectPaytype(TradeDict.PAYTYPE_CITIZEN_CARD, param.cardNo)
+                    .addDetail(AccountHolder.subject(Subject.SUBJNO_PAY_CITIZEN_CARD),
+                            AccountHolder.shop(param.shopaccno),
+                            param.amount / 100.0, "市民卡代扣消费")
+                    .also { builder ->
+                        param.feelist?.forEach {
+                            builder.addDetail(AccountHolder.feetype(it.feetype, TradeDict.PAYTYPE_CITIZEN_CARD)
+                                    .with(AccountHolder.shop(param.shopaccno))
+                                    .with(AccountHolder.subject(Subject.SUBJNO_PAY_CITIZEN_CARD))
+                                    , it.amount / 100.0)
+                        }
+                    }
+                    .init(personBalancePayService)
 
             ResponseEntity.ok(ResponseBodyBuilder.create()
-                    .data("refno","")
+                    .data("refno", dtl.refno)
+                    .data("amount", dtl.amount)
                     .success("交易初始化成功"))
-        }catch (ex: RequestParamCheckException) {
+
+        } catch (ex: RequestParamCheckException) {
             ResponseEntity.ok(ResponseBodyBuilder.create()
                     .requestException(ex, "请求参数错误"))
         } catch (et: TransactionException) {
             ResponseEntity.ok(ResponseBodyBuilder.create()
                     .transException(et, "业务处理错误"))
         }
-
-    }
-
-
-
-
-// ============================================== //
-
-    @PostMapping("/account/pay")
-    fun accountPay(userid: String, amount: Int, manageFee: Int): ResponseEntity<Any> {
-        val dtl = PersonTransBuilder.newBuilder(accountUtilServcie)
-                .setTransDatetime("20190411", "112311")
-                .enableOverdraft(false)
-                .addDetail(AccountHolder.person(userid),
-                        AccountHolder.shop("12323"),
-                        amount / 100.0, "")
-                .addDetail(AccountHolder.person(userid), AccountHolder.transType(301),
-                        manageFee / 100.0, "")
-                .done(personBalancePayService, true)
-        return ResponseEntity.ok(dtl)
-    }
-
-    @GetMapping("/account/payinit")
-    fun accountPayInit(userid: String, amount: Int, manageFee: Int): ResponseEntity<Any> {
-        val dtl = PersonTransBuilder.newBuilder(accountUtilServcie)
-                .setTransDatetime("20190411", "112311")
-                .enableOverdraft(false)
-                .addDetail(AccountHolder.person(userid),
-                        AccountHolder.shop("12323"),
-                        amount / 100.0, "")
-                .addDetail(AccountHolder.person(userid), AccountHolder.transType(301),
-                        manageFee / 100.0, "")
-                .done(personBalancePayService, false)
-
-        return ResponseEntity.ok(dtl)
-    }
-
-    @GetMapping("/account/payfinish")
-    fun accountPayFinish(refno: String): ResponseEntity<Any> {
-        val dtl = PersonTransBuilder.newBuilder(accountUtilServcie)
-                .done(refno, TradeDict.DTL_STATUS_SUCCESS, personBalancePayService)
-        return ResponseEntity.ok(dtl)
-    }
-
-    @PostMapping("/ykt/payinit")
-    fun yktPayInit(userid: String, amount: Int, manageFee: Int,
-                   stuempno: String, shopid: String, transdate: String, transtime: String,
-                   outtradeno: String, payinfo: String, feetype: String): ResponseEntity<Any> {
-        //一卡通支付款 112240
-        return try {
-            val paytype = paytypeService.getByPaytype(PaytypeUtil.YKTPAY)
-            if (paytype == null || ConstantUtil.ENABLE_YES != paytype.enable) {
-                ResponseEntity.ok(ResponseBodyBuilder.create()
-                        .fail(1, "支付方式未开启"))
-            }
-            val person = userService.findByThirdUniqueIdenty(stuempno,"")
-            val dtl = PersonTransBuilder.newBuilder(accountUtilServcie)
-                    .setTransDatetime(transdate, transtime)
-                    .selectPaytype(PaytypeUtil.YKTPAY, payinfo)
-                    .setOuttradeno(outtradeno)
-                    .also {
-                        if (null != person) it.setOwner(person)
-                    }
-                    .tryLock(true)
-                    .setTransinfo(TradeCode.TRANSCODE_YKTPAY, "一卡通支付")
-                    .chooseTradetype(Tradetype.CONSUME)
-                    .also {
-                        when (feetype) {
-                            TradeDict.FEETYPE_CONSUME_MEALER -> {
-                                it.addDetail(AccountHolder.subject(Subject.SUBJNO_PAY_YKT),
-                                        AccountHolder.shop(shopid),
-                                        amount / 100.0, "一卡通支付")
-                                        .addDetail(AccountHolder.transType(TranstypeCode.TT_CONSUUME_MANAGE_FEE)
-                                                .with(AccountHolder.shop(shopid)),
-                                                manageFee / 100.0)
-                            }
-                            TradeDict.FEETYPE_CONSUME_DISCOUNT -> {
-                                it.addDetail(AccountHolder.subject(Subject.SUBJNO_PAY_YKT),
-                                        AccountHolder.shop(shopid),
-                                        (amount - manageFee) / 100.0, "一卡通支付")
-                                        .addDetail(AccountHolder.subject(Subject.SUBJNO_CONSUME_DISCOUNT),
-                                                AccountHolder.shop(shopid),
-                                                manageFee / 100.0, "优惠折扣")
-                            }
-                            else -> {
-                                it.addDetail(AccountHolder.subject(Subject.SUBJNO_PAY_YKT),
-                                        AccountHolder.shop(shopid),
-                                        amount / 100.0, "一卡通支付")
-                            }
-                        }
-                    }.done(personBalancePayService, false)
-            ResponseEntity.ok(ResponseBodyBuilder.create()
-                    .data("refno", dtl.refno)
-                    .success())
-        } catch (e: TransactionException) {
-            ResponseEntity.ok(ResponseBodyBuilder.create()
-                    .transException(e, "交易初始化异常"))
-        }
-    }
-
-    @PostMapping("/ykt/payfinish")
-    fun yktPayFinish(refno: String, yktshopid: String, devphyid: String?): ResponseEntity<Any> {
-        return try {
-            val dtl = personBalancePayService.wip(refno)
-            val person = userService.findPersonByUserid(dtl.userid)
-            val code = CallService.callYktPay(paytypeService.getPaytypeConfigByPaytype(PaytypeUtil.YKTPAY),
-                    dtl, DateUtil.getNow(), "", yktshopid, devphyid)
-            if (code.retcode == "0") {
-                PersonTransBuilder.newBuilder(accountUtilServcie)
-                        .done(dtl.refno, TradeDict.DTL_STATUS_SUCCESS, personBalancePayService)
-                ResponseEntity.ok(ResponseBodyBuilder.create()
-                        .data("refno", dtl.refno)
-                        .success())
-            } else {
-                PersonTransBuilder.newBuilder(accountUtilServcie)
-                        .done(dtl.refno, TradeDict.DTL_STATUS_FAIL, personBalancePayService)
-                ResponseEntity.ok(ResponseBodyBuilder.create()
-                        .fail(TradeErrorCode.TRANSACTION_NOT_EXISTS, "交易请求失败-${code.retcode}"))
-            }
-        } catch (e: TransactionException) {
-            ResponseEntity.ok(ResponseBodyBuilder.create()
-                    .transException(e, "交易确认失败"))
-        }
     }
 
     /**
-     * 微信支付
-     * wechattype
-     * qrcode-扫微信二维码支付
-     * app-原生app微信支付
-     * mp-微信公众号支付
-     * h5-微信h5支付
-     *
+     * 市民卡交易确认
      * */
-    @PostMapping("/wechat/payinit")
-    fun wechatPayInit(userid: String, amount: Int, manageFee: Int,
-                      stuempno: String, shopid: String, transdate: String, transtime: String,
-                      outtradeno: String, payinfo: String, feetype: String,
-                      wechattype: String, realip: String?, qrcode: String?, openid: String?): ResponseEntity<Any> {
+    @PostMapping("/citizencard/payfinish")
+    fun citizencardPayinit(@RequestBody param: CitizenCardPayfinishParam, request: HttpServletRequest, response: HttpServletResponse): ResponseEntity<Any> {
         return try {
-            val paytype = paytypeService.getByPaytype(PaytypeUtil.WECHAT)
-            if (paytype == null || ConstantUtil.ENABLE_YES != paytype.enable) {
+            if (param.checkParam() && param.checkSign(commonService.getAppidSecretByRequest(request))) {
                 ResponseEntity.ok(ResponseBodyBuilder.create()
-                        .fail(1, "支付方式未开启"))
+                        .fail(TradeErrorCode.REQUEST_SIGN_ERROR, "参数签名错误"))
             }
-            val person = userService.findByThirdUniqueIdenty(stuempno,"")
-            val dtl = PersonTransBuilder.newBuilder(accountUtilServcie)
-                    .setTransDatetime(transdate, transtime)
-                    .selectPaytype(PaytypeUtil.WECHAT, payinfo)
-                    .setOuttradeno(outtradeno)
-                    .also {
-                        if (null != person) it.setOwner(person)
-                    }
-                    .tryLock(true)
-                    .setTransinfo(TradeCode.TRANSCODE_WECHAT, "微信支付")
-                    .chooseTradetype(Tradetype.CONSUME)
-                    .also {
-                        when (feetype) {
-                            TradeDict.FEETYPE_CONSUME_MEALER -> {
-                                it.addDetail(AccountHolder.subject(Subject.SUBJNO_PAY_WECHAT),
-                                        AccountHolder.shop(shopid),
-                                        amount / 100.0, "微信支付")
-                                        .addDetail(AccountHolder.transType(TranstypeCode.TT_CONSUUME_MANAGE_FEE)
-                                                .with(AccountHolder.shop(shopid)),
-                                                manageFee / 100.0)
-                            }
-                            TradeDict.FEETYPE_CONSUME_DISCOUNT -> {
-                                it.addDetail(AccountHolder.subject(Subject.SUBJNO_PAY_WECHAT),
-                                        AccountHolder.shop(shopid),
-                                        (amount - manageFee) / 100.0, "微信支付")
-                                        .addDetail(AccountHolder.subject(Subject.SUBJNO_CONSUME_DISCOUNT),
-                                                AccountHolder.shop(shopid),
-                                                manageFee / 100.0, "优惠折扣")
-                            }
-                            else -> {
-                                it.addDetail(AccountHolder.subject(Subject.SUBJNO_PAY_WECHAT),
-                                        AccountHolder.shop(shopid),
-                                        amount / 100.0, "微信支付")
-                            }
-                        }
-                    }.done(personBalancePayService, false)
-            val code = CallService.callWechatPay(paytypeService.getPaytypeConfigByPaytype(PaytypeUtil.WECHAT),
-                    dtl, DateUtil.getNow(), wechattype, realip, qrcode, openid)
+
+            var dtl = PersonTransBuilder.newBuilder(accountUtilServcie)
+                    .setRefno(param.refno)
+                    .wip(personBalancePayService)
+            val code = CallService.CallCitizenCardPay(consumePayService.getPaytypeConfig(TradeDict.PAYTYPE_CITIZEN_CARD, "shopaccno"), dtl)
             if (code.retcode == "0") {
+                dtl = PersonTransBuilder.newBuilder(accountUtilServcie)
+                        .setRefno(param.refno)
+                        .addResult(code.data)
+                        .success(personBalancePayService) //流水置成功
+
                 ResponseEntity.ok(ResponseBodyBuilder.create()
                         .data("refno", dtl.refno)
+                        .data("billno", dtl.outtradeno)
                         .success())
             } else {
+                PersonTransBuilder.newBuilder(accountUtilServcie)
+                        .setRefno(param.refno)
+                        .addResult("errmsg", code.retmsg!!)
+                        .finish(personBalancePayService, TradeDict.DTL_STATUS_FAIL) //流水置成功
+
                 ResponseEntity.ok(ResponseBodyBuilder.create()
-                        .fail(TradeErrorCode.TRANSACTION_NOT_EXISTS, "交易请求失败-${code.retcode}"))
+                        .fail(TradeErrorCode.BUSINESS_DEAL_ERROR, "交易扣费失败-${code.retmsg}"))
             }
-        } catch (e: TransactionException) {
+
+        } catch (ex: RequestParamCheckException) {
             ResponseEntity.ok(ResponseBodyBuilder.create()
-                    .transException(e, "交易初始化异常"))
+                    .requestException(ex, "请求参数错误"))
+        } catch (et: TransactionException) {
+            ResponseEntity.ok(ResponseBodyBuilder.create()
+                    .transException(et, "业务处理错误"))
         }
     }
+
+    @PostMapping("/balance/pay")
+    fun balancePay(@RequestBody param: CitizenCardPayinitParam, request: HttpServletRequest, response: HttpServletResponse): ResponseEntity<Any> {
+        return try {
+            if (param.checkParam() && param.checkSign(commonService.getAppidSecretByRequest(request))) {
+                ResponseEntity.ok(ResponseBodyBuilder.create()
+                        .fail(TradeErrorCode.REQUEST_SIGN_ERROR, "参数签名错误"))
+            }
+
+            val person = userService.findPersonByIdentityCheckStatus(param.cardNo)
+            val dtl = PersonTransBuilder.newBuilder(accountUtilServcie)
+                    .chooseTradetype(Tradetype.CONSUME) //消费
+                    .setOwner(person) //记名
+                    .setTransinfo(TradeCode.TRANSCODE_PAY, "支付交易")
+                    .setTransDatetime(param.transdate, param.transtime) //交易时间
+                    .selectPaytype(TradeDict.PAYTYPE_BALANCE, param.cardNo)
+                    .addDetail(AccountHolder.person(person.userid),
+                            AccountHolder.shop(param.shopaccno),
+                            param.amount / 100.0, "账户余额消费")
+                    .also { builder ->
+                        param.feelist?.forEach {
+                            builder.addDetail(AccountHolder.feetype(it.feetype, TradeDict.PAYTYPE_BALANCE)
+                                    .with(AccountHolder.shop(param.shopaccno))
+                                    .with(AccountHolder.person(person.userid))
+                                    , it.amount / 100.0)
+                        }
+                    }
+                    .done(personBalancePayService)
+
+            ResponseEntity.ok(ResponseBodyBuilder.create()
+                    .data("refno", dtl.refno)
+                    .data("amount", dtl.amount)
+                    .success("交易成功"))
+
+        } catch (ex: RequestParamCheckException) {
+            ResponseEntity.ok(ResponseBodyBuilder.create()
+                    .requestException(ex, "请求参数错误"))
+        } catch (et: TransactionException) {
+            ResponseEntity.ok(ResponseBodyBuilder.create()
+                    .transException(et, "业务处理错误"))
+        }
+    }
+
+// ============================================== //
+//
+//    @GetMapping("/account/payinit")
+//    fun accountPayInit(userid: String, amount: Int, manageFee: Int): ResponseEntity<Any> {
+//        val dtl = PersonTransBuilder.newBuilder(accountUtilServcie)
+//                .setTransDatetime("20190411", "112311")
+//                .enableOverdraft(false)
+//                .addDetail(AccountHolder.person(userid),
+//                        AccountHolder.shop("12323"),
+//                        amount / 100.0, "")
+//                .addDetail(AccountHolder.person(userid), AccountHolder.transType(301),
+//                        manageFee / 100.0, "")
+//                .done(personBalancePayService, false)
+//
+//        return ResponseEntity.ok(dtl)
+//    }
+//
+//    @GetMapping("/account/payfinish")
+//    fun accountPayFinish(refno: String): ResponseEntity<Any> {
+//        val dtl = PersonTransBuilder.newBuilder(accountUtilServcie)
+//                .done(refno, TradeDict.DTL_STATUS_SUCCESS, personBalancePayService)
+//        return ResponseEntity.ok(dtl)
+//    }
+//
+//    @PostMapping("/ykt/payinit")
+//    fun yktPayInit(userid: String, amount: Int, manageFee: Int,
+//                   stuempno: String, shopid: String, transdate: String, transtime: String,
+//                   outtradeno: String, payinfo: String, feetype: String): ResponseEntity<Any> {
+//        //一卡通支付款 112240
+//        return try {
+//            val paytype = paytypeService.getByPaytype(PaytypeUtil.YKTPAY)
+//            if (paytype == null || ConstantUtil.ENABLE_YES != paytype.enable) {
+//                ResponseEntity.ok(ResponseBodyBuilder.create()
+//                        .fail(1, "支付方式未开启"))
+//            }
+//            val person = userService.findByThirdUniqueIdenty(stuempno)
+//            val dtl = PersonTransBuilder.newBuilder(accountUtilServcie)
+//                    .setTransDatetime(transdate, transtime)
+//                    .selectPaytype(PaytypeUtil.YKTPAY, payinfo)
+//                    .setOuttradeno(outtradeno)
+//                    .also {
+//                        if (null != person) it.setOwner(person)
+//                    }
+//                    .tryLock(true)
+//                    .setTransinfo(TradeCode.TRANSCODE_YKTPAY, "一卡通支付")
+//                    .chooseTradetype(Tradetype.CONSUME)
+//                    .also {
+//                        when (feetype) {
+//                            TradeDict.FEETYPE_CONSUME_MEALER -> {
+//                                it.addDetail(AccountHolder.subject(Subject.SUBJNO_PAY_YKT),
+//                                        AccountHolder.shop(shopid),
+//                                        amount / 100.0, "一卡通支付")
+//                                        .addDetail(AccountHolder.transType(TranstypeCode.TT_CONSUUME_MANAGE_FEE)
+//                                                .with(AccountHolder.shop(shopid)),
+//                                                manageFee / 100.0)
+//                            }
+//                            TradeDict.FEETYPE_CONSUME_DISCOUNT -> {
+//                                it.addDetail(AccountHolder.subject(Subject.SUBJNO_PAY_YKT),
+//                                        AccountHolder.shop(shopid),
+//                                        (amount - manageFee) / 100.0, "一卡通支付")
+//                                        .addDetail(AccountHolder.subject(Subject.SUBJNO_CONSUME_DISCOUNT),
+//                                                AccountHolder.shop(shopid),
+//                                                manageFee / 100.0, "优惠折扣")
+//                            }
+//                            else -> {
+//                                it.addDetail(AccountHolder.subject(Subject.SUBJNO_PAY_YKT),
+//                                        AccountHolder.shop(shopid),
+//                                        amount / 100.0, "一卡通支付")
+//                            }
+//                        }
+//                    }.done(personBalancePayService, false)
+//            ResponseEntity.ok(ResponseBodyBuilder.create()
+//                    .data("refno", dtl.refno)
+//                    .success())
+//        } catch (e: TransactionException) {
+//            ResponseEntity.ok(ResponseBodyBuilder.create()
+//                    .transException(e, "交易初始化异常"))
+//        }
+//    }
+//
+//    @PostMapping("/ykt/payfinish")
+//    fun yktPayFinish(refno: String, yktshopid: String, devphyid: String?): ResponseEntity<Any> {
+//        return try {
+//            val dtl = personBalancePayService.wip(refno)
+//            val person = userService.findPersonByUserid(dtl.userid)
+//            val code = CallService.callYktPay(paytypeService.getPaytypeConfigByPaytype(PaytypeUtil.YKTPAY),
+//                    dtl, DateUtil.getNow(), "", yktshopid, devphyid)
+//            if (code.retcode == "0") {
+//                PersonTransBuilder.newBuilder(accountUtilServcie)
+//                        .done(dtl.refno, TradeDict.DTL_STATUS_SUCCESS, personBalancePayService)
+//                ResponseEntity.ok(ResponseBodyBuilder.create()
+//                        .data("refno", dtl.refno)
+//                        .success())
+//            } else {
+//                PersonTransBuilder.newBuilder(accountUtilServcie)
+//                        .done(dtl.refno, TradeDict.DTL_STATUS_FAIL, personBalancePayService)
+//                ResponseEntity.ok(ResponseBodyBuilder.create()
+//                        .fail(TradeErrorCode.TRANSACTION_NOT_EXISTS, "交易请求失败-${code.retcode}"))
+//            }
+//        } catch (e: TransactionException) {
+//            ResponseEntity.ok(ResponseBodyBuilder.create()
+//                    .transException(e, "交易确认失败"))
+//        }
+//    }
+//
+//    /**
+//     * 微信支付
+//     * wechattype
+//     * qrcode-扫微信二维码支付
+//     * app-原生app微信支付
+//     * mp-微信公众号支付
+//     * h5-微信h5支付
+//     *
+//     * */
+//    @PostMapping("/wechat/payinit")
+//    fun wechatPayInit(userid: String, amount: Int, manageFee: Int,
+//                      stuempno: String, shopid: String, transdate: String, transtime: String,
+//                      outtradeno: String, payinfo: String, feetype: String,
+//                      wechattype: String, realip: String?, qrcode: String?, openid: String?): ResponseEntity<Any> {
+//        return try {
+//            val paytype = paytypeService.getByPaytype(PaytypeUtil.WECHAT)
+//            if (paytype == null || ConstantUtil.ENABLE_YES != paytype.enable) {
+//                ResponseEntity.ok(ResponseBodyBuilder.create()
+//                        .fail(1, "支付方式未开启"))
+//            }
+//            val person = userService.findByThirdUniqueIdenty(stuempno)
+//            val dtl = PersonTransBuilder.newBuilder(accountUtilServcie)
+//                    .setTransDatetime(transdate, transtime)
+//                    .selectPaytype(PaytypeUtil.WECHAT, payinfo)
+//                    .setOuttradeno(outtradeno)
+//                    .also {
+//                        if (null != person) it.setOwner(person)
+//                    }
+//                    .tryLock(true)
+//                    .setTransinfo(TradeCode.TRANSCODE_WECHAT, "微信支付")
+//                    .chooseTradetype(Tradetype.CONSUME)
+//                    .also {
+//                        when (feetype) {
+//                            TradeDict.FEETYPE_CONSUME_MEALER -> {
+//                                it.addDetail(AccountHolder.subject(Subject.SUBJNO_PAY_WECHAT),
+//                                        AccountHolder.shop(shopid),
+//                                        amount / 100.0, "微信支付")
+//                                        .addDetail(AccountHolder.transType(TranstypeCode.TT_CONSUUME_MANAGE_FEE)
+//                                                .with(AccountHolder.shop(shopid)),
+//                                                manageFee / 100.0)
+//                            }
+//                            TradeDict.FEETYPE_CONSUME_DISCOUNT -> {
+//                                it.addDetail(AccountHolder.subject(Subject.SUBJNO_PAY_WECHAT),
+//                                        AccountHolder.shop(shopid),
+//                                        (amount - manageFee) / 100.0, "微信支付")
+//                                        .addDetail(AccountHolder.subject(Subject.SUBJNO_CONSUME_DISCOUNT),
+//                                                AccountHolder.shop(shopid),
+//                                                manageFee / 100.0, "优惠折扣")
+//                            }
+//                            else -> {
+//                                it.addDetail(AccountHolder.subject(Subject.SUBJNO_PAY_WECHAT),
+//                                        AccountHolder.shop(shopid),
+//                                        amount / 100.0, "微信支付")
+//                            }
+//                        }
+//                    }.done(personBalancePayService, false)
+//            val code = CallService.callWechatPay(paytypeService.getPaytypeConfigByPaytype(PaytypeUtil.WECHAT),
+//                    dtl, DateUtil.getNow(), wechattype, realip, qrcode, openid)
+//            if (code.retcode == "0") {
+//                ResponseEntity.ok(ResponseBodyBuilder.create()
+//                        .data("refno", dtl.refno)
+//                        .success())
+//            } else {
+//                ResponseEntity.ok(ResponseBodyBuilder.create()
+//                        .fail(TradeErrorCode.TRANSACTION_NOT_EXISTS, "交易请求失败-${code.retcode}"))
+//            }
+//        } catch (e: TransactionException) {
+//            ResponseEntity.ok(ResponseBodyBuilder.create()
+//                    .transException(e, "交易初始化异常"))
+//        }
+//    }
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/supwisdom/dlpay/api/controller/notify_api_controller.kt b/src/main/kotlin/com/supwisdom/dlpay/api/controller/notify_api_controller.kt
index 408cc3d..cc262cb 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/api/controller/notify_api_controller.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/api/controller/notify_api_controller.kt
@@ -89,7 +89,9 @@
                     && !StringUtils.isEmpty(result_code) && "SUCCESS" == result_code) {
                 //map.get("transaction_id") 第三方流水号
                 PersonTransBuilder.newBuilder(accountUtilServcie)
-                        .done(out_trade_no!!, TradeDict.DTL_STATUS_SUCCESS, map, personBalancePayService)
+                        .setRefno(out_trade_no!!)
+                        .addResult(map)
+                        .success(personBalancePayService)
             }
             return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>"
         } catch (e: Exception) {
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 a8f4bfc..5f92a0c 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
@@ -6,12 +6,14 @@
 import com.supwisdom.dlpay.api.service.ShopService
 import com.supwisdom.dlpay.exception.RequestParamCheckException
 import com.supwisdom.dlpay.exception.TransactionException
-import com.supwisdom.dlpay.framework.service.SystemUtilService
+import com.supwisdom.dlpay.framework.service.CommonService
 import com.supwisdom.dlpay.framework.util.TradeErrorCode
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.http.ResponseEntity
 import org.springframework.web.bind.annotation.*
 import java.net.URLDecoder
+import javax.servlet.http.HttpServletRequest
+import javax.servlet.http.HttpServletResponse
 
 @RestController
 @RequestMapping("/api/shop")
@@ -19,27 +21,27 @@
     @Autowired
     private lateinit var shopService: ShopService
     @Autowired
-    private lateinit var systemUtilService: SystemUtilService
+    private lateinit var commonService: CommonService
 
     @PostMapping("/open")
-    fun openAccount(@RequestBody request: OpenShopParam): ResponseEntity<Any> {
+    fun openAccount(@RequestBody param: OpenShopParam, request: HttpServletRequest, response: HttpServletResponse): ResponseEntity<Any> {
         return try {
-            if (request.checkParam() && request.checkSign(systemUtilService.getSubsystemSignKey(request.syscode))) {
+            if (param.checkParam() && param.checkSign(commonService.getAppidSecretByRequest(request))) {
                 ResponseEntity.ok(ResponseBodyBuilder.create()
                         .fail(TradeErrorCode.REQUEST_SIGN_ERROR, "参数签名错误"))
             }
-            shopService.findByThirdUniqueId(request.shopUniqueId)?.let {
+            shopService.findByThirdUniqueId(param.shopUniqueId)?.let {
                 ResponseEntity.ok(ResponseBodyBuilder.create()
-                        .fail(TradeErrorCode.BUSINESS_SHOP_EXISTS, "该商户唯一号[${request.shopUniqueId}]已经存在"))
+                        .fail(TradeErrorCode.BUSINESS_SHOP_EXISTS, "该商户唯一号[${param.shopUniqueId}]已经存在"))
             }
 
-            request.shopname = request.shopname?.let { URLDecoder.decode(request.shopname, Charsets.UTF_8.toString()) } //解码
-            request.contactman = request.contactman?.let { URLDecoder.decode(request.contactman, Charsets.UTF_8.toString()) } //解码
-            request.address = request.address?.let { URLDecoder.decode(request.address, Charsets.UTF_8.toString()) } //解码
-            shopService.registerShop(request)?.let {
+            param.shopname = param.shopname?.let { URLDecoder.decode(param.shopname, Charsets.UTF_8.toString()) } //解码
+            param.contactman = param.contactman?.let { URLDecoder.decode(param.contactman, Charsets.UTF_8.toString()) } //解码
+            param.address = param.address?.let { URLDecoder.decode(param.address, Charsets.UTF_8.toString()) } //解码
+            shopService.registerShop(param)?.let {
                 ResponseEntity.ok(ResponseBodyBuilder.create()
                         .data("shopid", it.shopid)
-                        .data("shopaccno",it.shopaccno?:"")
+                        .data("shopaccno", it.shopaccno ?: "")
                         .success("注册成功"))
             }
 
@@ -55,16 +57,16 @@
     }
 
     @GetMapping("/query")
-    fun queryShop(@RequestBody request: QueryShopParam): ResponseEntity<Any> {
+    fun queryShop(@RequestBody param: QueryShopParam, request: HttpServletRequest, response: HttpServletResponse): ResponseEntity<Any> {
         return try {
-            if (request.checkParam() && request.checkSign(systemUtilService.getSubsystemSignKey(request.syscode))) {
+            if (param.checkParam() && param.checkSign(commonService.getAppidSecretByRequest(request))) {
                 ResponseEntity.ok(ResponseBodyBuilder.create()
                         .fail(TradeErrorCode.REQUEST_SIGN_ERROR, "参数签名错误"))
             }
 
-            shopService.findByShopBySearch(request.shopid,request.shopaccno,request.shopUniqueId)?.let {
+            shopService.findByShopBySearch(param.shopid, param.shopaccno, param.shopUniqueId)?.let {
                 ResponseEntity.ok(ResponseBodyBuilder.create()
-                        .data("shopid", it)
+                        .data("shop", it)
                         .success())
             }
 
diff --git a/src/main/kotlin/com/supwisdom/dlpay/api/controller/user_api_controller.kt b/src/main/kotlin/com/supwisdom/dlpay/api/controller/user_api_controller.kt
index ac86e3a..5b838e4 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/api/controller/user_api_controller.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/api/controller/user_api_controller.kt
@@ -7,7 +7,7 @@
 import com.supwisdom.dlpay.exception.RequestParamCheckException
 import com.supwisdom.dlpay.exception.TransactionException
 import com.supwisdom.dlpay.framework.ResponseBodyBuilder
-import com.supwisdom.dlpay.framework.service.SystemUtilService
+import com.supwisdom.dlpay.framework.service.CommonService
 import com.supwisdom.dlpay.framework.util.TradeErrorCode
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.http.ResponseEntity
@@ -16,6 +16,8 @@
 import org.springframework.web.bind.annotation.RequestMapping
 import org.springframework.web.bind.annotation.RestController
 import java.net.URLDecoder
+import javax.servlet.http.HttpServletRequest
+import javax.servlet.http.HttpServletResponse
 
 @RestController
 @RequestMapping("/api/user")
@@ -23,28 +25,28 @@
     @Autowired
     private lateinit var useService: UserService
     @Autowired
-    private lateinit var systemUtilService: SystemUtilService
+    private lateinit var commonService: CommonService
 
     @PostMapping("/open")
-    fun openAccount(@RequestBody request: OpenUserParam): ResponseEntity<Any> {
+    fun openAccount(@RequestBody param: OpenUserParam, request: HttpServletRequest, response: HttpServletResponse): ResponseEntity<Any> {
         return try {
-            if (request.checkParam() && request.checkSign(systemUtilService.getSubsystemSignKey(request.syscode))) {
+            if (param.checkParam() && param.checkSign(commonService.getAppidSecretByRequest(request))) {
                 ResponseEntity.ok(ResponseBodyBuilder.create()
                         .fail(TradeErrorCode.REQUEST_SIGN_ERROR, "参数签名错误"))
             }
-            useService.findByThirdUniqueIdenty(request.uid, request.syscode).let {
+            useService.findByThirdUniqueIdenty(param.uid).let {
                 if (null != it) {
                     ResponseEntity.ok(ResponseBodyBuilder.create()
                             .fail(TradeErrorCode.REGISTER_USER_EXIST, "改用户唯一号已经注册"))
                 }
 
-                request.name = URLDecoder.decode(request.name, Charsets.UTF_8.toString()) //解码
-                request.address = request.address?.let { URLDecoder.decode(request.address, Charsets.UTF_8.toString()) }  //解码
-                useService.registerUser(request).let {
+                param.name = URLDecoder.decode(param.name, Charsets.UTF_8.toString()) //解码
+                param.address = param.address?.let { URLDecoder.decode(param.address, Charsets.UTF_8.toString()) }  //解码
+                useService.registerUser(param).let {
                     if (null != it) {
                         ResponseEntity.ok(ResponseBodyBuilder.create()
                                 .data("userid", it.userid)
-                                .data("uid", request.uid)
+                                .data("uid", param.uid)
                                 .success())
                     }
 
@@ -62,14 +64,14 @@
     }
 
     @PostMapping("/query")
-    fun queryAccount(@RequestBody request: QueryUserParam): ResponseEntity<Any> {
+    fun queryAccount(@RequestBody param: QueryUserParam, request: HttpServletRequest, response: HttpServletResponse): ResponseEntity<Any> {
         return try {
-            if (request.checkParam() && request.checkSign(systemUtilService.getSubsystemSignKey(request.syscode))) {
+            if (param.checkParam() && param.checkSign(commonService.getAppidSecretByRequest(request))) {
                 ResponseEntity.ok(ResponseBodyBuilder.create()
                         .fail(TradeErrorCode.REQUEST_SIGN_ERROR, "参数签名错误"))
             }
 
-            useService.findByUseridOrThirdUniqueIdenty(request.userid, request.uid, request.syscode).let {
+            useService.findByUseridOrThirdUniqueIdenty(param.userid, param.uid).let {
                 if (null != it) {
                     val account = useService.findAccountByUserid(it.userid, null)
                     val pointacc = useService.findPointsAccountByUserid(it.userid)
@@ -111,16 +113,16 @@
     }
 
     @PostMapping("/modify")
-    fun modifyAccount(@RequestBody request: ModifyUserParam): ResponseEntity<Any> {
+    fun modifyAccount(@RequestBody param: ModifyUserParam, request: HttpServletRequest, response: HttpServletResponse): ResponseEntity<Any> {
         return try {
-            if (request.checkParam() && request.checkSign(systemUtilService.getSubsystemSignKey(request.syscode))) {
+            if (param.checkParam() && param.checkSign(commonService.getAppidSecretByRequest(request))) {
                 ResponseEntity.ok(ResponseBodyBuilder.create()
                         .fail(TradeErrorCode.REQUEST_SIGN_ERROR, "参数签名错误"))
             }
-            useService.findByUseridOrThirdUniqueIdenty(request.userid, request.uid, request.syscode)?.let {
-                request.name = request.name?.let { URLDecoder.decode(request.name, Charsets.UTF_8.toString()) } //解码
-                request.address = request.address?.let { URLDecoder.decode(request.address, Charsets.UTF_8.toString()) } //解码
-                if (useService.modifyUserInfo(it, request)) {
+            useService.findByUseridOrThirdUniqueIdenty(param.userid, param.uid)?.let {
+                param.name = param.name?.let { URLDecoder.decode(param.name, Charsets.UTF_8.toString()) } //解码
+                param.address = param.address?.let { URLDecoder.decode(param.address, Charsets.UTF_8.toString()) } //解码
+                if (useService.modifyUserInfo(it, param)) {
                     ResponseEntity.ok(ResponseBodyBuilder.create()
                             .success("修改成功"))
                 } else {
diff --git a/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/pay_service_impl.kt b/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/pay_service_impl.kt
index c043553..7ef63a5 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/pay_service_impl.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/pay_service_impl.kt
@@ -11,9 +11,11 @@
 import com.supwisdom.dlpay.api.service.PersonBalancePayService
 import com.supwisdom.dlpay.exception.TransactionException
 import com.supwisdom.dlpay.exception.TransactionProcessException
+import com.supwisdom.dlpay.framework.dao.FeetypeConfigDao
 import com.supwisdom.dlpay.framework.dao.ShopaccDao
 import com.supwisdom.dlpay.framework.dao.SubjectDao
 import com.supwisdom.dlpay.framework.dao.TranstypeDao
+import com.supwisdom.dlpay.framework.domain.TFeetypeConfig
 import com.supwisdom.dlpay.framework.domain.TShopacc
 import com.supwisdom.dlpay.framework.domain.TSubject
 import com.supwisdom.dlpay.framework.domain.TTranstype
@@ -40,7 +42,7 @@
     lateinit var subjectDao: SubjectDao
 
     @Autowired
-    lateinit var transtypeDao: TranstypeDao
+    lateinit var feetypeConfigDao: FeetypeConfigDao
 
 
     override fun readAccountForUpdateNowait(userid: String): TAccount {
@@ -70,9 +72,9 @@
                 ?: throw TransactionProcessException(TradeErrorCode.SUBJECT_NOT_EXISTS, "科目<$subjno>不存在")
     }
 
-    override fun readTranstype(transtype: Int): TTranstype {
-        return transtypeDao.findByTranstype(transtype)
-                ?: throw TransactionProcessException(TradeErrorCode.SUBJECT_NOT_EXISTS, "交易类型<$transtype>未配置")
+    override fun readFeetype(feetype: String, paytype: String): TFeetypeConfig {
+        return feetypeConfigDao.getById(feetype, paytype)
+                ?: throw TransactionProcessException(TradeErrorCode.FEETYPE_NOT_EXISTS, "在支付方式<$paytype>下不存在费用类别<$feetype>")
     }
 }
 
@@ -152,7 +154,7 @@
     }
 
     override fun process(builder: PersonTransBuilder): TUserdtl {
-        return finish(init(builder), TradeDict.DTL_STATUS_SUCCESS, null)
+        return finish(init(builder), TradeDict.DTL_STATUS_SUCCESS, builder.resultMap)
     }
 
     override fun init(builder: PersonTransBuilder): TUserdtl {
@@ -286,4 +288,36 @@
         userdtl.status = TradeDict.DTL_STATUS_WIP  //待支付
         return userdtlDao.save(userdtl)
     }
+
+    override fun wip(builder: PersonTransBuilder): TUserdtl {
+        return wip(builder.refno)
+    }
+
+    override fun finish(builder: PersonTransBuilder): TUserdtl{
+        return finish(builder.refno, builder.status, builder.resultMap)
+    }
+
+    override fun getUserdtlForUpdateNowait(refno: String): TUserdtl{
+        return try {
+            userdtlDao.findByRefnoForUpdateNowait(refno)
+                    ?: throw TransactionProcessException(TradeErrorCode.ACCOUNT_NOT_EXISTS, "交易参考号<$refno>流水不存在")
+        } catch (ex: Exception) {
+            when (ex) {
+                is CannotAcquireLockException, is LockTimeoutException -> throw TransactionException(TradeErrorCode.ACCOUNT_TRADE_BUSY, "流水<$refno>被锁定,请稍后再试")
+                else -> throw ex
+            }
+        }
+    }
+
+    override fun getUserdtlByBillnoForUpdateNowait(billno: String, shopaccno: String): TUserdtl {
+        return try {
+            userdtlDao.findByBillnoForUpdateNowait(billno, shopaccno)
+                    ?: throw TransactionProcessException(TradeErrorCode.ACCOUNT_NOT_EXISTS, "商户流水号<$billno>流水不存在")
+        } catch (ex: Exception) {
+            when (ex) {
+                is CannotAcquireLockException, is LockTimeoutException -> throw TransactionException(TradeErrorCode.ACCOUNT_TRADE_BUSY, "商户流水号<$billno>流水被锁定,请稍后再试")
+                else -> throw ex
+            }
+        }
+    }
 }
\ No newline at end of file
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 510fd35..fa30ada 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
@@ -16,7 +16,6 @@
 import com.supwisdom.dlpay.framework.util.*
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.stereotype.Service
-import java.net.URLDecoder
 
 /**
  * Created by shuwei on 2019/4/15.
@@ -79,23 +78,26 @@
             }
         }
         personIdentityDao.save(TPersonIdentity().apply {
-            thirdUserid = param.uid
-            thirdSyscode = param.syscode
+            thirdUid = param.uid
             this.person = person
+            status = person.status
+            lossflag = 0
+            lockflag = 0
+            createtime = systemdatetime.hostdatetime
         }) //保存绑定关系
 
         return person
     }
 
-    override fun findByThirdUniqueIdenty(thirdUniqueIdenty: String, syscode: String): TPerson? {
-        return personIdentityDao.getPersonIdentityById(thirdUniqueIdenty, syscode)?.let { it.person }
+    override fun findByThirdUniqueIdenty(thirdUniqueIdenty: String): TPerson? {
+        return personIdentityDao.getByThirdUid(thirdUniqueIdenty)?.let { it.person }
     }
 
-    override fun findByUseridOrThirdUniqueIdenty(userid: String?, thirdUniqueIdenty: String?, syscode: String): TPerson? {
+    override fun findByUseridOrThirdUniqueIdenty(userid: String?, thirdUniqueIdenty: String?): TPerson? {
         return if (!StringUtil.isEmpty(userid)) {
             personDao.findByUserid(userid)
         } else {
-            personIdentityDao.getPersonIdentityById(thirdUniqueIdenty, syscode)?.let { it.person }
+            personIdentityDao.getByThirdUid(thirdUniqueIdenty)?.let { it.person }
         }
     }
 
@@ -137,4 +139,32 @@
         return pointsAccountDao.findByUserid(userid)
     }
 
+    override fun findPersonIdentity(thirdUniqueIdenty: String): TPersonIdentity? {
+        return personIdentityDao.getByThirdUid(thirdUniqueIdenty)
+    }
+
+    override fun findPersonByIdentityCheckStatus(thirdUniqueIdenty: String): TPerson {
+        personIdentityDao.getByThirdUid(thirdUniqueIdenty).let {
+            if (null != it) {
+                if (TradeDict.STATUS_NORMAL != it.status) {
+                    throw TransactionProcessException(TradeErrorCode.PERSON_STATUS_ERROR, "账户状态异常")
+                }
+                if (1 == it.lossflag) {
+                    throw TransactionProcessException(TradeErrorCode.ACCOUNT_IS_LOSS, "账户已挂失")
+                }
+                if (1 == it.lockflag) {
+                    throw TransactionProcessException(TradeErrorCode.ACCOUNT_IS_LOCKED, "账户已冻结")
+                }
+
+                if (null != it.person) {
+                    return it.person
+                } else {
+                    throw TransactionProcessException(TradeErrorCode.ACCOUNT_NOT_EXISTS, "账户不存在")
+                }
+            }
+
+            throw TransactionProcessException(TradeErrorCode.ACCOUNT_NOT_EXISTS, "账户不存在")
+        }
+    }
+
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/supwisdom/dlpay/api/service/pay_service.kt b/src/main/kotlin/com/supwisdom/dlpay/api/service/pay_service.kt
index b789d39..568d9bb 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/api/service/pay_service.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/api/service/pay_service.kt
@@ -3,6 +3,7 @@
 import com.supwisdom.dlpay.api.PersonTransBuilder
 import com.supwisdom.dlpay.api.domain.TAccount
 import com.supwisdom.dlpay.api.domain.TUserdtl
+import com.supwisdom.dlpay.framework.domain.TFeetypeConfig
 import com.supwisdom.dlpay.framework.domain.TShopacc
 import com.supwisdom.dlpay.framework.domain.TSubject
 import com.supwisdom.dlpay.framework.domain.TTranstype
@@ -21,7 +22,7 @@
 
     fun readSubject(subjno: String): TSubject
 
-    fun readTranstype(transtype: Int): TTranstype
+    fun readFeetype(feetype: String, paytype: String): TFeetypeConfig
 }
 
 interface PersonBalancePayService {
@@ -58,4 +59,15 @@
     @Transactional(propagation = Propagation.REQUIRED, rollbackFor = arrayOf(Exception::class))
     fun wip(refno: String): TUserdtl
 
+    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = arrayOf(Exception::class))
+    fun wip(builder: PersonTransBuilder): TUserdtl
+
+    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = arrayOf(Exception::class))
+    fun finish(builder: PersonTransBuilder): TUserdtl
+
+    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = arrayOf(Exception::class))
+    fun getUserdtlForUpdateNowait(refno: String): TUserdtl
+
+    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = arrayOf(Exception::class))
+    fun getUserdtlByBillnoForUpdateNowait(billno: String, shopaccno: String): TUserdtl
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/supwisdom/dlpay/api/service/user_service.kt b/src/main/kotlin/com/supwisdom/dlpay/api/service/user_service.kt
index 9f2d3fd..c4d9b20 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/api/service/user_service.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/api/service/user_service.kt
@@ -4,6 +4,7 @@
 import com.supwisdom.dlpay.api.bean.OpenUserParam
 import com.supwisdom.dlpay.api.domain.TAccount
 import com.supwisdom.dlpay.api.domain.TPerson
+import com.supwisdom.dlpay.api.domain.TPersonIdentity
 import com.supwisdom.dlpay.api.domain.TPointsAccount
 import org.springframework.transaction.annotation.Propagation
 import org.springframework.transaction.annotation.Transactional
@@ -16,10 +17,10 @@
     fun registerUser(param: OpenUserParam): TPerson
 
     @Transactional(propagation = Propagation.REQUIRED, rollbackFor = arrayOf(Exception::class), readOnly = true)
-    fun findByThirdUniqueIdenty(thirdUniqueIdenty: String, syscode: String): TPerson?
+    fun findByThirdUniqueIdenty(thirdUniqueIdenty: String): TPerson?
 
     @Transactional(propagation = Propagation.REQUIRED, rollbackFor = arrayOf(Exception::class), readOnly = true)
-    fun findByUseridOrThirdUniqueIdenty(userid: String?, thirdUniqueIdenty: String?, syscode: String): TPerson?
+    fun findByUseridOrThirdUniqueIdenty(userid: String?, thirdUniqueIdenty: String?): TPerson?
 
     @Transactional(propagation = Propagation.REQUIRED, rollbackFor = arrayOf(Exception::class), readOnly = true)
     fun modifyUserInfo(person:TPerson,param: ModifyUserParam):Boolean
@@ -33,4 +34,10 @@
     @Transactional(propagation = Propagation.REQUIRED, rollbackFor = arrayOf(Exception::class), readOnly = true)
     fun findPointsAccountByUserid(userid: String): TPointsAccount?
 
+    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = arrayOf(Exception::class), readOnly = true)
+    fun findPersonIdentity(thirdUniqueIdenty: String):TPersonIdentity?
+
+    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = arrayOf(Exception::class), readOnly = true)
+    fun findPersonByIdentityCheckStatus(thirdUniqueIdenty: String): TPerson
+
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/supwisdom/dlpay/framework/service/framework_service.kt b/src/main/kotlin/com/supwisdom/dlpay/framework/service/framework_service.kt
index b072cc2..99161e3 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/framework/service/framework_service.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/framework/service/framework_service.kt
@@ -1,5 +1,13 @@
 package com.supwisdom.dlpay.framework.service
 
+import com.supwisdom.dlpay.api.bean.ConsumeFeetype
+import javax.servlet.http.HttpServletRequest
+
 interface CommonService{
     fun getSystemVersion(): String
+
+    fun getRequestAppid(request: HttpServletRequest): String
+
+    fun getAppidSecretByRequest(request: HttpServletRequest): String
+
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/supwisdom/dlpay/framework/service/impl/framework_service_impl.kt b/src/main/kotlin/com/supwisdom/dlpay/framework/service/impl/framework_service_impl.kt
index 7429de9..56f2586 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/framework/service/impl/framework_service_impl.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/framework/service/impl/framework_service_impl.kt
@@ -1,11 +1,37 @@
 package com.supwisdom.dlpay.framework.service.impl
 
+import com.google.gson.Gson
+import com.google.gson.reflect.TypeToken
 import com.jcabi.manifests.Manifests
+import com.supwisdom.dlpay.api.bean.ConsumeFeetype
+import com.supwisdom.dlpay.exception.RequestParamCheckException
+import com.supwisdom.dlpay.exception.TransactionProcessException
+import com.supwisdom.dlpay.framework.core.JwtConfig
+import com.supwisdom.dlpay.framework.core.JwtTokenUtil
+import com.supwisdom.dlpay.framework.dao.ApiClientDao
 import com.supwisdom.dlpay.framework.service.CommonService
+import com.supwisdom.dlpay.framework.util.StringUtil
+import com.supwisdom.dlpay.framework.util.TradeErrorCode
+import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.stereotype.Service
+import javax.servlet.http.HttpServletRequest
 
 @Service
 class CommonServiceImpl : CommonService {
+    @Autowired
+    lateinit var jwtConfig: JwtConfig
+    @Autowired
+    lateinit var apiClientDao: ApiClientDao
+
+    private var jwtUtil: JwtTokenUtil? = null
+
+    private fun getUtil(): JwtTokenUtil {
+        if (jwtUtil == null) {
+            jwtUtil = JwtTokenUtil((jwtConfig))
+        }
+        return jwtUtil as JwtTokenUtil
+    }
+
     override fun getSystemVersion(): String {
         try {
             return Manifests.read("Payapi-Version") ?: "version 1.0"
@@ -14,4 +40,27 @@
             return "unknown"
         }
     }
+
+    override fun getRequestAppid(request: HttpServletRequest): String {
+        request.getHeader(jwtConfig.header).let {
+            if (null != it && it.startsWith(jwtConfig.tokenHeader)) {
+                val claims = getUtil().verifyToken(it.substring(jwtConfig.tokenHeader.length))
+                val uid = claims["uid"]?.toString()
+                if (!StringUtil.isEmpty(uid)) {
+                    return uid as String
+                }
+            }
+
+            throw TransactionProcessException(TradeErrorCode.BUSINESS_APPID_NOTFOUND, "APPID未找到") //报错
+        }
+    }
+
+    override fun getAppidSecretByRequest(request: HttpServletRequest): String {
+        return apiClientDao.findByAppid(getRequestAppid(request)).let {
+            if (null != it)
+                it.secret
+            else
+                throw TransactionProcessException(TradeErrorCode.BUSINESS_APPID_NOTFOUND, "APPID记录未找到") //报错
+        }
+    }
 }
\ No newline at end of file