交易细节修改
diff --git a/src/main/java/com/supwisdom/dlpay/api/dao/UserdtlBusinessDao.java b/src/main/java/com/supwisdom/dlpay/api/dao/UserdtlBusinessDao.java
new file mode 100644
index 0000000..347e79a
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/api/dao/UserdtlBusinessDao.java
@@ -0,0 +1,10 @@
+package com.supwisdom.dlpay.api.dao;
+
+import com.supwisdom.dlpay.api.domain.TUserdtlBusiness;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface UserdtlBusinessDao extends JpaRepository<TUserdtlBusiness, String> {
+  TUserdtlBusiness getByRefno(String refno);
+}
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 72181db..007cff7 100644
--- a/src/main/java/com/supwisdom/dlpay/api/dao/UserdtlDao.java
+++ b/src/main/java/com/supwisdom/dlpay/api/dao/UserdtlDao.java
@@ -27,4 +27,6 @@
   @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);
+
+  TUserdtl findByOuttradenoAndShopaccno(String outtradeno,String shopaccno);
 }
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 be80103..088cb9e 100644
--- a/src/main/java/com/supwisdom/dlpay/api/domain/TPaytype.java
+++ b/src/main/java/com/supwisdom/dlpay/api/domain/TPaytype.java
@@ -16,13 +16,13 @@
     private String enable;
 
     @Column(name = "CHARGE_ENABLE", nullable = false, length = 10)
-    private String chargeEnable;
+    private String chargeEnable; //充值总开关
 
     @Column(name = "CONSUME_ENABLE",nullable = false, length = 10)
-    private String consumeEnable;
+    private String consumeEnable; //消费总开关
 
     @Column(name = "ANONYMOUS_ENABLE", nullable = false, length = 10)
-    private String anonymousEnable;
+    private String anonymousEnable; //匿名消费总开关
 
     @Column(name = "PAYDESC",  length = 200)
     private String 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 cb4662e..a9b95f1 100644
--- a/src/main/java/com/supwisdom/dlpay/api/domain/TShopPaytype.java
+++ b/src/main/java/com/supwisdom/dlpay/api/domain/TShopPaytype.java
@@ -15,13 +15,13 @@
   private String paytype;
 
   @Column(name = "CONSUME_ENABLE", nullable = false, length = 10)
-  private String consumeEnable;
+  private String consumeEnable; //该商户下,此支付方式能否消费
 
   @Column(name = "ANONYMOUS_ENABLE", nullable = false, length = 10)
-  private String anonymousEnable;
+  private String anonymousEnable; //该商户下,此支付方式能否匿名消费
 
   @Column(name = "REVERSE_ENABLE", nullable = false, length = 10)
-  private String reverseEnable;
+  private String reverseEnable; //该商户下,此支付方式能否冲正
 
   @Column(name = "CREATETIME", length = 14)
   private String createtime;
diff --git a/src/main/java/com/supwisdom/dlpay/api/domain/TUserdtlBusiness.java b/src/main/java/com/supwisdom/dlpay/api/domain/TUserdtlBusiness.java
index cb5e67c..42ed8ca 100644
--- a/src/main/java/com/supwisdom/dlpay/api/domain/TUserdtlBusiness.java
+++ b/src/main/java/com/supwisdom/dlpay/api/domain/TUserdtlBusiness.java
@@ -29,7 +29,7 @@
     this.jsonContent = jsonContent;
   }
 
-  public TUserdtlBusiness(String refno, Map<String, Object> map) {
+  public TUserdtlBusiness(String refno, Map<String, String> map) {
     this.refno = refno;
     if (null == map || map.isEmpty()) {
       this.jsonContent = "";
@@ -54,10 +54,10 @@
     this.jsonContent = jsonContent;
   }
 
-  public Map<String, Object> getContentMap() {
-    Map<String, Object> map = new HashMap<>(0);
+  public Map<String, String> getContentMap() {
+    Map<String, String> map = new HashMap<>(0);
     if (!StringUtil.isEmpty(this.jsonContent))
-      map = gsonUtil.fromJson(this.jsonContent, new TypeToken<Map<String, Object>>() {
+      map = gsonUtil.fromJson(this.jsonContent, new TypeToken<Map<String, String>>() {
       }.getType());
     return map;
   }
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 5c51c26..20cd922 100644
--- a/src/main/java/com/supwisdom/dlpay/framework/util/TradeCode.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/util/TradeCode.java
@@ -4,8 +4,11 @@
  * 交易码、交易类型
  * */
 public class TradeCode {
-  public static final int TRANSCODE_PAY = 3000;
-  public static final int TRANSCODE_YKTPAY=1000;
+  public static final int TRANSCODE_BALANCE_PAY = 3000; //账户余额支付
+  public static final int TRANSCODE_CITIZENCARD_PAY=3010; //市民卡代扣消费
+  public static final int TRANSCODE_YKTCARD_PAY=3020; //一卡通支付
+
+
   public static final int TRANSCODE_WECHAT=1001;
 
 
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 a8139c9..336239e 100644
--- a/src/main/java/com/supwisdom/dlpay/framework/util/TradeErrorCode.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/util/TradeErrorCode.java
@@ -100,6 +100,12 @@
   public static final int FEETYPE_NOT_EXISTS = 10018;
 
   /**
+   * 费用类别不支持
+   * */
+  public static final int FEETYPE_NOT_NOSUPPORT = 10019;
+
+
+  /**
    * 请求参数错误
    * */
   public static final int REQUEST_PARAM_ERROR = 20000;
diff --git a/src/main/kotlin/com/supwisdom/dlpay/api/ThirdPayCall.kt b/src/main/kotlin/com/supwisdom/dlpay/api/ThirdPayCall.kt
index d02ba57..4902e84 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/api/ThirdPayCall.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/api/ThirdPayCall.kt
@@ -23,8 +23,8 @@
 class CallService {
 
     companion object {
-        fun callYktPay(config: Map<String, String>, paydtl: TUserdtl, time: String, stuempno: String, yktshopid: String, devphyid: String?): BaseResp {
-            val code = BaseResp()
+        fun callYktPay(config: Map<String, String?>, paydtl: TUserdtl, time: String, stuempno: String, yktshopid: String, devphyid: String?): CallBackResp {
+            val code = CallBackResp()
             val appid = config["appid"]
             if (appid.isNullOrEmpty()) {
                 code.retcode = "1"
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 414da8e..f498fee 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
@@ -212,6 +212,42 @@
     }
 }
 
+class YktCardPayinitParam : APIRequestParam() {
+    @Sign
+    var uid: String? = null //未注册,可能不传
+    @Sign
+    var shopaccno: String = "" //必传
+    @Sign
+    var amount: Int = 0 //必传
+
+    var feelist: List<ConsumeFeetype>? = null //TODO: 怎么拼接签名字符串??
+    @Sign
+    var billno: String = "" //必传
+    @Sign
+    var transdate: String = "" //必传
+    @Sign
+    var transtime: String = "" //必传
+    @Sign
+    var stuempno: String = "" //必传
+    @Sign
+    var yktshopid: String? = null
+    @Sign
+    var devphyid: String? = null
+
+    fun checkParam(): Boolean {
+
+        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]")
+        if (StringUtil.isEmpty(stuempno)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "一卡通唯一号不能为空")
+        if(!StringUtil.isEmpty(yktshopid) && !NumberUtil.isDigits(yktshopid)) throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "一卡通商户号非整数")
+
+        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 2c1555c..ff29e99 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/api/comsume_builder.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/api/comsume_builder.kt
@@ -86,6 +86,7 @@
     lateinit var refno: String
     lateinit var status: String
     lateinit var shopaccno: String
+    val extendMap = mutableMapOf<String, String>() //存调第三方需要的参数信息
     val resultMap = mutableMapOf<String, String>() //存调第三方结果数据
 
     var transcode = 0
@@ -167,6 +168,15 @@
         return this
     }
 
+    fun addExtendParam(key: String, value: String): PersonTransBuilder {
+        this.extendMap.plus(mapOf(key to value))
+        return this
+    }
+
+    fun addExtendParam(param: Map<String, String>): PersonTransBuilder {
+        this.extendMap.plus(param)
+        return this
+    }
     fun addResult(key: String, value: String): PersonTransBuilder {
         this.resultMap.plus(mapOf(key to value))
         return this
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 a35b8ce..066e43c 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
@@ -6,9 +6,11 @@
 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.bean.YktCardPayinitParam
 import com.supwisdom.dlpay.api.service.*
 import com.supwisdom.dlpay.exception.RequestParamCheckException
 import com.supwisdom.dlpay.exception.TransactionException
+import com.supwisdom.dlpay.exception.TransactionProcessException
 import com.supwisdom.dlpay.framework.ResponseBodyBuilder
 import com.supwisdom.dlpay.framework.service.CommonService
 import com.supwisdom.dlpay.framework.service.SystemUtilService
@@ -78,7 +80,75 @@
     }
 
     /**
-     * 市民卡交易初始化
+     * ============================================================================
+     *                           账户【余额支付】
+     * ============================================================================
+     * */
+    @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)
+            if (consumePayService.checkShopPaytype(param.shopaccno, TradeDict.PAYTYPE_BALANCE)) {
+                val dtl = PersonTransBuilder.newBuilder(accountUtilServcie)
+                        .chooseTradetype(Tradetype.CONSUME) //消费
+                        .setOwner(person) //记名
+                        .setTransinfo(TradeCode.TRANSCODE_BALANCE_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 {
+                                when(it.feetype){
+                                    TradeDict.FEETYPE_CONSUME_MEALER -> {
+                                        if (it.amount <= 0) {
+                                            throw RequestParamCheckException(TradeErrorCode.REQUEST_PARAM_ERROR, "费用类别<${it.feetype}>的金额不能为负")
+                                        }
+                                        builder.addDetail(AccountHolder.feetype(it.feetype, TradeDict.PAYTYPE_BALANCE)
+                                                .with(AccountHolder.shop(param.shopaccno))
+                                                .with(AccountHolder.person(person.userid))
+                                                , it.amount / 100.0)
+                                    }
+                                    TradeDict.FEETYPE_CONSUME_DISCOUNT->{
+                                        TODO("折扣逻辑暂缺")
+                                    }
+                                    else -> throw TransactionProcessException(TradeErrorCode.FEETYPE_NOT_NOSUPPORT, "费用类别<${it.feetype}>不支持")
+                                }
+
+                            }
+                        }
+                        .done(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, "业务处理错误"))
+        }
+    }
+
+
+
+    /**
+     * ============================================================================
+     *                           市民卡【交易初始化】
+     * ============================================================================
      * */
     @PostMapping("/citizencard/payinit")
     fun citizencardPayinit(@RequestBody param: CitizenCardPayinitParam, request: HttpServletRequest, response: HttpServletResponse): ResponseEntity<Any> {
@@ -93,7 +163,7 @@
                 val dtl = PersonTransBuilder.newBuilder(accountUtilServcie)
                         .chooseTradetype(Tradetype.CONSUME) //消费
                         .setOwner(person) //记名
-                        .setTransinfo(TradeCode.TRANSCODE_PAY, "支付交易")
+                        .setTransinfo(TradeCode.TRANSCODE_CITIZENCARD_PAY, "市民卡代扣消费")
                         .setTransDatetime(param.transdate, param.transtime) //交易时间
                         .selectPaytype(TradeDict.PAYTYPE_CITIZEN_CARD, param.cardNo)
                         .addDetail(AccountHolder.subject(Subject.SUBJNO_PAY_CITIZEN_CARD),
@@ -101,6 +171,7 @@
                                 param.amount / 100.0, "市民卡代扣消费")
                         .also { builder ->
                             param.feelist?.forEach {
+                                //fixme: 科目 -> 商户 与个人无关
                                 builder.addDetail(AccountHolder.feetype(it.feetype, TradeDict.PAYTYPE_CITIZEN_CARD)
                                         .with(AccountHolder.shop(param.shopaccno))
                                         .with(AccountHolder.subject(Subject.SUBJNO_PAY_CITIZEN_CARD))
@@ -128,7 +199,9 @@
     }
 
     /**
-     * 市民卡交易确认
+     * ============================================================================
+     *                           市民卡【交易确认】
+     * ============================================================================
      * */
     @PostMapping("/citizencard/payfinish")
     fun citizencardPayinit(@RequestBody param: CitizenCardPayfinishParam, request: HttpServletRequest, response: HttpServletResponse): ResponseEntity<Any> {
@@ -141,7 +214,7 @@
             var dtl = PersonTransBuilder.newBuilder(accountUtilServcie)
                     .setRefno(param.refno)
                     .wip(personBalancePayService)
-            val code = CallService.CallCitizenCardPay(consumePayService.getPaytypeConfig(TradeDict.PAYTYPE_CITIZEN_CARD, "shopaccno"), dtl)
+            val code = CallService.CallCitizenCardPay(consumePayService.getPaytypeConfig(TradeDict.PAYTYPE_CITIZEN_CARD, dtl.shopaccno), dtl)
             if (code.retcode == "0") {
                 dtl = PersonTransBuilder.newBuilder(accountUtilServcie)
                         .setRefno(param.refno)
@@ -171,47 +244,58 @@
         }
     }
 
+
+
     /**
-     * 账户余额支付
+     * ============================================================================
+     *                           一卡通支付【交易初始化】
+     * ============================================================================
      * */
-    @PostMapping("/balance/pay")
-    fun balancePay(@RequestBody param: CitizenCardPayinitParam, request: HttpServletRequest, response: HttpServletResponse): ResponseEntity<Any> {
+    @PostMapping("/ykt/payinit")
+    fun yktPayInit(@RequestBody param: YktCardPayinitParam, 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)
-            if (consumePayService.checkShopPaytype(param.shopaccno, TradeDict.PAYTYPE_BALANCE)) {
+            val person = param.uid?.let { userService.findByThirdUniqueIdenty(it) } ?: null //没注册,可能匿名?
+            if (consumePayService.checkShopPaytype(param.shopaccno, TradeDict.PAYTYPE_YKT_CARD, person==null)) {
                 val dtl = PersonTransBuilder.newBuilder(accountUtilServcie)
                         .chooseTradetype(Tradetype.CONSUME) //消费
-                        .setOwner(person) //记名
-                        .setTransinfo(TradeCode.TRANSCODE_PAY, "支付交易")
+                        .also {
+                            if (null != person) it.setOwner(person)
+                        }
+                        .setTransinfo(TradeCode.TRANSCODE_YKTCARD_PAY, "一卡通支付")
                         .setTransDatetime(param.transdate, param.transtime) //交易时间
-                        .selectPaytype(TradeDict.PAYTYPE_BALANCE, param.cardNo)
-                        .addDetail(AccountHolder.person(person.userid),
+                        .selectPaytype(TradeDict.PAYTYPE_YKT_CARD, param.stuempno)
+                        .addDetail(AccountHolder.subject(Subject.SUBJNO_PAY_YKT),
                                 AccountHolder.shop(param.shopaccno),
-                                param.amount / 100.0, "账户余额消费")
+                                param.amount / 100.0, "一卡通支付")
                         .also { builder ->
                             param.feelist?.forEach {
-                                builder.addDetail(AccountHolder.feetype(it.feetype, TradeDict.PAYTYPE_BALANCE)
+                                //fixme: 科目 -> 商户 与个人无关
+                                builder.addDetail(AccountHolder.feetype(it.feetype, TradeDict.PAYTYPE_YKT_CARD)
                                         .with(AccountHolder.shop(param.shopaccno))
-                                        .with(AccountHolder.person(person.userid))
+                                        .with(AccountHolder.subject(Subject.SUBJNO_PAY_YKT))
                                         , it.amount / 100.0)
                             }
                         }
-                        .done(personBalancePayService)
+                        .addExtendParam("stuempno", param.stuempno)
+                        .addExtendParam("yktshopid", param.yktshopid ?: "")
+                        .addExtendParam("devphyid", param.devphyid ?: "")
+                        //.addExtendParam(param.extendmap)  //fixme: 保存调一卡通附加参数 (是否直接传附加参数map)
+                        .init(personBalancePayService)
 
                 ResponseEntity.ok(ResponseBodyBuilder.create()
                         .data("refno", dtl.refno)
                         .data("amount", dtl.amount)
-                        .success("交易成功"))
+                        .success("交易初始化成功"))
+
             }
 
             ResponseEntity.ok(ResponseBodyBuilder.create()
-                    .fail(TradeErrorCode.BUSINESS_PAYTYPE_NOSUPPORT, "不支持支付方式<账户余额>"))
-
+                    .fail(TradeErrorCode.BUSINESS_PAYTYPE_NOSUPPORT, "不支持支付方式<一卡通支付>"))
         } catch (ex: RequestParamCheckException) {
             ResponseEntity.ok(ResponseBodyBuilder.create()
                     .requestException(ex, "请求参数错误"))
@@ -221,51 +305,47 @@
         }
     }
 
+
     /**
-     * 一卡通支付
+     * ============================================================================
+     *                           一卡通支付【交易确认】
+     * ============================================================================
      * */
-    @PostMapping("/ykt/payinit")
-    fun yktPayInit(@RequestBody param: CitizenCardPayinitParam, request: HttpServletRequest, response: HttpServletResponse): ResponseEntity<Any> {
+    @PostMapping("/ykt/payfinish")
+    fun yktPayFinish(@RequestBody param:CitizenCardPayfinishParam,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)
+            var dtl = PersonTransBuilder.newBuilder(accountUtilServcie)
+                    .setRefno(param.refno)
+                    .wip(personBalancePayService)
+            val extendMap = consumePayService.getUserdtlExtendParamMap(dtl.refno)
+            val code = CallService.callYktPay(consumePayService.getPaytypeConfig(TradeDict.PAYTYPE_YKT_CARD, dtl.shopaccno, dtl.userid==null),
+                    dtl, DateUtil.getNow(), extendMap["stuempno"]!!, extendMap["yktshopid"]!!, extendMap["devphyid"])
+            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("amount", dtl.amount)
-                        .success("交易初始化成功"))
+                        .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.BUSINESS_DEAL_ERROR, "交易扣费失败-${code.retmsg}"))
             }
 
-            ResponseEntity.ok(ResponseBodyBuilder.create()
-                    .fail(TradeErrorCode.BUSINESS_PAYTYPE_NOSUPPORT, "不支持支付方式<一卡通支付>"))
-        } catch (ex: RequestParamCheckException) {
+        }catch (ex: RequestParamCheckException) {
             ResponseEntity.ok(ResponseBodyBuilder.create()
                     .requestException(ex, "请求参数错误"))
         } catch (et: TransactionException) {
@@ -299,31 +379,7 @@
 //    }
 
 
-//
-//    @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, "交易确认失败"))
-//        }
-//    }
+
 //
 //    /**
 //     * 微信支付
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 a81b21a..54d8475 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
@@ -9,4 +9,7 @@
 
     @Transactional(propagation = Propagation.REQUIRED, rollbackFor = arrayOf(Exception::class))
     fun getPaytypeConfig(paytype: String, shopaccno: String, anonymousflag: Boolean? = false, ignoreStatus: Boolean? = false): Map<String, String?>
+
+    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = arrayOf(Exception::class))
+    fun getUserdtlExtendParamMap(refno: String): 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 6f36155..3c40253 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
@@ -1,9 +1,10 @@
 package com.supwisdom.dlpay.api.service.impl
 
-import com.supwisdom.dlpay.api.dao.PaytypeConfigDao
 import com.supwisdom.dlpay.api.dao.PaytypeDao
 import com.supwisdom.dlpay.api.dao.ShopPaytypeConfigDao
 import com.supwisdom.dlpay.api.dao.ShopPaytypeDao
+import com.supwisdom.dlpay.api.dao.UserdtlBusinessDao
+import com.supwisdom.dlpay.api.domain.TUserdtlBusiness
 import com.supwisdom.dlpay.api.service.ConsumePayService
 import com.supwisdom.dlpay.exception.TransactionProcessException
 import com.supwisdom.dlpay.framework.util.TradeErrorCode
@@ -19,6 +20,8 @@
     lateinit var shopPaytypeDao: ShopPaytypeDao
     @Autowired
     lateinit var shopPaytypeConfigDao: ShopPaytypeConfigDao
+    @Autowired
+    lateinit var userdtlBusinessDao: UserdtlBusinessDao
 
     override fun checkShopPaytype(shopaccno: String, paytype: String, anonymousflag: Boolean?): Boolean{
         paytypeDao.getByPaytype(paytype).let {
@@ -53,6 +56,7 @@
             if (null == it) {
                 throw TransactionProcessException(TradeErrorCode.INPUT_DATA_ERROR, "系统不支持支付方式[$paytype]")
             } else {
+                //对账取配置时不关心状态,不能报错
                 if (true != ignoreStatus && (ConstantUtil.ENABLE_YES != it.enable || ConstantUtil.ENABLE_YES != it.consumeEnable)) {
                     throw TransactionProcessException(TradeErrorCode.INPUT_DATA_ERROR, "系统未启用支付方式[$paytype]消费")
                 }
@@ -66,6 +70,7 @@
             if (null == it) {
                 throw TransactionProcessException(TradeErrorCode.INPUT_DATA_ERROR, "该商户[$shopaccno]未启用支付方式[$paytype]")
             } else {
+                //对账取配置时不关心状态,不能报错
                 if (true != ignoreStatus && ConstantUtil.ENABLE_YES != it.consumeEnable) {
                     throw TransactionProcessException(TradeErrorCode.INPUT_DATA_ERROR, "该商户[$shopaccno]未启用支付方式[$paytype]")
                 }
@@ -85,4 +90,10 @@
             }
         } ?: throw TransactionProcessException(TradeErrorCode.INPUT_DATA_ERROR, "该商户[$shopaccno]的支付方式[$paytype]未配置参数")
     }
+
+    override fun getUserdtlExtendParamMap(refno: String): Map<String, String> {
+        return userdtlBusinessDao.getByRefno(refno)?.let {
+            it.contentMap
+        } ?: mutableMapOf<String, String>()
+    }
 }
\ No newline at end of file
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 7ef63a5..a322f11 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
@@ -3,22 +3,20 @@
 import com.supwisdom.dlpay.api.PersonTransBuilder
 import com.supwisdom.dlpay.api.dao.AccountDao
 import com.supwisdom.dlpay.api.dao.DebitCreditDtlDao
+import com.supwisdom.dlpay.api.dao.UserdtlBusinessDao
 import com.supwisdom.dlpay.api.dao.UserdtlDao
 import com.supwisdom.dlpay.api.domain.TAccount
 import com.supwisdom.dlpay.api.domain.TDebitCreditDtl
 import com.supwisdom.dlpay.api.domain.TUserdtl
+import com.supwisdom.dlpay.api.domain.TUserdtlBusiness
 import com.supwisdom.dlpay.api.service.AccountUtilServcie
 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.dao.*
 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.service.SystemUtilService
 import com.supwisdom.dlpay.framework.util.*
 import org.hibernate.exception.LockTimeoutException
@@ -44,7 +42,6 @@
     @Autowired
     lateinit var feetypeConfigDao: FeetypeConfigDao
 
-
     override fun readAccountForUpdateNowait(userid: String): TAccount {
         return try {
             accountDao.getByUseridForUpdateNowait(userid)
@@ -88,6 +85,9 @@
     @Autowired
     lateinit var accountDao: AccountDao
 
+    @Autowired
+    lateinit var userdtlBusinessDao: UserdtlBusinessDao
+
     @PersistenceContext
     lateinit var em: EntityManager
 
@@ -129,11 +129,6 @@
                 ?: throw TransactionProcessException(TradeErrorCode.TRANSACTION_NOT_EXISTS, "交易参考号<$refno>不存在")
     }
 
-    private fun checkOuttradenoExist(outtradeno: String): Boolean {
-//        TODO("判断 outtradeno 重复发起")
-        return false
-    }
-
     private fun doDealAccount(accno: String, amount: Double, overdraft: Boolean): TAccount {
         val account = getlockAccount(accno)
         if (account.tacCheck())
@@ -158,7 +153,21 @@
     }
 
     override fun init(builder: PersonTransBuilder): TUserdtl {
-        val userdtl = TUserdtl()
+        //判断第三方流水号重复  标准:shopaccno + outtradeno 唯一?
+        var userdtl = userdtlDao.findByOuttradenoAndShopaccno(builder.outtradeno, builder.shopaccno) //加锁?
+        if (null != userdtl) {
+            if (TradeDict.DTL_STATUS_INIT != userdtl.status) {
+                throw TransactionProcessException(TradeErrorCode.OUTTRADENO_ALREADY_EXISTS, "外部流水号重复") //非初始化状态,直接报错
+            }
+            //fixme: 判断是同一笔交易重发(标准??)  是->已初始化直接返回;否 -> 报错:外部流水号重复
+            if(builder.amount == userdtl.amount && builder.paytype == userdtl.paytype && builder.transDate == userdtl.transdate && builder.transTime==userdtl.transtime){
+                return userdtl // 交易日期,时间重发时是否会变??
+            }else{
+                throw TransactionProcessException(TradeErrorCode.OUTTRADENO_ALREADY_EXISTS, "外部流水号重复")
+            }
+        }
+
+        userdtl = TUserdtl() // 新建流水
         userdtl.refno = systemUtilService.refno
         userdtl.accdate = systemUtilService.accdate
         userdtl.userid = builder.person.userid
@@ -176,20 +185,18 @@
         userdtl.payinfo = builder.payinfo
         userdtl.transcode = builder.transcode
         if (StringUtil.isEmpty(builder.description)) {
-            userdtl.transdesc = systemUtilService.getTranscodeName(builder.transcode, null);
+            userdtl.transdesc = systemUtilService.getTranscodeName(builder.transcode, null)
         } else {
             userdtl.transdesc = builder.description
         }
         userdtl.outtradeno = builder.outtradeno
+        userdtl.shopaccno = builder.shopaccno
 //        userdtl.operid =
         when (builder.tradetype) {
             Tradetype.RECHARGE -> userdtl.tradeflag = 1
             Tradetype.CONSUME -> userdtl.tradeflag = 2
         }
         userdtl.createtime = systemUtilService.sysdatetime.hostdatetime
-        if (checkOuttradenoExist(userdtl.outtradeno)) {
-            throw TransactionProcessException(TradeErrorCode.OUTTRADENO_ALREADY_EXISTS, "外部流水号重复")
-        }
 
         userdtl.amount = builder.amount
         userdtl.status = TradeDict.DTL_STATUS_INIT
@@ -208,6 +215,11 @@
                 debitCreditDtlDao.save(this)
             }
         }
+
+        if(builder.extendMap.isNotEmpty()){
+            userdtlBusinessDao.save(TUserdtlBusiness(userdtl.refno, builder.extendMap)) //保存参数
+        }
+
         return userdtl
     }
 
diff --git a/src/main/kotlin/com/supwisdom/dlpay/framework/framework_util.kt b/src/main/kotlin/com/supwisdom/dlpay/framework/framework_util.kt
index 894ad77..0293457 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/framework/framework_util.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/framework/framework_util.kt
@@ -74,7 +74,9 @@
         if (retCode == INVALIDE_RETCODE) {
             throw TransactionCheckException(TradeErrorCode.INPUT_DATA_ERROR, "未设置返回码!")
         } else if (retCode != 0) {
-            LOGGER.error(Gson().toJson(this.respData))
+            LOGGER.error("【 ==== ERROR ==== 】: " + Gson().toJson(this.respData))
+        }else{
+            LOGGER.info("retcode=[0],retmsg=[$retMsg] return success!!! \n" + Gson().toJson(this.respData))
         }
         return this.respData.plus(mapOf("retcode" to retCode, "retmsg" to retMsg))
     }