Merge tag '1.0.32' into develop

农商行快捷支付
diff --git a/build.gradle b/build.gradle
index 2acc881..296f715 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,31 +1,149 @@
 plugins {
     id 'java'
-    id 'org.springframework.boot' version '2.1.6.RELEASE'
-    id 'io.spring.dependency-management' version '1.0.8.RELEASE'
+    id 'org.springframework.boot' version '2.2.2.RELEASE' apply false
     id 'org.jetbrains.kotlin.jvm' version '1.3.31'
     id 'org.jetbrains.kotlin.plugin.spring' version '1.3.31'
+    id 'org.jetbrains.kotlin.plugin.jpa' version '1.3.31' apply false
     id "com.palantir.git-version" version "0.12.0-rc2"
-    id 'com.palantir.docker' version '0.22.1'
+    id 'com.palantir.docker' version '0.22.1' apply false
 }
 
+group = 'com.supwisdom'
+
 allprojects {
     repositories {
         jcenter()
         mavenCentral()
     }
-    
+    ext {
+        set('junit_jupiter_version', "5.5.2")
+        set("junit_platform_version", "1.5.2")
+        set("mockitoVersion", "3.1.0")
+    }
+
+    apply plugin: 'java'
+    apply plugin: 'io.spring.dependency-management'
+
+    sourceCompatibility = JavaVersion.VERSION_1_8
+    targetCompatibility = JavaVersion.VERSION_1_8
+
+    compileKotlin {
+        kotlinOptions {
+            freeCompilerArgs = ['-Xjsr305=strict']
+            jvmTarget = jdkVersion
+        }
+    }
+
+    compileTestKotlin {
+        kotlinOptions {
+            freeCompilerArgs = ['-Xjsr305=strict']
+            jvmTarget = jdkVersion
+        }
+    }
+
+    version = gitVersion()
+    ext {
+        details = versionDetails()
+    }
 }
 
+
 subprojects {
-    version = '1.0'
-}
 
-bootJar {
-    enabled = false
+    ext {
+        set('springCloudVersion', "Hoxton.RELEASE")
+    }
+
+    dependencies {
+        ext {
+            slf4jVersion = '1.7.26'
+            beanutilsVersion = '1.9.3'
+            codecVersion = '1.13'
+            lang3Version = '3.9'
+            commonCodecVersion = '1.12'
+            lombokVersion = '1.18.8'
+            javaELVersion = '3.0.0'
+            shedlockVersion = '2.5.0'
+            jose4jVersion = '0.6.5'
+            jcabiManifestsVersion = '1.1'
+            kotlnLogVersion = '1.6.26'
+            slf4jVersion = '1.7.26'
+            gsonVersion = '2.8.5'
+            dbcpVersion = '1.4'
+            log4jVersion = '1.2.17'
+            alibabFastjsonVerison = '1.2.60'
+            beanutilsVersion = '1.9.3'
+            alipaySDKVersion = '3.7.110.ALL'
+            lombokVersion = '1.18.8'
+            resetAssuredVersion = '3.3.0'
+            hamcrestVersion = '2.1'
+            mockkVersion = '1.9.3'
+            commonNetVersion = '3.6'
+            kaptchaVersion = '2.3.2'
+            jerseyClientVersion = '1.19'
+            javaxWSRSVersion = '2.1.1'
+            dom4jVersion = '2.1.1'
+            springSocialVersion = '1.1.6.RELEASE'
+            springKafkaVersion = '2.3.4.RELEASE'
+            postgresVersion = '42.2.5'
+        }
+        implementation "org.jetbrains.kotlin:kotlin-reflect"
+        implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
+
+        implementation "org.springframework.boot:spring-boot-starter"
+        implementation "org.springframework.boot:spring-boot-starter-data-jpa"
+        implementation "org.springframework.boot:spring-boot-starter-data-redis"
+        implementation "org.springframework.boot:spring-boot-starter-validation"
+
+        implementation "javax.validation:validation-api"
+        implementation "com.jcabi:jcabi-manifests:${jcabiManifestsVersion}"
+        implementation "org.slf4j:slf4j-parent:${slf4jVersion}"
+        implementation "org.slf4j:slf4j-api:${slf4jVersion}"
+        implementation "org.postgresql:postgresql:${postgresVersion}"
+        implementation "io.github.microutils:kotlin-logging:${kotlnLogVersion}"
+        implementation "com.google.code.gson:gson:${gsonVersion}"
+        implementation "commons-dbcp:commons-dbcp:${dbcpVersion}"
+        implementation "commons-codec:commons-codec:${commonCodecVersion}"
+        implementation "log4j:log4j:${log4jVersion}"
+        implementation "com.alibaba:fastjson:${alibabFastjsonVerison}"
+        implementation "com.fasterxml.jackson.module:jackson-module-kotlin"
+
+
+        annotationProcessor "org.springframework.boot:spring-boot-configuration-processor"
+        annotationProcessor "org.projectlombok:lombok:${lombokVersion}"
+        compileOnly "org.projectlombok:lombok:${lombokVersion}"
+
+        //    implementation "javax.el:javax.el-api:${javaELVersion}"
+        //    implementation "javax.servlet:javax.servlet-api:4.0.1"
+//        testImplementation 'org.springframework:spring-test'
+//        testImplementation 'org.springframework.boot:spring-boot-test'
+//    implementation "javax.servlet:jstl:1.2"
+//    implementation "taglibs:standard:1.1.2"
+        testImplementation "org.springframework.boot:spring-boot-starter-test"
+        testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}"
+        testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}"
+        testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}"
+        testImplementation "io.mockk:mockk:${mockkVersion}"
+        testImplementation "org.hamcrest:hamcrest:${hamcrestVersion}"
+        testImplementation "io.rest-assured:rest-assured:${resetAssuredVersion}"
+        testImplementation "io.rest-assured:spring-mock-mvc:${resetAssuredVersion}"
+    }
+
+    test {
+        useJUnitPlatform()
+        testLogging {
+            events "passed", "skipped", "failed"
+        }
+    }
+
+    dependencyManagement {
+        imports {
+            mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
+        }
+    }
 }
 
 tasks.withType(JavaCompile) {
     options.encoding = "UTF-8"
 }
 
-group = 'com.supwisdom'
\ No newline at end of file
diff --git a/config/application-devel-pg-local.properties b/config/application-devel-pg-local.properties
index 3b2dd4a..1c33450 100644
--- a/config/application-devel-pg-local.properties
+++ b/config/application-devel-pg-local.properties
@@ -3,6 +3,7 @@
 spring.jpa.hibernate.ddl-auto=update
 spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
 spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults=false
+spring.jpa.properties.hibernate.default_schema=public
 spring.datasource.continue-on-error=true
 spring.datasource.initialization-mode=always
 # Postgresql settings
@@ -10,7 +11,6 @@
 spring.datasource.url=jdbc:postgresql://localhost:5432/payapi
 spring.datasource.username=payapi
 spring.datasource.password=123456
-database.dbtype=postgresql
 # Redis settings
 spring.redis.host=localhost
 spring.redis.port=6379
@@ -32,3 +32,26 @@
 resttemplate.proxy.type=http
 resttemplate.proxy.host=127.0.0.1
 resttemplate.proxy.port=1087
+
+#============== kafka ===================
+# 指定kafka 代理地址,可以多个
+spring.kafka.bootstrap-servers=172.28.201.101:9192
+#=============== provider  =======================
+spring.kafka.producer.retries=3
+# 每次批量发送消息的数量
+spring.kafka.producer.batch-size=16384
+spring.kafka.producer.buffer-memory=33554432
+# 指定消息key和消息体的编解码方式
+spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer
+spring.kafka.producer.value-serializer=org.apache.kafka.common.serialization.StringSerializer
+
+#===============kafka consumer  =======================
+# 指定默认消费者group id
+spring.kafka.listen.auto.start=false
+spring.kafka.consumer.group-id=epaymessager1
+spring.kafka.consumer.auto-offset-reset=earliest
+spring.kafka.consumer.enable-auto-commit=true
+spring.kafka.consumer.auto-commit-interval=100
+# 指定消息key和消息体的编解码方式
+spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer
+spring.kafka.consumer.value-deserializer=org.apache.kafka.common.serialization.StringDeserializer
\ No newline at end of file
diff --git a/gradle/swnx-publish.gradle b/gradle/swnx-publish.gradle
new file mode 100644
index 0000000..1350386
--- /dev/null
+++ b/gradle/swnx-publish.gradle
@@ -0,0 +1,14 @@
+publishing {
+    repositories {
+        maven {
+            // change URLs to point to your repos, e.g. http://my.org/repo
+            def releasesRepoUrl = "http://ykt-nx.supwisdom.com/repository/ecard-repo/"
+            def snapshotsRepoUrl = "http://ykt-nx.supwisdom.com/repository/ecard-repo/snapshot/"
+            url = version.endsWith('dirty') ? snapshotsRepoUrl : releasesRepoUrl
+            credentials(PasswordCredentials) {
+                username = nxUser
+                password = nxPassword
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 7e5d2a8..36fd7d1 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.10-all.zip
diff --git a/oauth/build.gradle b/oauth/build.gradle
index 232445f..2854362 100644
--- a/oauth/build.gradle
+++ b/oauth/build.gradle
@@ -2,7 +2,7 @@
     id 'java'
     id 'org.springframework.boot'
     id 'org.jetbrains.kotlin.jvm'
-    id 'org.jetbrains.kotlin.plugin.jpa' version '1.3.31'
+    id 'org.jetbrains.kotlin.plugin.jpa'
     id 'org.jetbrains.kotlin.plugin.spring'
     id "com.palantir.git-version"
 }
@@ -10,11 +10,8 @@
 apply plugin: 'java'
 apply plugin: 'io.spring.dependency-management'
 
-def version = gitVersion()
 def details = versionDetails()
 
-group = rootProject.group
-version = '1'
 sourceCompatibility = jdkVersion
 def startClass = 'com.supwisdom.oauth.OAuthApplication'
 
@@ -38,44 +35,28 @@
 
 
 dependencies {
-    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
-    implementation 'org.springframework.boot:spring-boot-starter-data-redis'
-    implementation 'org.springframework.boot:spring-boot-starter-web'
-    implementation 'org.springframework.boot:spring-boot-starter-security'
-    implementation 'org.springframework.boot:spring-boot-starter-cache'
-    implementation 'org.springframework.boot:spring-boot-autoconfigure'
-    implementation 'org.springframework.security:spring-security-oauth2-jose'
-    implementation 'org.springframework.security:spring-security-oauth2-client'
-    implementation 'org.springframework.security:spring-security-oauth2-jose'
-    implementation 'org.springframework.security.oauth.boot:spring-security-oauth2-autoconfigure:2.1.5.RELEASE'
-    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
-    implementation 'org.springframework.session:spring-session-data-redis'
-    implementation 'org.springframework.boot:spring-boot-starter-cache'
-    implementation 'org.springframework.social:spring-social-web:1.1.6.RELEASE'
-    implementation 'org.jetbrains.kotlin:kotlin-reflect'
-    implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
-    implementation 'commons-codec:commons-codec:1.12'
-    implementation 'org.apache.commons:commons-lang3:3.9'
-    implementation 'net.javacrumbs.shedlock:shedlock-spring:2.5.0'
-    implementation 'net.javacrumbs.shedlock:shedlock-provider-redis-spring:2.5.0'
+    implementation project(":payapi-common")
 
-    implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5'
+    implementation "org.springframework.boot:spring-boot-starter-data-jpa"
+    implementation "org.springframework.boot:spring-boot-starter-data-redis"
+    implementation "org.springframework.boot:spring-boot-starter-web"
+    implementation "org.springframework.boot:spring-boot-starter-security"
+    implementation "org.springframework.boot:spring-boot-starter-cache"
+    implementation "org.springframework.boot:spring-boot-autoconfigure"
+    implementation "org.springframework.security:spring-security-oauth2-jose"
+    implementation "org.springframework.security:spring-security-oauth2-client"
+    implementation "org.springframework.security:spring-security-oauth2-jose"
+    implementation "org.springframework.security.oauth.boot:spring-security-oauth2-autoconfigure"
+    implementation "org.springframework.boot:spring-boot-starter-thymeleaf"
+    implementation "org.springframework.session:spring-session-data-redis"
+    implementation "org.springframework.boot:spring-boot-starter-cache"
 
-    implementation 'org.postgresql:postgresql:42.2.5'
-    implementation 'com.fasterxml.jackson.module:jackson-module-kotlin'
-    implementation 'com.jcabi:jcabi-manifests:1.1'
-    implementation 'org.bitbucket.b_c:jose4j:0.6.5'
-    implementation 'io.github.microutils:kotlin-logging:1.6.26'
-    implementation 'org.slf4j:slf4j-parent:1.7.26'
-
-    implementation 'commons-dbcp:commons-dbcp:1.4'
-
-    implementation project(':payapi-common')
-
-    testImplementation 'org.springframework.boot:spring-boot-starter-test'
-    testImplementation 'io.rest-assured:rest-assured:3.3.0'
-    testImplementation 'io.rest-assured:spring-mock-mvc:3.3.0'
-    testImplementation 'org.hamcrest:hamcrest:2.1'
+    implementation "org.thymeleaf.extras:thymeleaf-extras-springsecurity5"
+    implementation "org.springframework.social:spring-social-web:${springSocialVersion}"
+    implementation "net.javacrumbs.shedlock:shedlock-spring:${shedlockVersion}"
+    implementation "net.javacrumbs.shedlock:shedlock-provider-redis-spring:${shedlockVersion}"
+    implementation "org.bitbucket.b_c:jose4j:${jose4jVersion}"
+    implementation "org.apache.commons:commons-lang3:${lang3Version}"
 
 }
 
diff --git a/oauth/src/main/kotlin/com/supwisdom/oauth/service/impl/OAuthUserServiceImpl.kt b/oauth/src/main/kotlin/com/supwisdom/oauth/service/impl/OAuthUserServiceImpl.kt
index 75c1f0e..afc5d56 100644
--- a/oauth/src/main/kotlin/com/supwisdom/oauth/service/impl/OAuthUserServiceImpl.kt
+++ b/oauth/src/main/kotlin/com/supwisdom/oauth/service/impl/OAuthUserServiceImpl.kt
@@ -71,11 +71,12 @@
     }
 
     override fun findUserInfor(userid: String): UserInfor? {
-        var sql = "select ac.availbal as availbal, ac.LOWFREE_FLAG as lowfreeflag,ac.LOWFREE_LIMIT as lowfreelimit,ac.DAY_LIMIT as daylimit, ac.ACCNAME as name,pa.points " +
+        val sql = "select ac.availbal as availbal, ac.LOWFREE_FLAG as lowfreeflag,ac.LOWFREE_LIMIT as lowfreelimit,ac.DAY_LIMIT as daylimit, ac.ACCNAME as name,pa.points " +
                 "from tb_account ac left join tb_points_account pa on pa.userid=ac.userid where  ac.trans_status<>'closed' and ac.userid =:uid "
-        var query = entityManager.createNativeQuery(sql)
+        val query = entityManager.createNativeQuery(sql)
         query.setParameter("uid",userid)
         query.unwrap(NativeQuery::class.java).setResultTransformer(Transformers.aliasToBean(UserInfor::class.java))
+        @Suppress("UNCHECKED_CAST")
         val ret = query.resultList as List<UserInfor>
         if(ret.isNotEmpty()){
             return ret[0]
@@ -84,8 +85,8 @@
     }
 
     override fun updateFlag(userid: String,flag:Boolean,low:Double,day:Double):Int {
-        var sql = "update tb_account set lowfree_flag=:flag,lowfree_limit=:low, day_limit=:day where trans_status<>'closed' and userid=:uid  "
-        var query = entityManager.createNativeQuery(sql)
+        val sql = "update tb_account set lowfree_flag=:flag,lowfree_limit=:low, day_limit=:day where trans_status<>'closed' and userid=:uid  "
+        val query = entityManager.createNativeQuery(sql)
         query.setParameter("uid",userid)
         query.setParameter("flag",flag)
         query.setParameter("low",low)
diff --git a/oauth/src/main/kotlin/com/supwisdom/oauth/util/Test.kt b/oauth/src/main/kotlin/com/supwisdom/oauth/util/Test.kt
index b89841f..de856ed 100644
--- a/oauth/src/main/kotlin/com/supwisdom/oauth/util/Test.kt
+++ b/oauth/src/main/kotlin/com/supwisdom/oauth/util/Test.kt
@@ -9,12 +9,4 @@
         }
     }
 
-    private fun <T : Number> min(values: Array<T>?): T? where T : Comparable<T> {
-        if (values == null || values.size == 0) return null
-        var min = values[0]
-        for (i in 1 until values.size) {
-            if (min.compareTo(values[i]) > 0) min = values[i]
-        }
-        return min
-    }
 }
\ No newline at end of file
diff --git a/payapi-common/build.gradle b/payapi-common/build.gradle
index c257e6a..09ae6d4 100644
--- a/payapi-common/build.gradle
+++ b/payapi-common/build.gradle
@@ -1,11 +1,14 @@
 plugins {
-    id 'java-library'
-    id 'maven-publish'
-    id "com.palantir.git-version"
+    id "java-library"
+    id "maven-publish"
+    id "org.springframework.boot"
 }
 
-group = rootProject.group
-version = gitVersion()
+bootJar {
+    enabled = false
+}
+
+apply from: rootProject.file('gradle/swnx-publish.gradle')
 
 publishing {
     publications {
@@ -16,38 +19,15 @@
             from components.java
         }
     }
-    repositories {
-        maven {
-            // change URLs to point to your repos, e.g. http://my.org/repo
-            def releasesRepoUrl = "http://ykt-nx.supwisdom.com/repository/ecard-repo/"
-            def snapshotsRepoUrl = "http://ykt-nx.supwisdom.com/repository/ecard-repo/snapshot/"
-            url = version.endsWith('dirty') ? snapshotsRepoUrl : releasesRepoUrl
-            credentials(PasswordCredentials) {
-                username = nxUser
-                password = nxPassword
-            }
-        }
-    }
 }
 
 dependencies {
-    implementation 'org.slf4j:slf4j-parent:1.7.26'
-    implementation 'org.slf4j:slf4j-api:1.7.26'
-    implementation 'javax.validation:validation-api:2.0.1.Final'
-    implementation 'javax.servlet:javax.servlet-api:4.0.1'
-    implementation 'commons-beanutils:commons-beanutils:1.9.3'
-    implementation 'commons-codec:commons-codec:1.13'
-    implementation('org.springframework.boot:spring-boot-starter-validation:2.1.6.RELEASE')
+    implementation "commons-beanutils:commons-beanutils:${beanutilsVersion}"
+    implementation "commons-codec:commons-codec:${codecVersion}"
+    implementation "org.apache.commons:commons-lang3:${lang3Version}"
 
-    implementation 'com.fasterxml.jackson.core:jackson-annotations:2.10.1'
-    implementation 'org.hibernate:hibernate-validator:6.0.2.Final'
-    compile 'javax.el:javax.el-api:3.0.0'
-    compile 'org.glassfish.web:javax.el:2.2.6'
-
-    compileOnly 'org.projectlombok:lombok:1.18.8'
-    annotationProcessor 'org.projectlombok:lombok:1.18.8'
-
-    implementation 'org.apache.commons:commons-lang3:3.9'
+    compileOnly "org.projectlombok:lombok:${lombokVersion}"
+    annotationProcessor "org.projectlombok:lombok:${lombokVersion}"
 
     testImplementation 'junit:junit:4.12'
 }
diff --git a/payapi-common/src/main/java/com/supwisdom/dlpay/api/annotation/TransDate.java b/payapi-common/src/main/java/com/supwisdom/dlpay/api/annotation/TransDate.java
new file mode 100644
index 0000000..612d6f2
--- /dev/null
+++ b/payapi-common/src/main/java/com/supwisdom/dlpay/api/annotation/TransDate.java
@@ -0,0 +1,22 @@
+package com.supwisdom.dlpay.api.annotation;
+
+
+import com.supwisdom.dlpay.api.validator.TransDateValidator;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+import java.lang.annotation.*;
+
+@Constraint(validatedBy = {TransDateValidator.class})
+@Documented
+@Target({ElementType.METHOD, ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface TransDate {
+  String message() default "交易日期格式错误";
+
+  Class<?>[] groups() default {};
+
+  Class<? extends Payload>[] payload() default {};
+
+  String value() default "";
+}
diff --git a/payapi-common/src/main/java/com/supwisdom/dlpay/api/annotation/TransTime.java b/payapi-common/src/main/java/com/supwisdom/dlpay/api/annotation/TransTime.java
new file mode 100644
index 0000000..ddb74c2
--- /dev/null
+++ b/payapi-common/src/main/java/com/supwisdom/dlpay/api/annotation/TransTime.java
@@ -0,0 +1,22 @@
+package com.supwisdom.dlpay.api.annotation;
+
+
+import com.supwisdom.dlpay.api.validator.TransTimeValidator;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+import java.lang.annotation.*;
+
+@Constraint(validatedBy = {TransTimeValidator.class})
+@Documented
+@Target({ElementType.METHOD, ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface TransTime {
+  String message() default "交易时间格式错误";
+
+  Class<?>[] groups() default {};
+
+  Class<? extends Payload>[] payload() default {};
+
+  String value() default "";
+}
diff --git a/payapi-common/src/main/java/com/supwisdom/dlpay/api/bean/CardBizParam.java b/payapi-common/src/main/java/com/supwisdom/dlpay/api/bean/CardBizParam.java
new file mode 100644
index 0000000..3186283
--- /dev/null
+++ b/payapi-common/src/main/java/com/supwisdom/dlpay/api/bean/CardBizParam.java
@@ -0,0 +1,169 @@
+package com.supwisdom.dlpay.api.bean;
+
+import com.supwisdom.dlpay.api.APIRequestParam;
+import com.supwisdom.dlpay.api.annotation.TransDate;
+import com.supwisdom.dlpay.api.annotation.TransTime;
+import com.supwisdom.dlpay.api.bean.groups.ConfirmAction;
+import com.supwisdom.dlpay.api.bean.groups.InitAction;
+import com.supwisdom.dlpay.api.bean.groups.QueryAction;
+import com.supwisdom.dlpay.api.exception.RequestParamCheckException;
+
+import javax.validation.constraints.NotNull;
+
+public class CardBizParam extends APIRequestParam {
+  @NotNull(message = "操作员ID不能为空", groups = {InitAction.class, ConfirmAction.class, QueryAction.class})
+  private String operid;
+
+  private @NotNull(message = "操作员流水号不能为空", groups = {InitAction.class, ConfirmAction.class, QueryAction.class}) String operSeqno;
+
+  @TransDate(groups = {InitAction.class})
+  private String transdate;
+
+  @TransTime(groups = {InitAction.class})
+  private String transtime;
+
+  private String userid;
+
+  @NotNull(message = "资金方向不能为空", groups = {InitAction.class})
+  private String inOrOut;
+
+  @NotNull
+  private Integer totalAmount;
+
+  private String capitalSubjno;
+
+  @NotNull
+  private Integer cost;
+
+  @NotNull
+  private Integer cashPledge;
+
+  @NotNull
+  private Integer charge;
+
+  @NotNull(message = "交易摘要不能为空", groups = {InitAction.class})
+  private String summary;
+
+  @TransDate(message = "记账日期不能为空", groups = {ConfirmAction.class, QueryAction.class})
+  private String accdate;
+
+  @NotNull(message = "交易参考号不能为空", groups = {ConfirmAction.class, QueryAction.class})
+  private String refno;
+
+  public String getOperid() {
+    return operid;
+  }
+
+  public void setOperid(String operid) {
+    this.operid = operid;
+  }
+
+  public @NotNull(message = "操作员流水号不能为空", groups = {InitAction.class, ConfirmAction.class, QueryAction.class}) String getOperSeqno() {
+    return operSeqno;
+  }
+
+  public void setOperSeqno(@NotNull(message = "操作员流水号不能为空", groups = {InitAction.class, ConfirmAction.class, QueryAction.class}) String operSeqno) {
+    this.operSeqno = operSeqno;
+  }
+
+  public String getUserid() {
+    return userid;
+  }
+
+  public void setUserid(String userid) {
+    this.userid = userid;
+  }
+
+  public Integer getTotalAmount() {
+    return totalAmount;
+  }
+
+  public void setTotalAmount(Integer totalAmount) {
+    this.totalAmount = totalAmount;
+  }
+
+  public String getAccdate() {
+    return accdate;
+  }
+
+  public void setAccdate(String accdate) {
+    this.accdate = accdate;
+  }
+
+  public String getRefno() {
+    return refno;
+  }
+
+  public void setRefno(String refno) {
+    this.refno = refno;
+  }
+
+  public String getTransdate() {
+    return transdate;
+  }
+
+  public void setTransdate(String transdate) {
+    this.transdate = transdate;
+  }
+
+  public String getTranstime() {
+    return transtime;
+  }
+
+  public void setTranstime(String transtime) {
+    this.transtime = transtime;
+  }
+
+  public String getCapitalSubjno() {
+    return capitalSubjno;
+  }
+
+  public void setCapitalSubjno(String capitalSubjno) {
+    this.capitalSubjno = capitalSubjno;
+  }
+
+  public String getSummary() {
+    return summary;
+  }
+
+  public void setSummary(String summary) {
+    this.summary = summary;
+  }
+
+  public Integer getCost() {
+    return cost;
+  }
+
+  public void setCost(Integer cost) {
+    this.cost = cost;
+  }
+
+  public Integer getCashPledge() {
+    return cashPledge;
+  }
+
+  public void setCashPledge(Integer cashPledge) {
+    this.cashPledge = cashPledge;
+  }
+
+  public Integer getCharge() {
+    return charge;
+  }
+
+  public void setCharge(Integer charge) {
+    this.charge = charge;
+  }
+
+  public String getInOrOut() {
+    return inOrOut;
+  }
+
+  public void setInOrOut(String inOrOut) {
+    this.inOrOut = inOrOut;
+  }
+
+  @Override
+  public boolean checkParam() throws RequestParamCheckException {
+    return true;
+  }
+}
diff --git a/payapi-common/src/main/java/com/supwisdom/dlpay/api/bean/CardBizRefundParam.java b/payapi-common/src/main/java/com/supwisdom/dlpay/api/bean/CardBizRefundParam.java
new file mode 100644
index 0000000..70f4656
--- /dev/null
+++ b/payapi-common/src/main/java/com/supwisdom/dlpay/api/bean/CardBizRefundParam.java
@@ -0,0 +1,83 @@
+package com.supwisdom.dlpay.api.bean;
+
+import com.supwisdom.dlpay.api.APIRequestParam;
+import com.supwisdom.dlpay.api.annotation.TransDate;
+import com.supwisdom.dlpay.api.annotation.TransTime;
+import com.supwisdom.dlpay.api.bean.groups.ConfirmAction;
+import com.supwisdom.dlpay.api.bean.groups.InitAction;
+import com.supwisdom.dlpay.api.exception.RequestParamCheckException;
+
+import javax.validation.constraints.NotNull;
+
+public class CardBizRefundParam extends APIRequestParam {
+  @NotNull(message = "操作员号不能空", groups = {InitAction.class})
+  private String operid;
+
+  @NotNull(message = "操作员流水号不能为空", groups = {InitAction.class})
+  private String operSeqno;
+
+  @NotNull(message = "原始流水参考号不能为空", groups = {InitAction.class, ConfirmAction.class})
+  private String originRefno;
+
+  @NotNull(message = "退款总金额不能为空", groups = {InitAction.class})
+  private Integer totalAmount;
+
+  @TransDate(groups = {InitAction.class})
+  private String transdate;
+
+  @TransTime(groups = {InitAction.class})
+  private String transtime;
+
+  public String getOperid() {
+    return operid;
+  }
+
+  public void setOperid(String operid) {
+    this.operid = operid;
+  }
+
+  public String getOperSeqno() {
+    return operSeqno;
+  }
+
+  public void setOperSeqno(String operSeqno) {
+    this.operSeqno = operSeqno;
+  }
+
+  public String getOriginRefno() {
+    return originRefno;
+  }
+
+  public void setOriginRefno(String originRefno) {
+    this.originRefno = originRefno;
+  }
+
+  public Integer getTotalAmount() {
+    return totalAmount;
+  }
+
+  public void setTotalAmount(Integer totalAmount) {
+    this.totalAmount = totalAmount;
+  }
+
+  public String getTransdate() {
+    return transdate;
+  }
+
+  public void setTransdate(String transdate) {
+    this.transdate = transdate;
+  }
+
+  public String getTranstime() {
+    return transtime;
+  }
+
+  public void setTranstime(String transtime) {
+    this.transtime = transtime;
+  }
+
+  @Override
+  public boolean checkParam() throws RequestParamCheckException {
+    return true;
+  }
+}
diff --git a/payapi-common/src/main/java/com/supwisdom/dlpay/api/bean/CardBizResponse.java b/payapi-common/src/main/java/com/supwisdom/dlpay/api/bean/CardBizResponse.java
new file mode 100644
index 0000000..704c809
--- /dev/null
+++ b/payapi-common/src/main/java/com/supwisdom/dlpay/api/bean/CardBizResponse.java
@@ -0,0 +1,59 @@
+package com.supwisdom.dlpay.api.bean;
+
+import lombok.AllArgsConstructor;
+import lombok.NoArgsConstructor;
+
+@AllArgsConstructor
+@NoArgsConstructor
+public class CardBizResponse extends ApiResponse {
+  private String refno;
+
+  private String accdate;
+
+  private String description;
+
+  private Integer accountBal;
+
+  private String transStatus;
+
+  public String getRefno() {
+    return refno;
+  }
+
+  public void setRefno(String refno) {
+    this.refno = refno;
+  }
+
+  public String getAccdate() {
+    return accdate;
+  }
+
+  public void setAccdate(String accdate) {
+    this.accdate = accdate;
+  }
+
+  public String getDescription() {
+    return description;
+  }
+
+  public void setDescription(String description) {
+    this.description = description;
+  }
+
+
+  public Integer getAccountBal() {
+    return accountBal;
+  }
+
+  public void setAccountBal(Integer accountBal) {
+    this.accountBal = accountBal;
+  }
+
+  public String getTransStatus() {
+    return transStatus;
+  }
+
+  public void setTransStatus(String transStatus) {
+    this.transStatus = transStatus;
+  }
+}
diff --git a/payapi-common/src/main/java/com/supwisdom/dlpay/api/bean/CitizenCardInfo.java b/payapi-common/src/main/java/com/supwisdom/dlpay/api/bean/CitizenCardInfo.java
index d32a42f..dadc1ff 100644
--- a/payapi-common/src/main/java/com/supwisdom/dlpay/api/bean/CitizenCardInfo.java
+++ b/payapi-common/src/main/java/com/supwisdom/dlpay/api/bean/CitizenCardInfo.java
@@ -5,7 +5,6 @@
 import lombok.Getter;
 import lombok.NoArgsConstructor;
 import lombok.Setter;
-import org.springframework.boot.jackson.JsonComponent;
 
 @Getter
 @Setter
diff --git a/payapi-common/src/main/java/com/supwisdom/dlpay/api/validator/TransDateValidator.java b/payapi-common/src/main/java/com/supwisdom/dlpay/api/validator/TransDateValidator.java
new file mode 100644
index 0000000..cb5b243
--- /dev/null
+++ b/payapi-common/src/main/java/com/supwisdom/dlpay/api/validator/TransDateValidator.java
@@ -0,0 +1,30 @@
+package com.supwisdom.dlpay.api.validator;
+
+import com.supwisdom.dlpay.api.annotation.TransDate;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+
+public class TransDateValidator implements ConstraintValidator<TransDate, String> {
+
+  @Override
+  public boolean isValid(String value, ConstraintValidatorContext context) {
+    if (value == null || value.isEmpty()) {
+      return false;
+    }
+    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
+    try {
+      sdf.parse(value);
+      return true;
+    } catch (ParseException e) {
+      e.printStackTrace();
+    }
+    return false;
+  }
+
+  @Override
+  public void initialize(TransDate constraintAnnotation) {
+  }
+}
diff --git a/payapi-common/src/main/java/com/supwisdom/dlpay/api/validator/TransTimeValidator.java b/payapi-common/src/main/java/com/supwisdom/dlpay/api/validator/TransTimeValidator.java
new file mode 100644
index 0000000..96ac618
--- /dev/null
+++ b/payapi-common/src/main/java/com/supwisdom/dlpay/api/validator/TransTimeValidator.java
@@ -0,0 +1,31 @@
+package com.supwisdom.dlpay.api.validator;
+
+import com.supwisdom.dlpay.api.annotation.TransTime;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+
+public class TransTimeValidator implements ConstraintValidator<TransTime, String> {
+
+  @Override
+  public boolean isValid(String value, ConstraintValidatorContext context) {
+    if (value == null || value.isEmpty()) {
+      return false;
+    }
+    SimpleDateFormat sdf = new SimpleDateFormat("HHmmss");
+
+    try {
+      sdf.parse(value);
+      return true;
+    } catch (ParseException e) {
+      e.printStackTrace();
+    }
+    return false;
+  }
+
+  @Override
+  public void initialize(TransTime constraintAnnotation) {
+  }
+}
diff --git a/payapi-common/src/test/java/com/supwisdom/dlpay/api/bean/CitizenCardPayinitParamTest.java b/payapi-common/src/test/java/com/supwisdom/dlpay/api/bean/CitizenCardPayinitParamTest.java
index 0b3dd8b..0a20a77 100644
--- a/payapi-common/src/test/java/com/supwisdom/dlpay/api/bean/CitizenCardPayinitParamTest.java
+++ b/payapi-common/src/test/java/com/supwisdom/dlpay/api/bean/CitizenCardPayinitParamTest.java
@@ -1,25 +1,116 @@
 package com.supwisdom.dlpay.api.bean;
 
+import com.supwisdom.dlpay.api.annotation.*;
 import com.supwisdom.dlpay.api.types.IDTypes;
 import com.supwisdom.dlpay.api.types.SexTypes;
-import org.junit.Test;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
 
 import javax.validation.ConstraintViolation;
 import javax.validation.Validation;
 import javax.validation.Validator;
 import javax.validation.ValidatorFactory;
-import java.util.*;
+import java.util.List;
+import java.util.Set;
 import java.util.stream.Collectors;
 import java.util.stream.StreamSupport;
 
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 public class CitizenCardPayinitParamTest {
 
   private Validator validator;
 
-  @org.junit.Before
+  @IDNoCheck(idno = "idno", idtype = "idtype", value = IDTypes.IDTYPE_LIST)
+  public static class TestBean {
+    @TransDate(message = "不是合法的交易日期")
+    private String transDate;
+    @TransTime(message = "不是合法的交易时间")
+    private String transTime;
+
+    @Sex
+    private String sex;
+
+    @MobileNumber
+    private String mobile;
+
+    private String valueList;
+
+    @UserStatus
+    private String status;
+
+    private String idtype;
+
+    private String idno;
+
+    public String getTransDate() {
+      return transDate;
+    }
+
+    public void setTransDate(String transDate) {
+      this.transDate = transDate;
+    }
+
+    public String getTransTime() {
+      return transTime;
+    }
+
+    public void setTransTime(String transTime) {
+      this.transTime = transTime;
+    }
+
+    public String getSex() {
+      return sex;
+    }
+
+    public void setSex(String sex) {
+      this.sex = sex;
+    }
+
+    public String getMobile() {
+      return mobile;
+    }
+
+    public void setMobile(String mobile) {
+      this.mobile = mobile;
+    }
+
+    public String getValueList() {
+      return valueList;
+    }
+
+    public void setValueList(String valueList) {
+      this.valueList = valueList;
+    }
+
+    public String getStatus() {
+      return status;
+    }
+
+    public void setStatus(String status) {
+      this.status = status;
+    }
+
+    public String getIdtype() {
+      return idtype;
+    }
+
+    public void setIdtype(String idtype) {
+      this.idtype = idtype;
+    }
+
+    public String getIdno() {
+      return idno;
+    }
+
+    public void setIdno(String idno) {
+      this.idno = idno;
+    }
+  }
+
+  @BeforeEach
   public void setUp() throws Exception {
     ValidatorFactory factor = Validation.buildDefaultValidatorFactory();
     validator = factor.getValidator();
@@ -31,7 +122,7 @@
 
     List<ConstraintViolation<CitizenCardPayinitParam>> violations = validate(param);
     String message = getViolationMessage(violations);
-    assertFalse(message, violations.isEmpty());
+    assertFalse(violations.isEmpty(), message);
   }
 
   private <T> List<ConstraintViolation<T>> validate(T param) {
@@ -53,17 +144,31 @@
   public void testOpenUserParam() {
     OpenUserParam param = new OpenUserParam();
     List<ConstraintViolation<OpenUserParam>> result = validate(param);
-    assertFalse(getViolationMessage(result), result.isEmpty());
+    assertFalse(result.isEmpty(), getViolationMessage(result));
 
     param.setIdtype(IDTypes.IDCARD.value());
-    param.setIdno("123213");
+    param.setIdno("123456789012345678");
     param.setUid("1231323");
     param.setName("lily");
     param.setSex(SexTypes.MALE.value());
     param.setMobile("+8618272733888");
 
     result = validate(param);
-    assertTrue(getViolationMessage(result), result.isEmpty());
+    assertTrue(result.isEmpty(), getViolationMessage(result));
+  }
 
+  @Test
+  void testCustomizeValidator() {
+    TestBean bean = new TestBean();
+    bean.setIdtype(IDTypes.IDCARD.value());
+    bean.setIdno("123456789012345678");
+    bean.setTransDate("20191001");
+    bean.setTransTime("135943");
+    bean.setMobile("+8618621110059");
+    bean.setSex("male");
+    bean.setStatus("open");
+
+    List<ConstraintViolation<TestBean>> result = validate(bean);
+    assertThat(getViolationMessage(result), result.isEmpty());
   }
 }
\ No newline at end of file
diff --git a/payapi-sdk/build.gradle b/payapi-sdk/build.gradle
index 6d97ea4..c54d0f0 100644
--- a/payapi-sdk/build.gradle
+++ b/payapi-sdk/build.gradle
@@ -5,13 +5,13 @@
     id "com.palantir.git-version" 
 }
 
-
 apply plugin: 'io.spring.dependency-management'
 
-group = rootProject.group
-
 def sdkVersion = gitVersion()
 
+
+apply from: rootProject.file('gradle/swnx-publish.gradle')
+
 publishing {
     publications {
         mavenJava(MavenPublication) {
@@ -21,18 +21,6 @@
             from components.java
         }
     }
-    repositories {
-        maven {
-            // change URLs to point to your repos, e.g. http://my.org/repo
-            def releasesRepoUrl = "http://ykt-nx.supwisdom.com/repository/ecard-repo/"
-            def snapshotsRepoUrl = "http://ykt-nx.supwisdom.com/repository/ecard-repo/snapshot/"
-            url = version.endsWith('dirty') ? snapshotsRepoUrl : releasesRepoUrl
-            credentials(PasswordCredentials) {
-                username = nxUser
-                password = nxPassword
-            }
-        }
-    }
 }
 
 bootJar {
@@ -40,26 +28,10 @@
 }
 
 dependencies {
-    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
-    implementation 'org.springframework.boot:spring-boot-starter-data-redis'
+    implementation project(":payapi-common")
 
-    implementation project(':payapi-common')
-
-    implementation 'org.springframework.cloud:spring-cloud-dependencies:Finchley.SR3'
-    implementation 'org.springframework.cloud:spring-cloud-starter-openfeign:2.1.2.RELEASE'
-
-    implementation 'javax.servlet:javax.servlet-api:4.0.1'
-    compileOnly 'org.projectlombok:lombok:1.18.8'
-    annotationProcessor 'org.projectlombok:lombok:1.18.8'
-    compile 'com.github.mwiede:feign-validation:1.0'
-
-    testImplementation 'org.springframework:spring-test'
-    testImplementation 'org.springframework.boot:spring-boot-test'
-    testImplementation 'junit:junit:4.12'
-    testAnnotationProcessor 'org.projectlombok:lombok:1.18.8'
-    testCompileOnly 'org.projectlombok:lombok:1.18.8'
-    testImplementation 'org.hamcrest:hamcrest:2.1'
-    testImplementation project(':payapi-common')
+    implementation "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
+    implementation "org.springframework.cloud:spring-cloud-starter-openfeign"
 
 }
 
diff --git a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/UserProxy.java b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/UserProxy.java
index 1fb815f..13c5018 100644
--- a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/UserProxy.java
+++ b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/UserProxy.java
@@ -2,9 +2,7 @@
 
 import com.supwisdom.dlpay.api.bean.*;
 import org.springframework.cloud.openfeign.FeignClient;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.*;
 
 import java.util.Map;
 
@@ -28,6 +26,21 @@
   @PostMapping("/api/user/testmsg")
   ApiResponse testmsg();
 
+  @PostMapping("/api/user/biz_init")
+  CardBizResponse bizInit(@RequestBody CardBizParam param);
+
+  @PostMapping("/api/user/biz_confirm")
+  CardBizResponse bizConfirm(@RequestBody CardBizParam param);
+
+  @PostMapping("/api/user/biz_refund_init")
+  CardBizResponse bizRefundInit(@RequestBody CardBizRefundParam param);
+
+  @PostMapping("/api/user/biz_refund")
+  CardBizResponse bizRefund(String refno);
+
+  @RequestMapping(value = "/api/user/biz_query", method = RequestMethod.GET)
+  CardBizResponse bizQuery(@RequestParam("refno") String refno);
+
   @PostMapping("/api/user/userTask")
   ApiResponse userTask(@RequestBody UserTaskParam param);
 
diff --git a/payapi-sdk/src/test/java/com/supwisdom/dlpay/paysdktest/CitizenCardPayProxyTest.java b/payapi-sdk/src/test/java/com/supwisdom/dlpay/paysdktest/CitizenCardPayProxyTest.java
index 805d85e..16f82bb 100644
--- a/payapi-sdk/src/test/java/com/supwisdom/dlpay/paysdktest/CitizenCardPayProxyTest.java
+++ b/payapi-sdk/src/test/java/com/supwisdom/dlpay/paysdktest/CitizenCardPayProxyTest.java
@@ -5,7 +5,6 @@
 import com.supwisdom.dlpay.api.util.DateUtil;
 import com.supwisdom.dlpay.paysdk.ApiLoginHelper;
 import com.supwisdom.dlpay.paysdk.proxy.*;
-import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -17,10 +16,8 @@
 import org.springframework.cloud.openfeign.FeignAutoConfiguration;
 import org.springframework.cloud.openfeign.ribbon.FeignRibbonClientAutoConfiguration;
 import org.springframework.context.annotation.ComponentScan;
-import org.springframework.http.ResponseEntity;
 import org.springframework.test.context.junit4.SpringRunner;
 
-import java.util.LinkedHashMap;
 import java.util.List;
 
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -39,7 +36,9 @@
 @ComponentScan(basePackages = {"com.supwisdom.dlpay.paysdk"})
 public class CitizenCardPayProxyTest {
   private final static String appid = "700001";
-  private final static String secret = "5f788ce433ec44f299351cdf7f137e81";
+  private final static String secret = "d6dd7f0d4551419d8d11736d0f28df0d";
+
+  private final static String operid = "1001";
 
   @Autowired
   private ApiLoginProxy apiLoginProxy;
@@ -267,6 +266,66 @@
   }
 
   @Test
+  public void testPublishCard() {
+    ApiLoginHelper helper = new ApiLoginHelper(apiLoginProxy);
+    helper.login(appid, secret);
+
+    CardBizParam param = new CardBizParam();
+    param.setTransdate(DateUtil.getNow("yyyyMMdd"));
+    param.setTranstime(DateUtil.getNow("HHmmss"));
+    param.setOperid(operid);
+    param.setOperSeqno(param.getTransdate() + param.getTranstime());
+    param.setTotalAmount(10000);
+    param.setCapitalSubjno("112201");
+    param.setSummary("发卡");
+    param.setCost(1000);
+    param.setInOrOut("in");
+    param.setCharge(0);
+    param.setCashPledge(0);
+    param.setUserid("ff8080816dd8f3a6016dd8f5e5d80002");
+
+    CardBizResponse response = userProxy.bizInit(param);
+
+    assertThat("user card biz init " + response.getRetcode() + response.getRetmsg() + response.getException(),
+        response.getRetcode(), equalTo(0));
+
+    System.out.println("biz init accdate " + response.getAccdate() + " , refno " + response.getRefno()
+        + ", description " + response.getDescription() + "  summary " + response.getRetmsg());
+
+    param.setAccdate(response.getAccdate());
+    param.setRefno(response.getRefno());
+    response = userProxy.bizConfirm(param);
+
+    assertThat("user card biz confirm " + response.getRetcode() + response.getRetmsg() + response.getException(),
+        response.getRetcode(), equalTo(0));
+
+    System.out.println("biz confirm accdate " + response.getAccdate() + " , refno " + response.getRefno()
+        + ", account " + response.getAccountBal() / 100.0
+        + ", description " + response.getDescription() + "  summary " + response.getRetmsg());
+
+
+    CardBizRefundParam refundParam = new CardBizRefundParam();
+    refundParam.setOperid(operid);
+    refundParam.setTransdate(DateUtil.getNow("yyyyMMdd"));
+    refundParam.setTranstime(DateUtil.getNow("HHmmss"));
+    refundParam.setOperSeqno(refundParam.getTransdate() + refundParam.getTranstime() + "9");
+    refundParam.setTotalAmount(10000);
+    refundParam.setOriginRefno(response.getRefno());
+    response = userProxy.bizRefundInit(refundParam);
+    assertThat("user card biz refund init " + response.getRetcode() + response.getRetmsg() + response.getException(),
+        response.getRetcode(), equalTo(0));
+
+    System.out.println("biz refund init accdate " + response.getAccdate() + " , refno " + response.getRefno()
+        + ", description " + response.getDescription() + "  summary " + response.getRetmsg());
+
+    response = userProxy.bizRefund(response.getRefno());
+
+    System.out.println("biz refund accdate " + response.getAccdate() + " , refno " + response.getRefno()
+        + ", account " + response.getAccountBal() / 100.0
+        + ", description " + response.getDescription() + "  summary " + response.getRetmsg());
+  }
+
+  @Test
   public void thirdpay() {
 
   }
diff --git a/payapi/build.gradle b/payapi/build.gradle
index 7a4c6cf..c6061a2 100644
--- a/payapi/build.gradle
+++ b/payapi/build.gradle
@@ -1,56 +1,56 @@
 import java.text.SimpleDateFormat
 
 plugins {
-    id 'java'
-    id 'org.springframework.boot'
-    id 'io.spring.dependency-management'
-    id 'org.jetbrains.kotlin.jvm'
-    id 'org.jetbrains.kotlin.plugin.jpa' version '1.3.31'
-    id 'org.jetbrains.kotlin.plugin.spring'
-    id "com.palantir.git-version"
-    id 'com.palantir.docker'
+    id "java"
+    id "org.springframework.boot"
+    id "org.jetbrains.kotlin.jvm"
+    id "org.jetbrains.kotlin.plugin.jpa"
+    id "org.jetbrains.kotlin.plugin.spring"
+    id "com.palantir.docker"
 }
 
-tasks.withType(JavaCompile) {
-    options.encoding = "UTF-8"
-}
-
-
 payapiVersion = gitVersion()
 def details = versionDetails()
 
-group = rootProject.group
-version = '1'
-sourceCompatibility = jdkVersion
-def payapiStartClass = 'com.supwisdom.dlpay.PayApiApplicationKt'
+def payapiStartClass = "com.supwisdom.dlpay.PayApiApplicationKt"
 
 println("Build version: $payapiVersion")
 
 bootJar {
     mainClassName = payapiStartClass
     manifest {
-        attributes('Payapi-Version': payapiVersion,
-                'Payapi-Buildtime': new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").format(new Date()))
+        attributes("Payapi-Version": payapiVersion,
+                "Payapi-Buildtime": new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").format(new Date()))
     }
 }
 
 jar {
-    baseName = 'payapi'
+    baseName = "payapi"
 }
 
-ext {
-    set('springCloudVersion', "Greenwich.SR2")
+compileKotlin {
+    kotlinOptions {
+        freeCompilerArgs = ["-Xjsr305=strict"]
+        jvmTarget = jdkVersion
+    }
+}
+
+compileTestKotlin {
+    kotlinOptions {
+        freeCompilerArgs = ["-Xjsr305=strict"]
+        jvmTarget = jdkVersion
+    }
 }
 
 docker {
     def imageVersion
     if (details.gitHashFull.startsWith(details.lastTag) || !details.isCleanTag) {
-        imageVersion = 'dev'
+        imageVersion = "dev"
     } else {
         imageVersion = details.lastTag
     }
     println("Docker image tag : " + imageVersion)
-    name 'harbor.supwisdom.com/dali/payapi:' + imageVersion
+    name "harbor.supwisdom.com/dali/payapi:" + imageVersion
     println(jar.archivePath)
     files jar.archivePath
 }
@@ -112,7 +112,7 @@
     implementation group: 'taglibs', name: 'standard', version: '1.1.2'
     implementation group: 'commons-codec', name: 'commons-codec', version: '1.13'
     implementation files('libs/masmgc.sdk.sms-0.0.1-SNAPSHOT.jar')
-//    implementation files('libs/ojdbc6.jar')
+    //    implementation files('libs/ojdbc6.jar')
     implementation 'commons-dbcp:commons-dbcp:1.4'
     implementation 'commons-beanutils:commons-beanutils:1.9.3'
     implementation files('libs/ynrcc-openapi-sdk-1.1.2-RELEASE.jar')
@@ -136,29 +136,18 @@
     annotationProcessor 'org.projectlombok:lombok:1.18.8'
     compileOnly 'org.projectlombok:lombok:1.18.8'
 
-//    providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
+    implementation "org.apache.commons:commons-lang3:${lang3Version}"
+    implementation "net.javacrumbs.shedlock:shedlock-spring:${shedlockVersion}"
+    implementation "net.javacrumbs.shedlock:shedlock-provider-redis-spring:${shedlockVersion}"
+
+    //    providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
     testImplementation 'org.springframework.boot:spring-boot-starter-test'
     testImplementation 'io.rest-assured:rest-assured:3.3.0'
     testImplementation 'io.rest-assured:spring-mock-mvc:3.3.0'
     testImplementation 'org.hamcrest:hamcrest:2.1'
 }
 
-dependencyManagement {
-    imports {
-        mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
-    }
+tasks.withType(JavaCompile) {
+    options.encoding = "UTF-8"
 }
 
-compileKotlin {
-    kotlinOptions {
-        freeCompilerArgs = ['-Xjsr305=strict']
-        jvmTarget = jdkVersion
-    }
-}
-
-compileTestKotlin {
-    kotlinOptions {
-        freeCompilerArgs = ['-Xjsr305=strict']
-        jvmTarget = jdkVersion
-    }
-}
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/api/domain/TAccount.java b/payapi/src/main/java/com/supwisdom/dlpay/api/domain/TAccount.java
index 56e0cae..7b04f82 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/api/domain/TAccount.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/api/domain/TAccount.java
@@ -18,7 +18,7 @@
 public class TAccount implements Serializable {
   @Id
   @GenericGenerator(name = "idGenerator", strategy = "uuid")
-  @GeneratedValue(generator = "idGenerator")
+  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "idGenerator")
   @Column(name = "ACCNO", nullable = false, length = 32)
   private String accno; //账号
 
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/api/domain/TPersondtl.java b/payapi/src/main/java/com/supwisdom/dlpay/api/domain/TPersondtl.java
index c961f32..c103085 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/api/domain/TPersondtl.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/api/domain/TPersondtl.java
@@ -46,6 +46,9 @@
   @Column(name = "BEFBAL", precision = 9, scale = 2)
   private Double befbal;
 
+  @Column(name = "AFTBAL", precision = 9, scale = 2)
+  private Double aftbal;
+
   @Column(name = "amount", precision = 9, scale = 2)
   @NotNull
   private Double amount; //实际付款金额
@@ -298,4 +301,12 @@
   public void setAnonymous(Boolean anonymous) {
     this.anonymous = anonymous;
   }
+
+  public Double getAftbal() {
+    return aftbal;
+  }
+
+  public void setAftbal(Double aftbal) {
+    this.aftbal = aftbal;
+  }
 }
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/api/domain/TTransactionMain.java b/payapi/src/main/java/com/supwisdom/dlpay/api/domain/TTransactionMain.java
index 5987d59..f81af48 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/api/domain/TTransactionMain.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/api/domain/TTransactionMain.java
@@ -17,7 +17,7 @@
     indexes = {@Index(name = "transmain_accdate", columnList = "accdate"),
         @Index(name = "transmain_status", columnList = "status"),
         @Index(name = "transmain_tenantid_idx", columnList = "tenantid"),
-        @Index(name = "transmain_outtrade", unique = true, columnList = "outid, outtradeno")})
+        @Index(name = "transmain_outtrade", unique = true, columnList = "outid, outtradeno, tenantid")})
 @SequenceGenerator(name = "seq_refno", allocationSize = 100)
 public class TTransactionMain {
   @Id
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/framework/tenant/MultiTenantConnectionProviderImpl.java b/payapi/src/main/java/com/supwisdom/dlpay/framework/tenant/MultiTenantConnectionProviderImpl.java
index a8f8dd5..0666b65 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/framework/tenant/MultiTenantConnectionProviderImpl.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/framework/tenant/MultiTenantConnectionProviderImpl.java
@@ -1,8 +1,8 @@
 package com.supwisdom.dlpay.framework.tenant;
 
 import com.supwisdom.dlpay.framework.util.StringUtil;
+import lombok.extern.slf4j.Slf4j;
 import org.hibernate.HibernateException;
-import org.hibernate.engine.jdbc.connections.spi.AbstractDataSourceBasedMultiTenantConnectionProviderImpl;
 import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
@@ -14,6 +14,7 @@
 /**
  * Created by shuwei on 2018/12/4.
  */
+@Slf4j
 @Component
 public class MultiTenantConnectionProviderImpl implements MultiTenantConnectionProvider {
   @Autowired
@@ -35,8 +36,10 @@
     final Connection connection = getAnyConnection();
     try {
       if (!StringUtil.isEmpty(tenantIdentifier)) {
+        log.debug("postgresql set search path to  <" + tenantIdentifier + ">");
         connection.createStatement().execute("SET search_path = \"" + tenantIdentifier + "\", public");
       } else {
+        log.debug("postgresql set search path to public");
         connection.createStatement().execute("SET search_path =  public");
       }
     } catch (SQLException e) {
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/framework/util/Subject.java b/payapi/src/main/java/com/supwisdom/dlpay/framework/util/Subject.java
index 21602c4..179f6cf 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/framework/util/Subject.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/framework/util/Subject.java
@@ -109,7 +109,6 @@
   public static final String SUBJNO_PERSONAL_REFUND = "220211";
 
 
-
   //======================= 损益类 =====================//
   /**
    * 手续费收入 - 支付宝充值手续费
@@ -126,6 +125,10 @@
    */
   public static final String SUBJNO_SERVICEFEE_UNIONPAY = "602103";
 
+  /**
+   * 手续费收入 - 默认
+   */
+  public static final String SUBJNO_SERVICEFEE_DEFAULT = "602104";
 
   /**
    * 销售费用 - (消费)折扣优惠款
@@ -142,4 +145,9 @@
    */
   public static final String SUBJNO_MANAGEFEE = "6602";
 
+  /**
+   * 卡成本费
+   */
+  public static final String SUBJNO_CARD_COST = "6025";
+
 }
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/framework/util/TradeCode.java b/payapi/src/main/java/com/supwisdom/dlpay/framework/util/TradeCode.java
index 29f3921..587c400 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/framework/util/TradeCode.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/framework/util/TradeCode.java
@@ -32,5 +32,6 @@
 
   public static final int TRANSCODE_ERCHARGE = 3500; //账户充值
 
+  public static final int TRANSCODE_CARD_BIZ = 1007; // 卡务业务
 
 }
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/system/service/impl/PointsServiceImpl.java b/payapi/src/main/java/com/supwisdom/dlpay/system/service/impl/PointsServiceImpl.java
index a1f9c80..15c08ce 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/system/service/impl/PointsServiceImpl.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/system/service/impl/PointsServiceImpl.java
@@ -77,7 +77,7 @@
   @Override
   public LevelBean getLevel() {
     LevelBean levelBean = new LevelBean();
-    Sort sort = new Sort(Sort.Direction.ASC, "id");
+    Sort sort = Sort.by("id");
     List<TPersonLevel> list = personLevelDao.findAll(sort);
     if (!StringUtil.isEmpty(list)) levelBean.settPersonLevels(list);
     return levelBean;
@@ -197,7 +197,7 @@
 
   @Override
   public LevelBean getConpoints() {
-    Sort sort = new Sort(Sort.Direction.ASC, "id");
+    Sort sort = Sort.by("id");
     List<TConsumePoints> monthlist = consumePointsDao.findAllByAndRuletype(TradeDict.CONSUME_POINTS_MONTH, sort);
     List<TConsumePoints> daylist = consumePointsDao.findAllByAndRuletype(TradeDict.CONSUME_POINTS_DAY, sort);
     LevelBean levelBean = new LevelBean();
@@ -364,7 +364,7 @@
     List<TPersondtl> tPersondtl = getShopdtlByUseridAndTransdateAndReverseFlagAndStatus(userid, DateUtil.getNow("yyyyMMdd"), "none", "success");
     Double allConsume = -tPersondtl.stream().mapToDouble(o -> o.getAmount()).sum();
     // 2.循环日消费奖励规则
-    Sort sort = new Sort(Sort.Direction.ASC, "id");
+    Sort sort = Sort.by("id");
     List<TConsumePoints> daylist = consumePointsDao.findAllByAndRuletype(TradeDict.CONSUME_POINTS_DAY, sort);
     for (TConsumePoints temp : daylist) {
       // 3.判断用户是否达到日消费奖励积分的额度,达到再次判断是否获得过该规则的奖励
@@ -409,7 +409,7 @@
     List<TPersondtl> tPersondtl = getShopdtlByUseridAndTransdateStartingWithAndReverseFlagAndStatus(userid, DateUtil.getNow("yyyyMM"), "none", "success");
     Double allConsume = -tPersondtl.stream().mapToDouble(o -> o.getAmount()).sum();
     // 2.循环月消费奖励规则
-    Sort sort = new Sort(Sort.Direction.ASC, "id");
+    Sort sort = Sort.by("id");
     List<TConsumePoints> monthlist = consumePointsDao.findAllByAndRuletype(TradeDict.CONSUME_POINTS_MONTH, sort);
     for (TConsumePoints temp : monthlist) {
       // 3.判断用户是否达到月消费奖励积分的额度,达到再次判断是否获得过该规则的奖励
@@ -472,7 +472,7 @@
     List<TPersondtl> tPersondtl = getShopdtlByUseridAndTransdateAndReverseFlagAndStatus(userid, tPointsdtl.getTransdate(), "none", "success");
     Double allConsume = -tPersondtl.stream().mapToDouble(o -> o.getAmount()).sum();
     // 2.2.循环日消费奖励规则
-    Sort sort = new Sort(Sort.Direction.ASC, "id");
+    Sort sort = Sort.by("id");
     List<TConsumePoints> daylist = consumePointsDao.findAllByAndRuletype(TradeDict.CONSUME_POINTS_DAY, sort);
     for (TConsumePoints temp : daylist) {
       // 2.3.判断用户是否达到日消费奖励积分的额度,没有达到再次判断是否获得过该规则的奖励
@@ -587,7 +587,7 @@
   }
 
   public TPersonLevel getLevelByPoints(Integer points) {
-    Sort sort = new Sort(Sort.Direction.DESC, "id");
+    Sort sort = Sort.by(Sort.Order.desc("id"));
     List<TPersonLevel> all = personLevelDao.findAll(sort);
     for (TPersonLevel temp : all) {
       if (points >= temp.getPointsLower()) {
@@ -763,7 +763,7 @@
       personLevelResult.setPointsName("消费积分");
       levelBeans.add(personLevelResult);
       //统计日累计消费积分
-      Sort sort = new Sort(Sort.Direction.ASC, "id");
+      Sort sort = Sort.by("id");
       List<TConsumePoints> daylist = consumePointsDao.findAllByAndRuletype(TradeDict.CONSUME_POINTS_DAY, sort);
       List<Integer> dayTemp = daylist.stream().map(TConsumePoints::getId).collect(Collectors.toList());
       LevelBean dayTempBean = new LevelBean();
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/system/service/impl/SettleReportServiceImpl.java b/payapi/src/main/java/com/supwisdom/dlpay/system/service/impl/SettleReportServiceImpl.java
index 4d3a830..b52ea1e 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/system/service/impl/SettleReportServiceImpl.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/system/service/impl/SettleReportServiceImpl.java
@@ -9,6 +9,7 @@
 import com.supwisdom.dlpay.system.bean.*;
 import com.supwisdom.dlpay.system.service.SettleReportService;
 import com.supwisdom.dlpay.util.EnumCheck;
+import kotlin.Suppress;
 import org.hibernate.query.internal.NativeQueryImpl;
 import org.hibernate.transform.Transformers;
 import org.hibernate.type.DoubleType;
@@ -24,7 +25,6 @@
 import javax.persistence.PersistenceContext;
 import javax.persistence.Query;
 import java.util.ArrayList;
-import java.util.Date;
 import java.util.List;
 
 @Service
@@ -76,18 +76,18 @@
       bean.setCramt(info.getCramt() == null ? 0.00 : info.getCramt());
       bean.setDrbal(info.getDrbal() == null ? 0.00 : info.getDrbal());
       bean.setCrbal(info.getCrbal() == null ? 0.00 : info.getCrbal());
-      if (bean.getLastdaydrbal() == 0 && bean.getLastdaycrbal() == 0 && bean.getDramt() == 0 && bean.getCramt() == 0 && bean.getDrbal() == 0 && bean.getCrbal() == 0) {
+      if (bean.getLastdaydrbal() == 0 && bean.getLastdaycrbal() == 0
+          && bean.getDramt() == 0 && bean.getCramt() == 0
+          && bean.getDrbal() == 0 && bean.getCrbal() == 0) {
         //无交易记录
         if (nodealshow && "y".equals(bean.getDisplayflag())) {
           result.add(bean); //显示
-        } else {
-          continue;
         }
       } else {
         result.add(bean);
       }
     }
-    return new PageResult<SubjectDayShowBean>(result);
+    return new PageResult<>(result);
   }
 
   @Override
@@ -221,7 +221,7 @@
         //商户组,计算该组下所有的交易额
         long transcnt = 0;
         double transamt = 0;
-        List<TShop> childrenShops = getChildrenShopByShopid(shopAllList, shop.getShopid().intValue()); //子商户列表
+        List<TShop> childrenShops = getChildrenShopByShopid(shopAllList, shop.getShopid()); //子商户列表
         for (TShop child : childrenShops) {
           if (!StringUtil.isEmpty(child.getShopaccno())) {
             for (ShopBusinessInfo info : businessInfos) {
@@ -270,7 +270,7 @@
 
 
   @Override
-  public PageResult<ShopBusinessShowBean> getShopTodayBusinessShowInfos(String startdate, String enddate, String shopid, boolean nodealshow){
+  public PageResult<ShopBusinessShowBean> getShopTodayBusinessShowInfos(String startdate, String enddate, String shopid, boolean nodealshow) {
     List<ShopBusinessInfo> businessInfos = getTodayShopbusiness(startdate, enddate); //根据流水统计当天的数据
     if (StringUtil.isEmpty(businessInfos) && !nodealshow) {
       return new PageResult<>(99, "无数据"); //无交易记录
@@ -300,7 +300,9 @@
         .addScalar("dramt", DoubleType.INSTANCE)
         .addScalar("cramt", DoubleType.INSTANCE)
         .setResultTransformer(Transformers.aliasToBean(ShopBusinessInfo.class));
-    List<ShopBusinessInfo> list = query.getResultList();
+
+    @Suppress(names = "UNCHECKED_CAST")
+    List list = (List<ShopBusinessInfo>) query.getResultList();
     return list;
   }
 }
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/ThirdPayCall.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/ThirdPayCall.kt
index 3d3cbae..54f8434 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/ThirdPayCall.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/ThirdPayCall.kt
@@ -1,25 +1,28 @@
 package com.supwisdom.dlpay.api
 
-import com.google.gson.Gson
 import com.sun.jersey.api.client.Client
 import com.sun.jersey.api.client.ClientResponse
-import com.supwisdom.dlpay.api.bean.*
+import com.supwisdom.dlpay.api.bean.BaseResp
+import com.supwisdom.dlpay.api.bean.WechatReqResp
 import com.supwisdom.dlpay.api.domain.TPersondtl
-import com.supwisdom.dlpay.api.domain.TShopdtl
-import com.supwisdom.dlpay.framework.util.*
+import com.supwisdom.dlpay.framework.util.DateUtil
+import com.supwisdom.dlpay.framework.util.MoneyUtil
+import com.supwisdom.dlpay.framework.util.RandomUtils
+import com.supwisdom.dlpay.framework.util.XmlUtils
 import com.supwisdom.dlpay.util.Code
 import mu.KotlinLogging
 
 
-
 class CallService {
 
     companion object {
         private val logger = KotlinLogging.logger { }
 
 
-        fun callWechatPay(config: Map<String, String>, paydtl: TPersondtl, time: String, wechattype: String,
-                          realip: String?, qrcode: String?, openid: String?): BaseResp {
+        fun callWechatPay(config: Map<String, String>, paydtl: TPersondtl,
+                          @Suppress("UNUSED_PARAMETER") time: String, wechattype: String,
+                          realip: String?, @Suppress("UNUSED_PARAMETER") qrcode: String?,
+                          openid: String?): BaseResp {
             val code = BaseResp()
             val appid = config["appid"]
             if (appid.isNullOrEmpty()) {
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/advices.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/advices.kt
index 17d1d2e..03827e5 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/advices.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/advices.kt
@@ -116,9 +116,9 @@
 
     @Around("restcontroller() && postmapping() && args(@RequestBody body, ..)")
     @Throws(Throwable::class)
-    fun logPostMethods(joinPoint: ProceedingJoinPoint, body: Any): Any {
+    fun logPostMethods(joinPoint: ProceedingJoinPoint, body: Any?): Any {
         return try {
-            if (body is APIRequestParam) {
+            if (body != null && body is APIRequestParam) {
                 //TenantContext.setTenantSchema(body.tenantid)
                 body.checkParam()
 
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/shop_api_controller.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/shop_api_controller.kt
index 157c81c..97f2403 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/shop_api_controller.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/shop_api_controller.kt
@@ -116,9 +116,9 @@
         val pageSize = 5000 //每次查询笔数
         var offset = 0
         while (offset < count) {
-            var page = dtlDataService.getDownloadShopBillPage(param, offset, pageSize)
+            val page = dtlDataService.getDownloadShopBillPage(param, offset, pageSize)
             if (null == page || page.data.isNullOrEmpty()) break
-            page!!.data.forEach {
+            page.data.forEach {
                 writeLine(output, it.billno, it.refno, it.amount, it.paytime, it.status, it.sourcetype, it.dtltype) //输出数据
             }
             offset += pageSize
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/user_api_controller.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/user_api_controller.kt
index 8d8fb8f..cb55dad 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/user_api_controller.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/controller/user_api_controller.kt
@@ -2,11 +2,18 @@
 
 import com.supwisdom.dlpay.agent.citizencard.YnrccUtil
 import com.supwisdom.dlpay.agent.service.CitizencardPayService
+import com.supwisdom.dlpay.api.TransactionBuilder
 import com.supwisdom.dlpay.api.bean.*
+import com.supwisdom.dlpay.api.bean.groups.ConfirmAction
+import com.supwisdom.dlpay.api.bean.groups.InitAction
 import com.supwisdom.dlpay.api.exception.RequestParamCheckException
 import com.supwisdom.dlpay.api.service.*
+import com.supwisdom.dlpay.exception.TransactionCheckException
 import com.supwisdom.dlpay.exception.TransactionException
 import com.supwisdom.dlpay.framework.ResponseBodyBuilder
+import com.supwisdom.dlpay.framework.tenant.TenantContext
+import com.supwisdom.dlpay.framework.util.Subject
+import com.supwisdom.dlpay.framework.util.TradeCode
 import com.supwisdom.dlpay.framework.util.TradeDict
 import com.supwisdom.dlpay.framework.util.TradeErrorCode
 import com.supwisdom.dlpay.mobile.service.MobileApiService
@@ -19,17 +26,25 @@
 import org.springframework.validation.annotation.Validated
 import org.springframework.web.bind.annotation.*
 import java.net.URLDecoder
+import kotlin.math.roundToInt
 import javax.validation.Valid
 
+
 @RestController
 @RequestMapping("/api/user")
 class UserAPIController {
     @Autowired
     private lateinit var useService: UserService
+
+    @Autowired
+    private lateinit var accountUtilServcie: AccountUtilServcie
+
     @Autowired
     private lateinit var cardService: CardService
+
     @Autowired
     private lateinit var kafkaSendMsgService: KafkaSendMsgService
+
     @Autowired
     private lateinit var pointsService: PointsService
     @Autowired
@@ -41,6 +56,8 @@
     @Autowired
     private lateinit var qrcodeService: QRCodeService
     @Autowired
+    private lateinit var transactionService: TransactionServiceProxy
+    @Autowired
     private lateinit var ynrccNetPayBusinessService: YnrccNetPayBusinessService
     @Autowired
     private lateinit var userMessageService: UserMessageService
@@ -48,20 +65,18 @@
     @PostMapping("/open")
     fun openAccount(@RequestBody param: OpenUserParam): ResponseEntity<Any> {
         try {
-            useService.findByThirdUniqueIdenty(param.uid).let {
-                if (null != it) {
-                    return ResponseEntity.ok(ResponseBodyBuilder.create()
-                            .fail(TradeErrorCode.REGISTER_USER_EXIST, "该用户唯一号已经注册"))
-                }
+            useService.findByThirdUniqueIdenty(param.uid).takeIf { it != null }?.let {
+                return ResponseEntity.ok(ResponseBodyBuilder.create()
+                        .fail(TradeErrorCode.REGISTER_USER_EXIST, "该用户唯一号已经注册"))
+            }
 
-                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 {
-                    return ResponseEntity.ok(ResponseBodyBuilder.create()
-                            .data("userid", it.userid)
-                            .data("uid", param.uid)
-                            .success())
-                }
+            param.name = URLDecoder.decode(param.name, Charsets.UTF_8.toString()) //解码
+            param.address = param.address?.let { URLDecoder.decode(param.address, Charsets.UTF_8.toString()) }  //解码
+            return useService.registerUser(param).let { person ->
+                ResponseEntity.ok(ResponseBodyBuilder.create()
+                        .data("userid", person.userid)
+                        .data("uid", param.uid)
+                        .success())
             }
         } catch (ex: RequestParamCheckException) {
             return ResponseEntity.ok(ResponseBodyBuilder.create()
@@ -141,16 +156,17 @@
                     .transException(et, "业务处理错误"))
         }
     }
+
     @PostMapping("/querybycardno")
     fun querybycardno(@RequestBody param: QueryUserParam): ResponseEntity<Any> {
         val ret = when (!param.userid.isNullOrEmpty()) {
             true -> cardService.getPersonByUserid(param.userid)
             false -> cardService.getPersonByCardno(param.citizencardno, param.bankcardno)
         }
-        return if(ret.retcode==0){
+        return if (ret.retcode == 0) {
             ResponseEntity.ok(ResponseBodyBuilder.create()
-                    .success(ret,"ok"))
-        }else{
+                    .success(ret, "ok"))
+        } else {
             ResponseEntity.ok(ResponseBodyBuilder.create()
                     .fail(ret.retcode, ret.retmsg))
         }
@@ -159,10 +175,10 @@
     @PostMapping("/querycards")
     fun querycards(@RequestBody param: QueryCardsParam): ResponseEntity<Any> {
         val ret = cardService.getCardsByLastsaveDate(param.starttime, param.endtime)
-        return if(ret.retcode==0){
+        return if (ret.retcode == 0) {
             ResponseEntity.ok(ResponseBodyBuilder.create()
-                    .success(ret,"ok"))
-        }else{
+                    .success(ret, "ok"))
+        } else {
             ResponseEntity.ok(ResponseBodyBuilder.create()
                     .fail(ret.retcode, ret.retmsg))
         }
@@ -170,15 +186,217 @@
 
     @PostMapping("/testmsg")
     fun testmsg(): ResponseEntity<Any> {
-       kafkaSendMsgService.sendJpushMessage("402882816c2727a2016c2728165f0001","交易提醒","你有一笔0.01元的支出,点击查看详情","20190725133506000018", mutableMapOf(),"")
-       return  ResponseEntity.ok(ResponseBodyBuilder.create()
+        kafkaSendMsgService.sendJpushMessage("402882816c2727a2016c2728165f0001", "交易提醒",
+                "你有一笔0.01元的支出,点击查看详情", "20190725133506000018", mutableMapOf(), "")
+        return ResponseEntity.ok(ResponseBodyBuilder.create()
                 .success("ok"))
     }
 
+    @PostMapping("/biz_init")
+    fun userBizInit(@RequestBody @Validated(InitAction::class) request: CardBizParam): ResponseEntity<Any> {
+        val builder = TransactionBuilder().apply {
+            setTransInfo(request.transdate, request.transtime, TradeCode.TRANSCODE_CARD_BIZ, "balance")
+            setOutTransInfo(request.operid, request.operSeqno)
+            dtltype = "cardservice"
+        }
+        val transDesc = arrayListOf<String>()
+        transDesc.add(request.summary)
+        val result = CardBizResponse()
+
+        val user = useService.findAccountByUserid(request.userid, null)
+                ?: return ResponseBodyBuilder.failEntity(result,
+                        TradeErrorCode.ACCOUNT_NOT_EXISTS,
+                        "用户ID ${request.userid} 不存在")
+
+        if (user.transStatus != TradeDict.STATUS_NORMAL) {
+            return ResponseBodyBuilder.failEntity(result,
+                    TradeErrorCode.ACCOUNT_NOT_EXISTS,
+                    "用户ID ${request.userid} 状态异常")
+        }
+
+        val capitalSubj = accountUtilServcie.readSubject(request.capitalSubjno)
+
+        builder.person(user).apply {
+            setAmount(request.totalAmount / 100.0, TradeDict.TRADE_FLAG_IN)
+            setOpposite(capitalSubj.subjno, capitalSubj.subjname)
+        }
+
+
+        val depositAmount = request.totalAmount - request.cost - request.cashPledge - request.charge
+
+        when (request.inOrOut) {
+            TradeDict.TRADE_FLAG_IN -> {
+                request.totalAmount != 0
+            }
+            TradeDict.TRADE_FLAG_OUT -> {
+                request.totalAmount != 0
+            }
+            else -> false
+        }.takeIf {
+            !it
+        }?.apply {
+            return ResponseBodyBuilder.failEntity(result,
+                    TradeErrorCode.INPUT_DATA_ERROR, "资金方案向错误或交易金额有误")
+        }
+        if (request.totalAmount != 0) {
+            if (request.inOrOut == TradeDict.TRADE_FLAG_IN) {
+                if (depositAmount != 0) {
+                    builder.addDebitCreditRecord(capitalSubj.subjno, capitalSubj.subjno,
+                            user.accno, Subject.SUBJNO_PERSONAL_DEPOSIT, request.totalAmount / 100.0, request.summary)
+                    transDesc.add("充值 %.2f 元".format(depositAmount / 100.0))
+                }
+                if (request.cost != 0) {
+                    val subject = accountUtilServcie.readSubject(Subject.SUBJNO_CARD_COST)
+                    builder.addDebitCreditRecord(user.accno, Subject.SUBJNO_PERSONAL_DEPOSIT,
+                            subject.subjno, subject.subjno, request.cost / 100.0,
+                            request.summary)
+                    transDesc.add("收%s %.2f 元".format(subject.subjname, request.cost / 100.0))
+                }
+                if (request.cashPledge != 0) {
+                    val subject = accountUtilServcie.readSubject(Subject.SUBJNO_FOREGIFT)
+                    builder.addDebitCreditRecord(user.accno, Subject.SUBJNO_PERSONAL_DEPOSIT,
+                            subject.subjno, subject.subjno, request.cashPledge / 100.0,
+                            request.summary)
+                    transDesc.add("收%s %.2f 元".format(subject.subjname, request.cashPledge / 100.0))
+                }
+                if (request.charge != 0) {
+                    val subject = accountUtilServcie.readSubject(Subject.SUBJNO_SERVICEFEE_DEFAULT)
+                    builder.addDebitCreditRecord(user.accno, Subject.SUBJNO_PERSONAL_DEPOSIT,
+                            subject.subjno, subject.subjno, request.charge / 100.0,
+                            request.summary)
+                    transDesc.add("收%s %.2f 元".format(subject.subjname, request.charge / 100.0))
+                }
+            } else {
+                if (depositAmount != 0) {
+                    builder.addDebitCreditRecord(user.accno, Subject.SUBJNO_PERSONAL_DEPOSIT,
+                            capitalSubj.subjno, capitalSubj.subjno, request.totalAmount / 100.0, request.summary)
+                    transDesc.add("退余额 %.2f 元".format(depositAmount / 100.0))
+                }
+                if (request.cost != 0) {
+                    val subject = accountUtilServcie.readSubject(Subject.SUBJNO_CARD_COST)
+                    builder.addDebitCreditRecord(subject.subjno, subject.subjno,
+                            user.accno, Subject.SUBJNO_PERSONAL_DEPOSIT,
+                            request.cost / 100.0, request.summary)
+                    transDesc.add("退%s %.2f 元".format(subject.subjname, request.cost / 100.0))
+                }
+                if (request.cashPledge != 0) {
+                    val subject = accountUtilServcie.readSubject(Subject.SUBJNO_FOREGIFT)
+                    builder.addDebitCreditRecord(subject.subjno, subject.subjno,
+                            user.accno, Subject.SUBJNO_PERSONAL_DEPOSIT,
+                            request.cashPledge / 100.0, request.summary)
+                    transDesc.add("退%s %.2f 元".format(subject.subjname, request.cashPledge / 100.0))
+                }
+                if (request.charge != 0) {
+                    val subject = accountUtilServcie.readSubject(Subject.SUBJNO_SERVICEFEE_DEFAULT)
+                    builder.addDebitCreditRecord(subject.subjno, subject.subjno,
+                            user.accno, Subject.SUBJNO_PERSONAL_DEPOSIT,
+                            request.charge / 100.0, request.summary)
+                    transDesc.add("退%s %.2f 元".format(subject.subjname, request.charge / 100.0))
+                }
+            }
+        }
+        builder.description = transDesc.joinToString(";")
+        val transaction = transactionService.init(builder)
+
+        result.apply {
+            accdate = transaction.accdate
+            refno = transaction.refno
+            description = builder.description
+            transStatus = transaction.status
+        }
+        return ResponseBodyBuilder.successEntity(result, "${request.summary}初始化成功")
+    }
+
+    @PostMapping("/biz_confirm")
+    fun userBizConfirm(@RequestBody @Validated(ConfirmAction::class) request: CardBizParam): ResponseEntity<Any> {
+        val transaction = transactionService.success(request.refno)
+        val response = CardBizResponse().apply {
+            accdate = transaction.accdate
+            refno = transaction.refno
+            description = transaction.personDtl.transdesc
+            accountBal = (transaction.personDtl.aftbal * 100).roundToInt()
+            transStatus = transaction.status
+        }
+        return ResponseBodyBuilder.successEntity(response, "${request.summary}确认成功")
+    }
+
+    @PostMapping("/biz_refund_init")
+    fun userBizRefundInit(@RequestBody @Validated(InitAction::class) request: CardBizRefundParam): ResponseEntity<Any> {
+        val result = CardBizResponse()
+        val originTrans = transactionService.findTransactionByRefno(request.originRefno)
+                ?: return ResponseBodyBuilder.failEntity(result, TradeErrorCode.TRANSACTION_NOT_EXISTS,
+                        "退款原交易参考号不存在")
+        if (originTrans.tenantid != TenantContext.getTenantSchema()) {
+            return ResponseBodyBuilder.failEntity(result, TradeErrorCode.INPUT_DATA_ERROR,
+                    "退款交易参考号租户错误")
+        }
+
+        if (!originTrans.person) {
+            return ResponseBodyBuilder.failEntity(result, TradeErrorCode.INPUT_DATA_ERROR,
+                    "指定交易流水没有个人交易明细,无法退款")
+        }
+
+        val builder = TransactionBuilder().apply {
+            this.setTransInfo(request.transdate, request.transtime, TradeCode.TRANSCODE_CARD_BIZ,
+                    "balance")
+            this.setOutTransInfo(request.operid, request.operSeqno)
+        }
+        val transaction = builder.refundInit(request.originRefno, request.totalAmount / 100.0,
+                transactionService)
+
+        result.apply {
+            refno = transaction.refno
+            accdate = transaction.accdate
+            transStatus = transaction.status
+            if (transaction.person) {
+                description = transaction.personDtl.transdesc
+            }
+        }
+        return ResponseBodyBuilder.successEntity(result, "初始化成功")
+    }
+
+    @PostMapping("/biz_refund")
+    fun userBizRefund(refno: String): ResponseEntity<Any> {
+        val result = CardBizResponse()
+        val transaction = transactionService.success(refno)
+        result.apply {
+            this.refno = transaction.refno
+            accdate = transaction.accdate
+            transStatus = transaction.status
+            if (transaction.person) {
+                description = transaction.personDtl.transdesc
+                accountBal = (transaction.personDtl.aftbal * 100.0).roundToInt()
+            }
+        }
+        return ResponseBodyBuilder.failEntity(result, TradeErrorCode.INPUT_DATA_ERROR, "未实现")
+    }
+
+    @GetMapping("/biz_query")
+    fun userBizQuery(refno: String): ResponseEntity<Any> {
+        val transaction = transactionService.findTransactionByRefno(refno)
+                ?: throw TransactionCheckException(TradeErrorCode.TRANSACTION_NOT_EXISTS
+                        , "交易不存在")
+        val result = CardBizResponse()
+        if (transaction.tenantid != TenantContext.getTenantSchema()) {
+            return ResponseBodyBuilder.failEntity(result, TradeErrorCode.INPUT_DATA_ERROR,
+                    "非本租户交易参考号")
+        }
+        result.apply {
+            this.refno = transaction.refno
+            accdate = transaction.accdate
+            if (transaction.person) {
+                description = transaction.personDtl.transdesc
+                accountBal = (transaction.personDtl.aftbal * 100.0).roundToInt()
+            }
+            transStatus = transaction.status
+        }
+        return ResponseBodyBuilder.successEntity(result)
+    }
+
     @PostMapping("/userTask")
     fun userTask(@RequestBody param: UserTaskParam): ResponseEntity<Any> {
         val ret = pointsService.finishTask(param.userid, param.taskid)
-        return if(ret.get("code")==200){
+        return if (ret.get("code") == 200) {
             ResponseEntity.ok(ResponseBodyBuilder.create()
                     .success(ApiResponse().apply {
                         this.retcode = 0
@@ -189,17 +407,19 @@
                     .fail(500, ret.get("msg") as String))
         }
     }
+
     @PostMapping("/getTask")
     fun getTPointsTaskNoPage(userid:String?): ResponseEntity<Any> {
         val ret = pointsService.getTPointsTaskNoPage(userid)
         return if(ret.get("code")==200){
             ResponseEntity.ok(ResponseBodyBuilder.create().data("data", ret.get("dataList")!!)
                     .success("ok"))
-        }else{
+        } else {
             ResponseEntity.ok(ResponseBodyBuilder.create()
                     .fail(500, ret.get("msg") as String))
         }
     }
+
     @PostMapping("/getTaskStatus")
     fun getTaskStatus(userid:String,taskid:Int): ResponseEntity<Any> {
         val dtl = pointsService.getTaskStatus(userid,taskid)
@@ -210,6 +430,7 @@
         return ResponseEntity.ok(ResponseBodyBuilder.create().data("data",time)
                 .success("ok"))
     }
+
     @PostMapping("/getUserPoints")
     fun getUserPoints(@RequestBody param: UserPointsParam): ResponseEntity<Any> {
         var lev = LevelBean()
@@ -218,8 +439,8 @@
         lev.pageNo = param.pageNo
         lev.pageSize = param.pageSize
         val ret = pointsService.getTPointsByname(lev);
-        return  ResponseEntity.ok(ResponseBodyBuilder.create().data("page", ret!!)
-                    .success("ok"))
+        return ResponseEntity.ok(ResponseBodyBuilder.create().data("page", ret!!)
+                .success("ok"))
     }
 
     @PostMapping("/queryPersonDtl")
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/account_service_impl.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/account_service_impl.kt
index 5bc63a9..71c3189 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/account_service_impl.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/account_service_impl.kt
@@ -80,6 +80,7 @@
                     } else {
                         account.lastdayDpsamt += amount
                     }
+                    dtl.aftbal = account.availbal
                     try {
                         entityManager.persist(account)
                     } catch (ex: OptimisticLockException) {
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/card_service_impl.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/card_service_impl.kt
index 1985c94..34e3cbf 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/card_service_impl.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/card_service_impl.kt
@@ -62,8 +62,8 @@
     }
 
     override fun getPersonByCardno(citizencardno: String?, bankcardno: String?): UserInforResponse {
-        var resp = UserInforResponse()
-        var cityCard: TCard?
+        val resp = UserInforResponse()
+        val cityCard: TCard?
         if (!citizencardno.isNullOrEmpty()) {
             //根据市民卡号查询
             cityCard = cardDao.findCardByCardnoAndCardtype(citizencardno, ConstantUtil.CARDTYPE_CITIZENCARD)
@@ -78,7 +78,7 @@
             }
         } else if (!bankcardno.isNullOrEmpty()) {
             //根据银行卡号查询
-            val bankcard = cardDao.findCardByCardnoAndCardtype(bankcardno?.trim(), ConstantUtil.CARDTYPE_BANKCARD)
+            val bankcard = cardDao.findCardByCardnoAndCardtype(bankcardno.trim(), ConstantUtil.CARDTYPE_BANKCARD)
             if (bankcard == null) {
                 resp.retcode = 1
                 resp.retmsg = "银行卡不存在"
@@ -126,6 +126,7 @@
         query.setParameter("starttime", startdate)
         query.setParameter("endtime", enddate)
         query.unwrap(NativeQueryImpl::class.java).setResultTransformer(Transformers.aliasToBean(CitizenCardInfo::class.java))
+        @Suppress("UNCHECKED_CAST")
         val list = query.resultList as List<CitizenCardInfo>
         resp.retcode = 0
         resp.retmsg = "OK"
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/transaction_service_impl.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/transaction_service_impl.kt
index b93e7d3..e26a91b 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/transaction_service_impl.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/transaction_service_impl.kt
@@ -96,6 +96,7 @@
                         userName = builder.person().person!!.accname
                         befbal = builder.person().person!!.availbal
                     }
+                    aftbal = 0.0
                     outtradeno = builder.outtradeno
                     transdate = builder.transDate
                     transtime = builder.transTime
@@ -505,7 +506,7 @@
     }
 
     private fun doReversePrepareAndCheck(originTrans: TTransactionMain, builder: TransactionBuilder,
-                                         amount: Double) {
+                                         @Suppress("UNUSED_PARAMETER") amount: Double) {
         if (originTrans.person) {
             val account = accountUtilService.readAccount(originTrans.personDtl.userid)
             builder.person(account).apply {
@@ -560,18 +561,17 @@
 
         transaction.status = TradeDict.DTL_STATUS_SUCCESS //置为成功
         transactionOnSuccess(transaction, sourcetypeRefno, true)
-//        transaction.checkDate = systemUtilService.accdate
         transaction.settleDate = agentAccdate
         transaction.details?.forEach {
             it.settleDate = agentAccdate
         }
-        if(transaction.person){
+        if (transaction.person) {
             transaction.personDtl.remark = remark
         }
-        if(transaction.shop){
+        if (transaction.shop) {
             transaction.shopDtl.remark = remark
         }
-        if(transaction.subject){
+        if (transaction.subject) {
             //
         }
         transaction.endTime = systemUtilService.sysdatetime.sysdate
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/transaction_service.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/transaction_service.kt
index e7cfca6..4d18a91 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/transaction_service.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/transaction_service.kt
@@ -2,6 +2,7 @@
 
 import com.supwisdom.dlpay.api.ShopAccBalanceAsyncTask
 import com.supwisdom.dlpay.api.TransactionBuilder
+import com.supwisdom.dlpay.api.dao.TransactionMainDao
 import com.supwisdom.dlpay.api.domain.TTransactionMain
 import com.supwisdom.dlpay.exception.TransactionProcessException
 import com.supwisdom.dlpay.framework.util.TradeErrorCode
@@ -53,7 +54,7 @@
 
     // 补帐接口
     @Transactional(rollbackFor = [Exception::class])
-    fun repair(refno: String, agentAccdate: String, sourcetypeRefno: String, remark:String): TTransactionMain
+    fun repair(refno: String, agentAccdate: String, sourcetypeRefno: String, remark: String): TTransactionMain
 }
 
 @Service
@@ -62,10 +63,13 @@
     private lateinit var transactionService: TransactionService
 
     @Autowired
+    private lateinit var kafkaSendMsgService: KafkaSendMsgService
+
+    @Autowired
     private lateinit var shopAccBalanceAsyncTask: ShopAccBalanceAsyncTask
 
     @Autowired
-    private lateinit var kafkaSendMsgService: KafkaSendMsgService
+    private lateinit var transactionMainDao: TransactionMainDao
 
     @Autowired
     private lateinit var pointsService: PointsService
@@ -105,7 +109,10 @@
             }
 
             if (it.person && !it.personDtl.userid.isNullOrEmpty()) {
-                kafkaSendMsgService.sendJpushMessage(it.personDtl.userid, "交易提醒", "你有一笔${it.personDtl.amount}元的支出,点击查看详情", it.refno, mutableMapOf(), it.tenantid)
+                kafkaSendMsgService.sendJpushMessage(it.personDtl.userid,
+                        "交易提醒",
+                        "你有一笔${it.personDtl.amount}元的支出,点击查看详情",
+                        it.refno, mutableMapOf(), it.tenantid)
             }
             if(-it.personDtl.amount>=0) {
                 //支付成功  进行积分处理
@@ -149,4 +156,8 @@
         }
     }
 
+    fun findTransactionByRefno(refno: String): TTransactionMain? {
+        return transactionMainDao.findByRefno(refno)
+    }
+
 }
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/transaction_builder.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/transaction_builder.kt
index 64f9033..1b81661 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/transaction_builder.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/transaction_builder.kt
@@ -8,6 +8,7 @@
 import com.supwisdom.dlpay.framework.domain.TSubject
 import com.supwisdom.dlpay.framework.util.TradeDict
 import com.supwisdom.dlpay.framework.util.TradeErrorCode
+import org.apache.commons.lang3.StringUtils
 import kotlin.math.abs
 
 open class SubTransactionBuilder<T : SubTransactionBuilder<T>>(val parent: TransactionBuilder) {
@@ -217,6 +218,13 @@
     var remark: String = ""
     var dtltype: String = ""
 
+
+    private fun checkSubjectNo(subjno: String) {
+        if (!StringUtils.isNumeric(subjno)) {
+            throw TransactionCheckException(TradeErrorCode.INPUT_DATA_ERROR, "科目号<$subjno>不合法")
+        }
+    }
+
     fun person(): PersonTranactionBuilder {
         return this.personBuilder
     }
@@ -290,6 +298,8 @@
     fun addDebitCreditRecord(debitAccNo: String, debitSubjNo: String,
                              creditAccNo: String, creditSubjNo: String,
                              amount: Double, summary: String): TransactionBuilder {
+        checkSubjectNo(debitSubjNo)
+        checkSubjectNo(creditSubjNo)
         debitCreditLines.add(DebitCreditLine(debitAccNo, debitSubjNo,
                 creditAccNo, creditSubjNo,
                 amount, summary, debitCreditLines.size + 1))
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/framework/controller/security_controller.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/framework/controller/security_controller.kt
index db0f82d..ed5783f 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/framework/controller/security_controller.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/framework/controller/security_controller.kt
@@ -174,6 +174,7 @@
                 ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(mapOf("msg" to "appid error"))
             }
         } ?: ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(mapOf("msg" to "appid error"))
+        @Suppress("UNCHECKED_CAST")
         return result as ResponseEntity<Any>
     }
 }
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/framework/framework_util.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/framework/framework_util.kt
index 1f63e38..c9d61a1 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/framework/framework_util.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/framework/framework_util.kt
@@ -8,6 +8,7 @@
 import com.supwisdom.dlpay.exception.TransactionException
 import com.supwisdom.dlpay.framework.util.TradeErrorCode
 import mu.KotlinLogging
+import org.springframework.http.ResponseEntity
 
 
 class ResponseBodyBuilder private constructor() {
@@ -16,6 +17,14 @@
         private val RESERVED_KEY = setOf("retcode", "retmsg")
         private val LOGGER = KotlinLogging.logger {}
         fun create() = ResponseBodyBuilder()
+
+        fun successEntity(bean: ApiResponse, msg: String? = null): ResponseEntity<Any> {
+            return ResponseEntity.ok(create().success(bean, msg))
+        }
+
+        fun failEntity(bean: ApiResponse, code: Int, msg: String): ResponseEntity<Any> {
+            return ResponseEntity.ok(create().fail(bean, code, msg))
+        }
     }
 
     private var retCode = INVALIDE_RETCODE
@@ -44,6 +53,7 @@
         return bean
     }
 
+
     fun fail(code: Int, msg: String): Map<String, Any> {
         if (code == 0) {
             throw TransactionCheckException(TradeErrorCode.INPUT_DATA_ERROR, "错误码未正确定义")
diff --git a/payapi/src/main/resources/data.sql b/payapi/src/main/resources/data.sql
index 3bd9798..e2c3fac 100644
--- a/payapi/src/main/resources/data.sql
+++ b/payapi/src/main/resources/data.sql
@@ -566,6 +566,10 @@
 INSERT INTO "tb_subject" ("subjid","subjno", "balflag", "displayflag", "endflag", "fsubjno", "opendate", "subjlevel", "subjname", "subjtype", "tenantid")
 VALUES (26, '602103', 2, 'n', 1, '6021', 20190430, 2, '银联充值手续费', 6, '{tenantid}');
 INSERT INTO "tb_subject" ("subjid","subjno", "balflag", "displayflag", "endflag", "fsubjno", "opendate", "subjlevel", "subjname", "subjtype", "tenantid")
+VALUES (32, '602104', 2, 'n', 1, '6021', 20190430, 2, '收手续费', 6, '{tenantid}');
+INSERT INTO "tb_subject" ("subjid","subjno", "balflag", "displayflag", "endflag", "fsubjno", "opendate", "subjlevel", "subjname", "subjtype", "tenantid")
+VALUES (31, '6025', 2, 'y', 0, NULL, 20190430, 1, '卡成本费收入', 6, '{tenantid}');
+INSERT INTO "tb_subject" ("subjid","subjno", "balflag", "displayflag", "endflag", "fsubjno", "opendate", "subjlevel", "subjname", "subjtype", "tenantid")
 VALUES (27, '6601', 2, 'y', 0, NULL, 20190430, 1, '销售费用', 6, '{tenantid}');
 INSERT INTO "tb_subject" ("subjid","subjno", "balflag", "displayflag", "endflag", "fsubjno", "opendate", "subjlevel", "subjname", "subjtype", "tenantid")
 VALUES (28, '660101', 2, 'y', 1, '6601', 20190430, 2, '折扣优惠款', 6, '{tenantid}');
@@ -732,6 +736,8 @@
 VALUES (29, 'canteen', 'dtltypeList', '食堂就餐', '流水类型', '{tenantid}');
 INSERT INTO "tb_dictionary" ("id", "dictval", "dicttype", "dictcaption", "dicttypename", "tenantid")
 VALUES (30, 'shopmarket', 'dtltypeList', '商超消费', '流水类型', '{tenantid}');
+INSERT INTO "tb_dictionary" ("id", "dictval", "dicttype", "dictcaption", "dicttypename", "tenantid")
+VALUES (31, 'cardservice', 'dtltypeList', '卡务流水', '流水类型', '{tenantid}');
 
 
 
diff --git a/payapi/src/test/kotlin/com/supwisdom/dlpay/MvcBaseTest.kt b/payapi/src/test/kotlin/com/supwisdom/dlpay/MvcBaseTest.kt
index 91bd2e1..99294c2 100644
--- a/payapi/src/test/kotlin/com/supwisdom/dlpay/MvcBaseTest.kt
+++ b/payapi/src/test/kotlin/com/supwisdom/dlpay/MvcBaseTest.kt
@@ -1,24 +1,25 @@
 package com.supwisdom.dlpay
 
 import com.google.gson.Gson
-import org.junit.runner.RunWith
+import org.junit.jupiter.api.BeforeEach
+import org.mockito.MockitoAnnotations
 import org.springframework.beans.factory.annotation.Autowired
-import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
-import org.springframework.boot.test.context.SpringBootTest
-import org.springframework.test.context.ActiveProfiles
-import org.springframework.test.context.TestPropertySource
-import org.springframework.test.context.junit4.SpringRunner
 import org.springframework.test.web.servlet.MockMvc
 
 /**
  * mvc 基础测试类
  * 放置基础方法,如认证信息等
  */
-@RunWith(SpringRunner::class)
-@SpringBootTest
-@AutoConfigureMockMvc
-abstract class MvcBaseTest{
+//@RunWith(SpringRunner::class)
+//@SpringBootTest
+//@AutoConfigureMockMvc
+abstract class MvcBaseTest {
     @Autowired
     protected lateinit var mvc: MockMvc
     val gson = Gson()
+
+    @BeforeEach
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+    }
 }
\ No newline at end of file
diff --git a/payapi/src/test/kotlin/com/supwisdom/dlpay/controller/ApiControllerTest.kt b/payapi/src/test/kotlin/com/supwisdom/dlpay/controller/ApiControllerTest.kt
index 01d6e50..672a074 100644
--- a/payapi/src/test/kotlin/com/supwisdom/dlpay/controller/ApiControllerTest.kt
+++ b/payapi/src/test/kotlin/com/supwisdom/dlpay/controller/ApiControllerTest.kt
@@ -1,9 +1,7 @@
 package com.supwisdom.dlpay.controller
 
 import com.supwisdom.dlpay.MvcBaseTest
-import com.supwisdom.dlpay.api.service.KafkaSendMsgService
 import org.junit.Test
-import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.http.MediaType
 import org.springframework.test.web.servlet.request.MockMvcRequestBuilders
 import org.springframework.test.web.servlet.result.MockMvcResultHandlers
diff --git a/payapi/src/test/kotlin/com/supwisdom/dlpay/controller/UserControllerTest.kt b/payapi/src/test/kotlin/com/supwisdom/dlpay/controller/UserControllerTest.kt
index c76eb14..d13dc34 100644
--- a/payapi/src/test/kotlin/com/supwisdom/dlpay/controller/UserControllerTest.kt
+++ b/payapi/src/test/kotlin/com/supwisdom/dlpay/controller/UserControllerTest.kt
@@ -1,80 +1,139 @@
 package com.supwisdom.dlpay.controller
 
 import com.google.gson.Gson
-import com.supwisdom.dlpay.MvcBaseTest
 import com.supwisdom.dlpay.api.bean.OpenUserParam
 import com.supwisdom.dlpay.api.bean.QueryUserParam
+import com.supwisdom.dlpay.api.controller.UserAPIController
 import com.supwisdom.dlpay.api.domain.TAccount
 import com.supwisdom.dlpay.api.domain.TPerson
-import org.junit.Assert
-import org.junit.Test
+import com.supwisdom.dlpay.api.service.UserService
+import com.supwisdom.dlpay.framework.util.TradeErrorCode
+import io.mockk.MockKAnnotations
+import io.mockk.clearMocks
+import io.mockk.every
+import io.mockk.impl.annotations.InjectMockKs
+import io.mockk.impl.annotations.MockK
+import io.mockk.impl.annotations.RelaxedMockK
+import io.mockk.junit5.MockKExtension
+import io.mockk.verify
+import org.hamcrest.Matchers.`is`
+import org.hamcrest.Matchers.notNullValue
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.extension.ExtendWith
 import org.springframework.http.MediaType
+import org.springframework.test.web.servlet.MockMvc
 import org.springframework.test.web.servlet.request.MockMvcRequestBuilders
-import org.springframework.test.web.servlet.result.MockMvcResultHandlers
-import org.springframework.test.web.servlet.result.MockMvcResultMatchers
+import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath
+import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
+import org.springframework.test.web.servlet.setup.MockMvcBuilders
 
 
-class UserControllerTest : MvcBaseTest() {
+@ExtendWith(MockKExtension::class)
+internal class UserControllerTest {
+    companion object {
+        const val thirdUID = "101010"
+    }
 
-    class RetBean {
-        var userid: String = ""
-        var retcode: Int = 0
-        lateinit var person: TPerson
-        lateinit var account: TAccount
+    @InjectMockKs
+    var userAPIController = UserAPIController()
+
+    lateinit var mockMvc: MockMvc
+
+    @MockK
+    lateinit var userService: UserService
+
+    private val person = TPerson().apply {
+        userid = "12312312213"
+    }
+
+    private fun singlePerson() = person
+
+    @BeforeEach
+    fun `context load`() {
+        mockMvc = MockMvcBuilders.standaloneSetup(userAPIController)
+                .build()
+        MockKAnnotations.init(this, relaxUnitFun = true)
+    }
+
+    @AfterEach
+    fun cleanup() {
+        clearMocks(userService)
     }
 
     @Test
-    fun open() {
+    fun `test open account error when thirdUID exists`() {
         val userParam = OpenUserParam()
-        userParam.uid = ""//random req
+        userParam.uid = thirdUID
         userParam.name = "测试名称"
 
-        val ret = mvc.perform(MockMvcRequestBuilders.post("/api/user/open").content(gson.toJson(userParam))
-                .contentType(MediaType.APPLICATION_JSON))
-                .andExpect(MockMvcResultMatchers.status().isOk)
-                .andDo(MockMvcResultHandlers.print())
-                .andReturn()
-        val res = ret.response.contentAsString
-        Assert.assertNotNull(res)
-        val retBean = gson.fromJson(res, RetBean::class.java)
-        Assert.assertNotNull(retBean)
-        Assert.assertEquals(0, retBean.retcode)
-        Assert.assertNotNull(retBean.userid)
-        Assert.assertNotEquals("", retBean.userid)
+        every { userService.findByThirdUniqueIdenty(thirdUID) } returns singlePerson()
+        mockMvc.perform(MockMvcRequestBuilders.post("/api/user/open")
+                .contentType(MediaType.APPLICATION_JSON_UTF8)
+                .content(Gson().toJson(userParam)))
+                .andExpect(status().isOk)
+                .andExpect(jsonPath("$.retcode").value(TradeErrorCode.REGISTER_USER_EXIST))
+
+        verify(exactly = 1) { userService.findByThirdUniqueIdenty(thirdUID) }
     }
 
     @Test
-    fun get() {
+    fun `test open account success`() {
+        val userParam = OpenUserParam()
+        userParam.uid = thirdUID
+        userParam.name = "测试名称"
+        userParam.address = "上海市隆昌路619号8号楼"
 
-        val userParam = QueryUserParam()
-        userParam.uid = "testuseruniqueId"//测试用
-        val gson = Gson()
-        val ret = mvc.perform(MockMvcRequestBuilders.post("/api/user/open").content(gson.toJson(userParam))
-                .contentType(MediaType.APPLICATION_JSON))
-                .andExpect(MockMvcResultMatchers.status().isOk)
-                .andDo(MockMvcResultHandlers.print())
-                .andReturn()
-        val resOpen = ret.response.contentAsString
-        Assert.assertNotNull(resOpen)
-        val retBeanOpen = gson.fromJson(resOpen, RetBean::class.java)
-        Assert.assertNotNull(retBeanOpen)
-        Assert.assertNotNull(retBeanOpen.userid)
-        userParam.userid = retBeanOpen.userid
+        every { userService.findByThirdUniqueIdenty(thirdUID) } returns null
+        every { userService.registerUser(any()) } returns singlePerson()
+        mockMvc.perform(MockMvcRequestBuilders.post("/api/user/open")
+                .contentType(MediaType.APPLICATION_JSON_UTF8)
+                .content(Gson().toJson(userParam)))
+                .andExpect(status().isOk)
+                .andExpect(jsonPath("$.retcode").value(0))
+                .andExpect(jsonPath("$.uid", notNullValue()))
+                .andExpect(jsonPath("$.userid").value(person.userid))
 
-        val retGet = mvc.perform(MockMvcRequestBuilders.get("/api/user/query").content(gson.toJson(userParam))
-                .contentType(MediaType.APPLICATION_JSON))
-                .andExpect(MockMvcResultMatchers.status().isOk)
-                .andDo(MockMvcResultHandlers.print())
-                .andReturn()
-        val res = retGet.response.contentAsString
-        Assert.assertNotNull(res)
-        val retBean = gson.fromJson(res, RetBean::class.java)
-        Assert.assertNotNull(retBean)
-        Assert.assertEquals(0, retBean.retcode)
-        Assert.assertNotNull(retBean.person)
-        Assert.assertEquals(retBeanOpen.userid, retBean.person.userid)
-        Assert.assertNotNull(retBeanOpen.account)
-        Assert.assertEquals(retBeanOpen.person.userid, retBean.account.userid)
+        verify(exactly = 1) { userService.findByThirdUniqueIdenty(thirdUID) }
+        verify(exactly = 1) { userService.registerUser(any()) }
     }
 
+    @Test
+    fun `test query account success`() {
+
+        val param = QueryUserParam().apply {
+            uid = thirdUID
+            userid = "1010101010"
+        }
+
+        val person = TPerson().apply {
+            userid = param.userid
+            name = "张三"
+            idtype = "idcard"
+            idno = "10101010101"
+            mobile = "1231231"
+            email = "ddlddl"
+            status = "1"
+        }
+        val account = TAccount().apply {
+            userid = param.userid
+            availbal = 10.0
+        }
+        every { userService.findByUseridOrThirdUniqueIdenty(param.userid, param.uid) } returns person
+        every { userService.findAccountByUserid(param.userid, null) } returns account
+        every { userService.findPointsAccountByUserid(param.userid) } returns null
+
+        mockMvc.perform(MockMvcRequestBuilders.post("/api/user/query")
+                .contentType(MediaType.APPLICATION_JSON_UTF8)
+                .content(Gson().toJson(param)))
+                .andExpect(status().isOk)
+                .andExpect(jsonPath("$.retcode", `is`(0)))
+                .andExpect(jsonPath("$.userid", `is`(param.userid)))
+                .andExpect(jsonPath("$.balance", `is`(10.0)))
+
+        verify(exactly = 1) { userService.findByUseridOrThirdUniqueIdenty(param.userid, param.uid) }
+        verify(exactly = 1) { userService.findAccountByUserid(param.userid, null) }
+        verify(exactly = 1) { userService.findPointsAccountByUserid(param.userid) }
+    }
 }
\ No newline at end of file
diff --git a/payapi/src/test/kotlin/com/supwisdom/dlpay/transaction_service_test.kt b/payapi/src/test/kotlin/com/supwisdom/dlpay/transaction_service_test.kt
new file mode 100644
index 0000000..cfacc16
--- /dev/null
+++ b/payapi/src/test/kotlin/com/supwisdom/dlpay/transaction_service_test.kt
@@ -0,0 +1,131 @@
+package com.supwisdom.dlpay
+
+import com.supwisdom.dlpay.api.TransactionBuilder
+import com.supwisdom.dlpay.api.dao.TransactionMainDao
+import com.supwisdom.dlpay.api.domain.TAccount
+import com.supwisdom.dlpay.api.domain.TSourceType
+import com.supwisdom.dlpay.api.domain.TTransactionMain
+import com.supwisdom.dlpay.api.repositories.AccountService
+import com.supwisdom.dlpay.api.service.AccountUtilServcie
+import com.supwisdom.dlpay.api.service.SourceTypeService
+import com.supwisdom.dlpay.api.service.TransactionService
+import com.supwisdom.dlpay.api.service.impl.TransactionServiceImpl
+import com.supwisdom.dlpay.framework.data.SystemDateTime
+import com.supwisdom.dlpay.framework.domain.TShopacc
+import com.supwisdom.dlpay.framework.service.SystemUtilService
+import com.supwisdom.dlpay.framework.util.Subject
+import com.supwisdom.dlpay.framework.util.TradeCode
+import com.supwisdom.dlpay.framework.util.TradeDict
+import io.mockk.MockKAnnotations
+import io.mockk.every
+import io.mockk.impl.annotations.InjectMockKs
+import io.mockk.impl.annotations.MockK
+import io.mockk.junit5.MockKExtension
+import io.mockk.mockk
+import io.mockk.verify
+import org.hamcrest.CoreMatchers.notNullValue
+import org.hamcrest.MatcherAssert.assertThat
+import org.hamcrest.Matchers.equalTo
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.extension.ExtendWith
+import java.sql.Timestamp
+import java.util.*
+
+@ExtendWith(MockKExtension::class)
+class TransactionServcieTest {
+    companion object {
+        const val OutId = "1000"
+        const val OutTransNo = "12"
+        const val OperatorID = "3454"
+        const val OperatorType = "operator"
+        const val Refno = "20191216103421000001"
+        const val Accdate = "20191216"
+    }
+
+    @InjectMockKs
+    var transactionService: TransactionService = TransactionServiceImpl()
+
+    @MockK
+    private lateinit var transactionMainDao: TransactionMainDao
+
+    @MockK
+    private lateinit var accountService: AccountService
+
+    @MockK
+    private lateinit var accountUtilService: AccountUtilServcie
+
+    @MockK
+    private lateinit var systemUtilService: SystemUtilService
+
+    @MockK
+    private lateinit var sourceTypeService: SourceTypeService
+
+
+    init {
+        MockKAnnotations.init(this)
+    }
+
+    private fun testAccount(): TAccount {
+        return TAccount().apply {
+            accno = "1200203303"
+            accname = "test"
+            transStatus = TradeDict.STATUS_NORMAL
+        }
+    }
+
+    private fun testShop(): TShopacc {
+        return TShopacc().apply {
+            shopaccno = "4001"
+            shopid = 1
+            shopname = "test shop"
+            status = TradeDict.STATUS_NORMAL
+        }
+    }
+
+    @Test
+    fun testTransaction() {
+        val builder = TransactionBuilder()
+        val person = testAccount()
+        val shop = testShop()
+        val amount = 1600
+        builder.apply {
+            setTransInfo("20191205", "134521", TradeCode.TRANSCODE_CARD_BIZ, "balance")
+            setOutTransInfo(OutId, OutTransNo)
+            operator(OperatorID, OperatorType)
+            dtltype = "restaurant"
+        }.person(person).apply {
+            setOpposite(shop.shopaccno, shop.shopname)
+            setAmount(amount / 100.0, TradeDict.TRADE_FLAG_OUT)
+        }.and().shop(shop).apply {
+            setOpposite(person.accno, person.accname)
+            setAmount(amount / 100.0, TradeDict.TRADE_FLAG_IN)
+        }.and()
+                .addDebitCreditRecord(person.accno, Subject.SUBJNO_PERSONAL_DEPOSIT,
+                        shop.shopaccno, Subject.SUBJNO_MACHANT_INCOME,
+                        amount / 100.0, "消费")
+
+        every { systemUtilService.refno } returns Refno
+        every { systemUtilService.accdate } returns Accdate
+        every { sourceTypeService.getBySourceType(builder.sourceType) } returns TSourceType().apply {
+            sourceType = "balance"
+            checkable = false
+        }
+        every { systemUtilService.sysdatetime } returns mockk {
+            every { hostdate } returns "20191216"
+            every { hosttime } returns "131725"
+            every { hostdatetime } returns "20191216131725"
+            every { sysdate } returns Timestamp(System.currentTimeMillis())
+        }
+
+        every { transactionMainDao.save(any<TTransactionMain>()) } answers {
+            arg(0)
+        }
+
+        val transaction = transactionService.init(builder)
+        assertThat(transaction.refno, equalTo(Refno))
+        assertThat(transaction.accdate, equalTo(Accdate))
+        verify(exactly = 1) { systemUtilService.refno }
+        verify(atLeast = 1) { systemUtilService.accdate }
+        verify(exactly = 1) { sourceTypeService.getBySourceType(builder.sourceType) }
+    }
+}
\ No newline at end of file
diff --git a/payapi/src/test/kotlin/com/supwisdom/dlpay/utils_test.kt b/payapi/src/test/kotlin/com/supwisdom/dlpay/utils_test.kt
index 33cba31..7c22f4c 100644
--- a/payapi/src/test/kotlin/com/supwisdom/dlpay/utils_test.kt
+++ b/payapi/src/test/kotlin/com/supwisdom/dlpay/utils_test.kt
@@ -8,6 +8,7 @@
     @Test
     fun testAgentResponse() {
         val response = AgentResponse<String>()
+        response.payload = "ok test"
         assertNotNull(response.payload)
     }
 }
\ No newline at end of file
diff --git a/ynrcc-agent/build.gradle b/ynrcc-agent/build.gradle
index 4c222f6..2e612c1 100644
--- a/ynrcc-agent/build.gradle
+++ b/ynrcc-agent/build.gradle
@@ -8,11 +8,9 @@
 apply plugin: 'java'
 apply plugin: 'io.spring.dependency-management'
 
-def ynrccVersion = gitVersion()
+def ynrccVersion = version
 def details = versionDetails()
 
-group = rootProject.group
-version = '1'
 sourceCompatibility = jdkVersion
 def ynrccStartClass = 'com.supwisdom.agent.YnrccAgentApplication'
 
@@ -46,25 +44,15 @@
 
 dependencies {
 
-    implementation 'org.springframework.boot:spring-boot-starter-web'
-    implementation 'org.springframework.boot:spring-boot-autoconfigure'
-    implementation 'commons-codec:commons-codec:1.12'
-    implementation 'com.jcabi:jcabi-manifests:1.1'
-    implementation 'org.slf4j:slf4j-parent:1.7.26'
-    implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.5'
-    implementation group: 'com.sun.jersey', name: 'jersey-client', version: '1.19'
-    implementation group: 'javax.servlet', name: 'jstl', version: '1.2'
-    implementation group: 'taglibs', name: 'standard', version: '1.1.2'
-    implementation group: 'commons-codec', name: 'commons-codec', version: '1.6'
-    implementation 'org.dom4j:dom4j:2.1.1'
-    implementation 'commons-beanutils:commons-beanutils:1.9.3'
-    implementation 'commons-net:commons-net:3.6'
+    implementation project(":payapi-common")
 
-    implementation project(':payapi-common')
+    implementation "org.springframework.boot:spring-boot-starter-web"
+    implementation "org.springframework.boot:spring-boot-autoconfigure"
+    implementation "javax.ws.rs:javax.ws.rs-api:${javaxWSRSVersion}"
 
-    testImplementation 'org.springframework.boot:spring-boot-starter-test'
-    testImplementation 'io.rest-assured:rest-assured:3.3.0'
-    testImplementation 'io.rest-assured:spring-mock-mvc:3.3.0'
-    testImplementation 'org.hamcrest:hamcrest:2.1'
+    implementation "org.dom4j:dom4j:${dom4jVersion}"
+    implementation "commons-beanutils:commons-beanutils:${beanutilsVersion}"
+    implementation "commons-net:commons-net:${commonNetVersion}"
+
 }