API请求Sign计算优化
diff --git a/src/main/java/com/supwisdom/dlpay/api/domain/TPaytype.java b/src/main/java/com/supwisdom/dlpay/api/domain/TPaytype.java
index 5872560..be80103 100644
--- a/src/main/java/com/supwisdom/dlpay/api/domain/TPaytype.java
+++ b/src/main/java/com/supwisdom/dlpay/api/domain/TPaytype.java
@@ -21,6 +21,9 @@
     @Column(name = "CONSUME_ENABLE",nullable = false, length = 10)
     private String consumeEnable;
 
+    @Column(name = "ANONYMOUS_ENABLE", nullable = false, length = 10)
+    private String anonymousEnable;
+
     @Column(name = "PAYDESC",  length = 200)
     private String paydesc;
 
@@ -56,6 +59,14 @@
         this.consumeEnable = consumeEnable;
     }
 
+    public String getAnonymousEnable() {
+        return anonymousEnable;
+    }
+
+    public void setAnonymousEnable(String anonymousEnable) {
+        this.anonymousEnable = anonymousEnable;
+    }
+
     public String getPaydesc() {
         return paydesc;
     }
diff --git a/src/main/java/com/supwisdom/dlpay/api/domain/TShopPaytype.java b/src/main/java/com/supwisdom/dlpay/api/domain/TShopPaytype.java
index 81c893c..cb4662e 100644
--- a/src/main/java/com/supwisdom/dlpay/api/domain/TShopPaytype.java
+++ b/src/main/java/com/supwisdom/dlpay/api/domain/TShopPaytype.java
@@ -17,6 +17,9 @@
   @Column(name = "CONSUME_ENABLE", nullable = false, length = 10)
   private String consumeEnable;
 
+  @Column(name = "ANONYMOUS_ENABLE", nullable = false, length = 10)
+  private String anonymousEnable;
+
   @Column(name = "REVERSE_ENABLE", nullable = false, length = 10)
   private String reverseEnable;
 
@@ -47,6 +50,14 @@
     this.consumeEnable = consumeEnable;
   }
 
+  public String getAnonymousEnable() {
+    return anonymousEnable;
+  }
+
+  public void setAnonymousEnable(String anonymousEnable) {
+    this.anonymousEnable = anonymousEnable;
+  }
+
   public String getReverseEnable() {
     return reverseEnable;
   }
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 fc89e32..aa195a7 100644
--- a/src/main/java/com/supwisdom/dlpay/api/domain/TUserdtl.java
+++ b/src/main/java/com/supwisdom/dlpay/api/domain/TUserdtl.java
@@ -7,7 +7,8 @@
     indexes = {@Index(name = "userdtl_transdate_idx", columnList = "transdate"),
         @Index(name = "userdtl_accdate_idx", columnList = "accdate"),
         @Index(name = "userdtl_status_idx", columnList = "status"),
-        @Index(name = "userdtl_reverse_idx", columnList = "REVERSE_FLAG")})
+        @Index(name = "userdtl_reverse_idx", columnList = "REVERSE_FLAG"),
+        @Index(name = "userdtl_outtradeno_uk", unique = true, columnList = "outtradeno,shopaccno")})
 public class TUserdtl {
   @Id
   @Column(name = "REFNO", nullable = false, length = 32)
diff --git a/src/main/java/com/supwisdom/dlpay/framework/util/APIRequest.java b/src/main/java/com/supwisdom/dlpay/framework/util/APIRequest.java
deleted file mode 100644
index 6679181..0000000
--- a/src/main/java/com/supwisdom/dlpay/framework/util/APIRequest.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.supwisdom.dlpay.framework.util;
-
-public class APIRequest {
-  private String app_id;
-  private String sign;
-  private String sign_method;
-  private String timestamp;
-
-  public String getApp_id() {
-    return app_id;
-  }
-
-  public void setApp_id(String app_id) {
-    this.app_id = app_id;
-  }
-
-  public String getSign() {
-    return sign;
-  }
-
-  public void setSign(String sign) {
-    this.sign = sign;
-  }
-
-  public String getSign_method() {
-    return sign_method;
-  }
-
-  public void setSign_method(String sign_method) {
-    this.sign_method = sign_method;
-  }
-
-  public String getTimestamp() {
-    return timestamp;
-  }
-
-  public void setTimestamp(String timestamp) {
-    this.timestamp = timestamp;
-  }
-
-}
diff --git a/src/main/java/com/supwisdom/dlpay/framework/util/APIRequestParam.java b/src/main/java/com/supwisdom/dlpay/framework/util/APIRequestParam.java
new file mode 100644
index 0000000..78ea9d4
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/framework/util/APIRequestParam.java
@@ -0,0 +1,99 @@
+package com.supwisdom.dlpay.framework.util;
+
+import org.apache.log4j.Logger;
+
+import java.beans.Introspector;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+
+public class APIRequestParam {
+  @Sign
+  private String sign;
+  @Sign
+  private String sign_type;
+  @Sign
+  private String version;
+
+  private static final Logger logger = Logger.getLogger(APIRequestParam.class);
+
+  public String getSign() {
+    return sign;
+  }
+
+  public void setSign(String sign) {
+    this.sign = sign;
+  }
+
+  public String getSign_type() {
+    return sign_type;
+  }
+
+  public void setSign_type(String sign_type) {
+    this.sign_type = sign_type;
+  }
+
+  public String getVersion() {
+    return version;
+  }
+
+  public void setVersion(String version) {
+    this.version = version;
+  }
+
+  private boolean calcSignAndCheck(Map<String, String> map, String key) {
+    String sign = map.get("sign");
+    String signType = map.get("sign_type") == null ? "MD5" : map.get("sign_type");
+    if (StringUtil.isEmpty(sign)) return false;
+
+    String signdata = StringUtil.createLinkString(StringUtil.paraFilter(map));
+    logger.info("signdata=[" + signdata + "]");
+
+    String calcSign = null;
+    //fixme: 根据 signType 计算签名
+    if ("MD5".equalsIgnoreCase(signType)) {
+      calcSign = MD5.encodeByMD5(signdata + key); //默认MD5
+    }
+
+    if (sign.equalsIgnoreCase(calcSign)) {
+      return true;
+    }
+    return false;
+  }
+
+  public boolean checkSign(String key){
+    Class clazz = this.getClass();
+    Map<String, String> paramMap = new HashMap<>();
+    Method[] allGetter = clazz.getMethods();
+
+    for (Method meth : allGetter) {
+      if (meth.getName().startsWith("get") || meth.getName().startsWith("is")) {
+        String fieldName = Introspector.decapitalize(meth.getName().substring(meth.getName().startsWith("get") ? 3 : 2));
+        Field field;
+        try {
+          field = clazz.getDeclaredField(fieldName);
+        } catch (NoSuchFieldException e) {
+          try {
+            field = clazz.getSuperclass().getDeclaredField(fieldName);
+          } catch (NoSuchFieldException e1) {
+//            e1.printStackTrace();
+            continue;
+          }
+        }
+
+        if (field.isAnnotationPresent(Sign.class)) {
+          Object value;
+          try {
+            value = meth.invoke(this);
+          } catch (Exception e) {
+            e.printStackTrace();
+            continue;
+          }
+          paramMap.put(fieldName, value == null ? null : value.toString());
+        }
+      }
+    }
+    return calcSignAndCheck(paramMap,key);
+  }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/framework/util/Sign.java b/src/main/java/com/supwisdom/dlpay/framework/util/Sign.java
new file mode 100644
index 0000000..399da55
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/framework/util/Sign.java
@@ -0,0 +1,12 @@
+package com.supwisdom.dlpay.framework.util;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface Sign {
+  int order() default 0;
+}
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 2b392b3..7bec421 100644
--- a/src/main/java/com/supwisdom/dlpay/framework/util/TradeDict.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/util/TradeDict.java
@@ -47,6 +47,7 @@
   public static final String PAYTYPE_ALIPAY = "alipay"; //市民卡
   public static final String PAYTYPE_WECHAT = "wechat"; //市民卡
   public static final String PAYTYPE_CITIZEN_CARD = "citizenCard"; //市民卡
+  public static final String PAYTYPE_YKT_CARD = "yktpay"; //一卡通
 
 
   /**
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 9087149..414da8e 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
@@ -1,45 +1,31 @@
 package com.supwisdom.dlpay.api.bean
 
 import com.supwisdom.dlpay.exception.RequestParamCheckException
-import com.supwisdom.dlpay.framework.util.DateUtil
-import com.supwisdom.dlpay.framework.util.MD5
-import com.supwisdom.dlpay.framework.util.StringUtil
-import com.supwisdom.dlpay.framework.util.TradeErrorCode
+import com.supwisdom.dlpay.framework.util.*
 import com.supwisdom.dlpay.util.ConstantUtil
 
-open class APIRequestParam {
-    open val param_map = mutableMapOf<String, String?>()
-
-    open fun checkSign(key: String): Boolean {
-        val sign = param_map["sign"]
-        val signType = param_map["sign_type"] ?: "MD5"
-        if (StringUtil.isEmpty(sign)) return false //未签名
-
-        //判断签名
-        val signdata = StringUtil.createLinkString(StringUtil.paraFilter(param_map))
-        val md5Sign = MD5.encodeByMD5(signdata + key) //默认MD5
-        if (sign.equals(md5Sign, true)) {
-            return true
-        }
-        return false
-    }
-}
-
-
 // ============================ USER ============================ //
 class OpenUserParam : APIRequestParam() {
+    @Sign
     var uid: String = ""    //第三方用户ID,必传
+    @Sign
     var name: String = ""   //必传
+    @Sign
     var sex: String? = null
+    @Sign
     var idtype: String = "" //必传
+    @Sign
     var idno: String = ""   //必传
+    @Sign
     var mobile: String? = null
+    @Sign
     var tel: String? = null
+    @Sign
     var email: String? = null
+    @Sign
     var address: String? = null
+    @Sign
     var zipcode: String? = null
-    var sign: String = "" //必传
-    var sign_type: String? = null
 
     fun checkParam(): Boolean {
         if (StringUtil.isEmpty(uid)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "用户唯一号不能为空")
@@ -51,39 +37,46 @@
         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("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() {
+    @Sign
     var userid: String? = null  // 用户ID二选一 (两者都传取userid)
+    @Sign
     var uid: String? = null    // 用户ID二选一
-    var sign: String = "" //必传
-    var sign_type: String? = null
 
     fun checkParam(): Boolean {
         if (StringUtil.isEmpty(userid) && StringUtil.isEmpty(uid)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "用户唯一号不能为空")
 
-        param_map.plus(mapOf("userid" to userid, "uid" to uid, "sign" to sign, "sign_type" to sign_type))
         return true
     }
 }
 
 class ModifyUserParam : APIRequestParam() {
+    @Sign
     var userid: String? = null  // 用户ID二选一 (两者都传取userid)
+    @Sign
     var uid: String? = null    // 用户ID二选一
+    @Sign
     var name: String? = null
+    @Sign
     var sex: String? = null
+    @Sign
     var idtype: String? = null
+    @Sign
     var idno: String? = null
+    @Sign
     var mobile: String? = null
+    @Sign
     var tel: String? = null
+    @Sign
     var email: String? = null
+    @Sign
     var address: String? = null
+    @Sign
     var zipcode: String? = null
-    var sign: String = "" //必传
-    var sign_type: String? = null
 
     fun checkParam(): Boolean {
         if (StringUtil.isEmpty(userid) && StringUtil.isEmpty(uid)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "用户唯一号不能为空")
@@ -95,8 +88,6 @@
         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("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
     }
 }
@@ -104,19 +95,28 @@
 
 // ============================ SHOP ============================ //
 class OpenShopParam : APIRequestParam() {
+    @Sign
     var shopUniqueId: String = "" //必传
+    @Sign
     var shoptype: Int = 1
+    @Sign
     var fshopid: Int? = null
+    @Sign
     var shopname: String = "" //必传
+    @Sign
     var contactman: String? = null
+    @Sign
     var idtype: String? = null
+    @Sign
     var idno: String? = null
+    @Sign
     var mobile: String? = null
+    @Sign
     var email: String? = null
+    @Sign
     var address: String? = null
+    @Sign
     var zipcode: String? = null
-    var sign: String = "" //必传
-    var sign_type: String? = null
 
     fun checkParam(): Boolean {
         if (StringUtil.isEmpty(shopUniqueId)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "商户唯一号不能为空")
@@ -128,22 +128,21 @@
         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("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() {
+    @Sign
     var shopid: Int? = null  //注册时返回的shopid
+    @Sign
     var shopaccno: String? = null  //注册时返回的shopaccno
+    @Sign
     var shopUniqueId: String? = null //注册传的商户唯一号
-    var sign: String = "" //必传
-    var sign_type: String? = null
 
     fun checkParam(): Boolean {
         if (StringUtil.isEmpty(shopUniqueId) && null == shopid && StringUtil.isEmpty(shopaccno)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "商户唯一标志不能为空")
 
-        param_map.plus(mapOf("shopUniqueId" to shopUniqueId, "shopid" to shopid, "shopaccno" to shopaccno, "sign" to sign, "sign_type" to sign_type))
         return true
     }
 }
@@ -153,34 +152,42 @@
 class ConsumeFeetype {
     var feetype: String = ""
     var amount: Int = 0
+
+    override fun toString(): String {
+        return "{feetype='$feetype', amount=$amount}"
+    }
 }
 
 class QueryDtlResultParam : APIRequestParam() {
+    @Sign
     var refno:String?=null //二选一
+    @Sign
     var billno:String?=null //二选一 (billno+shopaccno) 传billno时,shopaccno必传
+    @Sign
     var shopaccno: String?=null
-    var sign: String = "" //必传
-    var sign_type: String? = null
 
     fun checkParam(): Boolean {
         if (StringUtil.isEmpty(refno) && (StringUtil.isEmpty(billno) || StringUtil.isEmpty(shopaccno))) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "流水唯一号不能为空")
 
-        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() {
+    @Sign
     var cardNo: String = "" //必传
+    @Sign
     var shopaccno: String = "" //必传
+    @Sign
     var amount: Int = 0 //必传
-    var feelist: List<ConsumeFeetype>? = null// 的json字符串
+
+    var feelist: List<ConsumeFeetype>? = null //TODO: 怎么拼接签名字符串??
+    @Sign
     var billno: String = "" //必传
+    @Sign
     var transdate: String = "" //必传
+    @Sign
     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, "卡唯一号不能为空")
@@ -190,20 +197,17 @@
         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() {
+    @Sign
     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 94e5a08..2c1555c 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/api/comsume_builder.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/api/comsume_builder.kt
@@ -85,6 +85,7 @@
     lateinit var tradetype: Tradetype
     lateinit var refno: String
     lateinit var status: String
+    lateinit var shopaccno: String
     val resultMap = mutableMapOf<String, String>() //存调第三方结果数据
 
     var transcode = 0
@@ -196,20 +197,11 @@
             }
         }
 
-        amount = 0.0
         if (this.details.size < 1) {
             throw TransactionCheckException(TradeErrorCode.INPUT_DATA_ERROR, "未指定交易明细")
         }
-        val buyer = accountUtil.readAccount(person.userid) //判断是一个人的流水
 
         amount = this.details.sumByDouble { detail ->
-            if (detail.debitSubjNo == buyer.subjno && detail.debitAccNo != buyer.accno) {
-                throw throw TransactionCheckException(TradeErrorCode.INPUT_DATA_ERROR, "交易明细用户错误")
-            }
-
-            if (detail.creditSubjNo == buyer.subjno && detail.creditAccNo != buyer.accno) {
-                throw throw TransactionCheckException(TradeErrorCode.INPUT_DATA_ERROR, "交易明细用户错误")
-            }
             detail.amount
         }
 
@@ -225,6 +217,8 @@
         if (StringUtil.isEmpty(this.outtradeno)) {
             throw TransactionCheckException(TradeErrorCode.INPUT_DATA_ERROR, "未传递外部流水号")
         }
+
+
     }
 
     private fun preCheckAccount() {
@@ -244,6 +238,7 @@
                     it.accno to it.subjno
                 }
                 AccountHolder.IDTYPE_SHOP -> holder.withLock<TShopacc>().let {
+                    if(null==this.shopaccno) this.shopaccno=it.shopaccno
                     it.shopaccno to it.subjno
                 }
                 AccountHolder.IDTYPE_SUBJECT -> holder.withLock<TSubject>().let {
@@ -257,6 +252,7 @@
                     it.accno to it.subjno
                 }
                 AccountHolder.IDTYPE_SHOP -> holder.get<TShopacc>().let {
+                    if(null==this.shopaccno) this.shopaccno=it.shopaccno
                     it.shopaccno to it.subjno
                 }
                 AccountHolder.IDTYPE_SUBJECT -> holder.get<TSubject>().let {
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 debf0e5..a35b8ce 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
@@ -89,29 +89,34 @@
             }
 
             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)
+            if (consumePayService.checkShopPaytype(param.shopaccno, TradeDict.PAYTYPE_CITIZEN_CARD)) {
+                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)
+                        .init(personBalancePayService)
+
+                ResponseEntity.ok(ResponseBodyBuilder.create()
+                        .data("refno", dtl.refno)
+                        .data("amount", dtl.amount)
+                        .success("交易初始化成功"))
+            }
 
             ResponseEntity.ok(ResponseBodyBuilder.create()
-                    .data("refno", dtl.refno)
-                    .data("amount", dtl.amount)
-                    .success("交易初始化成功"))
+                    .fail(TradeErrorCode.BUSINESS_PAYTYPE_NOSUPPORT, "不支持支付方式<市民卡代扣>"))
 
         } catch (ex: RequestParamCheckException) {
             ResponseEntity.ok(ResponseBodyBuilder.create()
@@ -166,6 +171,9 @@
         }
     }
 
+    /**
+     * 账户余额支付
+     * */
     @PostMapping("/balance/pay")
     fun balancePay(@RequestBody param: CitizenCardPayinitParam, request: HttpServletRequest, response: HttpServletResponse): ResponseEntity<Any> {
         return try {
@@ -175,29 +183,34 @@
             }
 
             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)
+            if (consumePayService.checkShopPaytype(param.shopaccno, TradeDict.PAYTYPE_BALANCE)) {
+                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)
+                        .done(personBalancePayService)
+
+                ResponseEntity.ok(ResponseBodyBuilder.create()
+                        .data("refno", dtl.refno)
+                        .data("amount", dtl.amount)
+                        .success("交易成功"))
+            }
 
             ResponseEntity.ok(ResponseBodyBuilder.create()
-                    .data("refno", dtl.refno)
-                    .data("amount", dtl.amount)
-                    .success("交易成功"))
+                    .fail(TradeErrorCode.BUSINESS_PAYTYPE_NOSUPPORT, "不支持支付方式<账户余额>"))
 
         } catch (ex: RequestParamCheckException) {
             ResponseEntity.ok(ResponseBodyBuilder.create()
@@ -208,6 +221,59 @@
         }
     }
 
+    /**
+     * 一卡通支付
+     * */
+    @PostMapping("/ykt/payinit")
+    fun yktPayInit(@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, "参数签名错误"))
+            }
+
+            var person = userService.findByThirdUniqueIdenty(param.cardNo) //可能匿名?
+            if (consumePayService.checkShopPaytype(param.shopaccno, TradeDict.PAYTYPE_YKT_CARD, person==null)) {
+                val dtl = PersonTransBuilder.newBuilder(accountUtilServcie)
+                        .chooseTradetype(Tradetype.CONSUME) //消费
+                        .also {
+                            if(null!=person) it.setOwner(person)
+                        }
+                        .setTransinfo(TradeCode.TRANSCODE_PAY, "支付交易")
+                        .setTransDatetime(param.transdate, param.transtime) //交易时间
+                        .selectPaytype(TradeDict.PAYTYPE_YKT_CARD, param.cardNo)
+                        .addDetail(AccountHolder.subject(Subject.SUBJNO_PAY_YKT),
+                                AccountHolder.shop(param.shopaccno),
+                                param.amount / 100.0, "一卡通支付")
+                        .also { builder ->
+                            param.feelist?.forEach {
+                                builder.addDetail(AccountHolder.feetype(it.feetype, TradeDict.PAYTYPE_YKT_CARD)
+                                        .with(AccountHolder.shop(param.shopaccno))
+                                        .with(AccountHolder.subject(Subject.SUBJNO_PAY_YKT))
+                                        , it.amount / 100.0)
+                            }
+                        }
+                        .init(personBalancePayService)
+
+                ResponseEntity.ok(ResponseBodyBuilder.create()
+                        .data("refno", dtl.refno)
+                        .data("amount", dtl.amount)
+                        .success("交易初始化成功"))
+
+
+            }
+
+            ResponseEntity.ok(ResponseBodyBuilder.create()
+                    .fail(TradeErrorCode.BUSINESS_PAYTYPE_NOSUPPORT, "不支持支付方式<一卡通支付>"))
+        } catch (ex: RequestParamCheckException) {
+            ResponseEntity.ok(ResponseBodyBuilder.create()
+                    .requestException(ex, "请求参数错误"))
+        } catch (et: TransactionException) {
+            ResponseEntity.ok(ResponseBodyBuilder.create()
+                    .transException(et, "业务处理错误"))
+        }
+    }
+
 // ============================================== //
 //
 //    @GetMapping("/account/payinit")
@@ -231,62 +297,8 @@
 //                .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> {
diff --git a/src/main/kotlin/com/supwisdom/dlpay/api/service/consume_pay_service.kt b/src/main/kotlin/com/supwisdom/dlpay/api/service/consume_pay_service.kt
index 5d85e0f..a81b21a 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/api/service/consume_pay_service.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/api/service/consume_pay_service.kt
@@ -5,8 +5,8 @@
 
 interface ConsumePayService{
     @Transactional(propagation = Propagation.REQUIRED, rollbackFor = arrayOf(Exception::class))
-    fun checkShopPaytype(shopaccno: String, paytype: String): Boolean
+    fun checkShopPaytype(shopaccno: String, paytype: String, anonymousflag: Boolean? = false): Boolean
 
     @Transactional(propagation = Propagation.REQUIRED, rollbackFor = arrayOf(Exception::class))
-    fun getPaytypeConfig(paytype: String, shopaccno: String, ignoreStatus: Boolean? = false): Map<String, String?>
+    fun getPaytypeConfig(paytype: String, shopaccno: String, anonymousflag: Boolean? = false, ignoreStatus: Boolean? = false): Map<String, String?>
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/Consume_pay_service_impl.kt b/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/Consume_pay_service_impl.kt
index cdb134b..6f36155 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/Consume_pay_service_impl.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/Consume_pay_service_impl.kt
@@ -20,7 +20,7 @@
     @Autowired
     lateinit var shopPaytypeConfigDao: ShopPaytypeConfigDao
 
-    override fun checkShopPaytype(shopaccno: String, paytype: String): Boolean{
+    override fun checkShopPaytype(shopaccno: String, paytype: String, anonymousflag: Boolean?): Boolean{
         paytypeDao.getByPaytype(paytype).let {
             if (null == it) {
                 throw TransactionProcessException(TradeErrorCode.INPUT_DATA_ERROR, "系统不支持支付方式[$paytype]")
@@ -28,6 +28,9 @@
                 if (ConstantUtil.ENABLE_YES != it.enable || ConstantUtil.ENABLE_YES != it.consumeEnable) {
                     throw TransactionProcessException(TradeErrorCode.INPUT_DATA_ERROR, "系统未启用支付方式[$paytype]消费")
                 }
+                if (true == anonymousflag && ConstantUtil.ENABLE_YES != it.anonymousEnable) {
+                    throw TransactionProcessException(TradeErrorCode.INPUT_DATA_ERROR, "系统支付方式[$paytype]未启用匿名消费")
+                }
             }
         }
         shopPaytypeDao.getById(paytype, shopaccno).let {
@@ -37,12 +40,15 @@
                 if (ConstantUtil.ENABLE_YES != it.consumeEnable) {
                     throw TransactionProcessException(TradeErrorCode.INPUT_DATA_ERROR, "该商户[$shopaccno]未启用支付方式[$paytype]")
                 }
+                if (true == anonymousflag && ConstantUtil.ENABLE_YES != it.anonymousEnable) {
+                    throw TransactionProcessException(TradeErrorCode.INPUT_DATA_ERROR, "该商户[$shopaccno]的支付方式[$paytype]未启用匿名消费")
+                }
             }
         }
         return true
     }
 
-    override fun getPaytypeConfig(paytype: String, shopaccno: String, ignoreStatus: Boolean?): Map<String, String?> {
+    override fun getPaytypeConfig(paytype: String, shopaccno: String, anonymousflag: Boolean?, ignoreStatus: Boolean?): Map<String, String?> {
         paytypeDao.getByPaytype(paytype).let {
             if (null == it) {
                 throw TransactionProcessException(TradeErrorCode.INPUT_DATA_ERROR, "系统不支持支付方式[$paytype]")
@@ -50,6 +56,9 @@
                 if (true != ignoreStatus && (ConstantUtil.ENABLE_YES != it.enable || ConstantUtil.ENABLE_YES != it.consumeEnable)) {
                     throw TransactionProcessException(TradeErrorCode.INPUT_DATA_ERROR, "系统未启用支付方式[$paytype]消费")
                 }
+                if (true != ignoreStatus && true == anonymousflag && ConstantUtil.ENABLE_YES != it.anonymousEnable) {
+                    throw TransactionProcessException(TradeErrorCode.INPUT_DATA_ERROR, "系统支付方式[$paytype]未启用匿名消费")
+                }
             }
         }
 
@@ -60,6 +69,9 @@
                 if (true != ignoreStatus && ConstantUtil.ENABLE_YES != it.consumeEnable) {
                     throw TransactionProcessException(TradeErrorCode.INPUT_DATA_ERROR, "该商户[$shopaccno]未启用支付方式[$paytype]")
                 }
+                if (true != ignoreStatus && true == anonymousflag && ConstantUtil.ENABLE_YES != it.anonymousEnable) {
+                    throw TransactionProcessException(TradeErrorCode.INPUT_DATA_ERROR, "该商户[$shopaccno]的支付方式[$paytype]未启用匿名消费")
+                }
             }
         }