Merge branch 'hotfix/1.0.26'
diff --git a/bus-qrcode/src/main/java/com/supwisdom/dlpay/busqrcode/BinUtil.java b/bus-qrcode/src/main/java/com/supwisdom/dlpay/busqrcode/BinUtil.java
index ebb4f05..b04ecd4 100644
--- a/bus-qrcode/src/main/java/com/supwisdom/dlpay/busqrcode/BinUtil.java
+++ b/bus-qrcode/src/main/java/com/supwisdom/dlpay/busqrcode/BinUtil.java
@@ -58,10 +58,10 @@
   }
 
   public static String encodeBase64(byte[] data) {
-    return Base64.encodeBase64String(data);
+    return new Base64(true).encodeAsString(data);
   }
 
   public static byte[] decodeBase64(String data) {
-    return Base64.decodeBase64(data);
+    return new Base64(true).decode(data);
   }
 }
diff --git a/bus-qrcode/src/main/java/com/supwisdom/dlpay/busqrcode/QrCode.java b/bus-qrcode/src/main/java/com/supwisdom/dlpay/busqrcode/QrCode.java
index 93f6b60..fdbbf72 100644
--- a/bus-qrcode/src/main/java/com/supwisdom/dlpay/busqrcode/QrCode.java
+++ b/bus-qrcode/src/main/java/com/supwisdom/dlpay/busqrcode/QrCode.java
@@ -209,11 +209,13 @@
       logger.info("=======================================================");
     }
 
+    final String randomStr = getRandomString(6); //随机数
     final String totp = genTOTPWithSeed(qrBuilder.seed, 8);
     final String encDataPlain = new StringJoin(DELIMITER)
         .add(qrBuilder.uid)
         .add(qrBuilder.scope)
-        .add(totp).toString();
+        .add(totp)
+        .add(randomStr).toString();
 
     final byte[] encData = aesEncryptCFB(qrBuilder.rootKey, encDataPlain.getBytes(), qrBuilder.iv);
     final String code = encodeBase64(encData);
@@ -247,7 +249,7 @@
       logger.info("Decode data : <" + encDataPlain + ">");
     }
     String[] fields = encDataPlain.split(DELIMITER);
-    if (fields.length < 3) {
+    if (fields.length < 4) {
       throw new RuntimeException("qrcode plain text format error!");
     }
     String uid = fields[0];
diff --git a/payapi-common/src/main/java/com/supwisdom/dlpay/api/bean/QueryCardInfo.java b/payapi-common/src/main/java/com/supwisdom/dlpay/api/bean/QueryCardInfo.java
new file mode 100644
index 0000000..11f9437
--- /dev/null
+++ b/payapi-common/src/main/java/com/supwisdom/dlpay/api/bean/QueryCardInfo.java
@@ -0,0 +1,26 @@
+package com.supwisdom.dlpay.api.bean;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+@JsonIgnoreProperties(value = { "hibernateLazyInitializer", "handler" })
+public class QueryCardInfo {
+  private String id;
+  private String cardno;
+  private String cardtype;
+  private String cardphyid;
+  private String status;
+  private String transStatus;
+  private String expiredate;
+  private Boolean signed = false;
+  private String userid;
+  private String lastsaved;
+  private String tenantid = "";
+}
diff --git a/payapi-common/src/main/java/com/supwisdom/dlpay/api/bean/QueryCardParam.java b/payapi-common/src/main/java/com/supwisdom/dlpay/api/bean/QueryCardParam.java
new file mode 100644
index 0000000..934946b
--- /dev/null
+++ b/payapi-common/src/main/java/com/supwisdom/dlpay/api/bean/QueryCardParam.java
@@ -0,0 +1,30 @@
+package com.supwisdom.dlpay.api.bean;
+
+import com.supwisdom.dlpay.api.APIRequestParam;
+import com.supwisdom.dlpay.api.annotation.Sign;
+import com.supwisdom.dlpay.api.exception.RequestParamCheckException;
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.commons.lang3.StringUtils;
+
+import javax.validation.constraints.NotEmpty;
+
+@Getter
+@Setter
+public class QueryCardParam extends APIRequestParam {
+  @Sign
+  private String cardno;
+  @Sign
+  private String userid;
+  @Sign
+  @NotEmpty(message = "卡片类型不能为空")
+  private String cardtype;
+
+  @Override
+  public boolean checkParam() throws RequestParamCheckException {
+    if (StringUtils.isEmpty(cardno) && StringUtils.isEmpty(userid)) {
+      throw new RequestParamCheckException("卡号或用户ID不能全为空");
+    }
+    return true;
+  }
+}
diff --git a/payapi-common/src/main/java/com/supwisdom/dlpay/api/bean/QueryCardResponse.java b/payapi-common/src/main/java/com/supwisdom/dlpay/api/bean/QueryCardResponse.java
new file mode 100644
index 0000000..61bb14f
--- /dev/null
+++ b/payapi-common/src/main/java/com/supwisdom/dlpay/api/bean/QueryCardResponse.java
@@ -0,0 +1,12 @@
+package com.supwisdom.dlpay.api.bean;
+
+import lombok.*;
+
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+@ToString
+public class QueryCardResponse extends ApiResponse {
+  QueryCardInfo card;
+}
diff --git a/payapi-common/src/main/java/com/supwisdom/dlpay/api/bean/QueryPersonDtlParam.java b/payapi-common/src/main/java/com/supwisdom/dlpay/api/bean/QueryPersonDtlParam.java
new file mode 100644
index 0000000..35d0b9d
--- /dev/null
+++ b/payapi-common/src/main/java/com/supwisdom/dlpay/api/bean/QueryPersonDtlParam.java
@@ -0,0 +1,31 @@
+package com.supwisdom.dlpay.api.bean;
+
+import com.supwisdom.dlpay.api.APIRequestParam;
+import com.supwisdom.dlpay.api.annotation.Sign;
+import com.supwisdom.dlpay.api.exception.RequestParamCheckException;
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotEmpty;
+
+@Getter
+@Setter
+public class QueryPersonDtlParam extends APIRequestParam {
+  @Sign
+  @NotEmpty(message = "userid不能为空")
+  private String userid;
+  @Sign
+  @NotEmpty(message = "查询月份不能为空")
+  private String month;
+  @Sign
+  @NotEmpty(message = "起始页不能为空")
+  private Integer pageno;
+  @Sign
+  @NotEmpty(message = "每页条数不能为空")
+  private Integer pagesize;
+
+  @Override
+  public boolean checkParam() throws RequestParamCheckException {
+    return true;
+  }
+}
diff --git a/payapi-common/src/main/java/com/supwisdom/dlpay/api/bean/QueryPersonInfo.java b/payapi-common/src/main/java/com/supwisdom/dlpay/api/bean/QueryPersonInfo.java
new file mode 100644
index 0000000..0426249
--- /dev/null
+++ b/payapi-common/src/main/java/com/supwisdom/dlpay/api/bean/QueryPersonInfo.java
@@ -0,0 +1,30 @@
+package com.supwisdom.dlpay.api.bean;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+@JsonIgnoreProperties(value = { "hibernateLazyInitializer", "handler" })
+public class QueryPersonInfo {
+  private String userid;
+  private String name;
+  private String sex;
+  private String status;
+  private String idtype;
+  private String idno;
+  private String country;
+  private String nation;
+  private String email;
+  private String tel;
+  private String mobile;
+  private String addr;
+  private String zipcode;
+  private String lastsaved;
+  private String tenantid = "";
+}
diff --git a/payapi-common/src/main/java/com/supwisdom/dlpay/api/bean/QueryPersonResponse.java b/payapi-common/src/main/java/com/supwisdom/dlpay/api/bean/QueryPersonResponse.java
new file mode 100644
index 0000000..035ff25
--- /dev/null
+++ b/payapi-common/src/main/java/com/supwisdom/dlpay/api/bean/QueryPersonResponse.java
@@ -0,0 +1,12 @@
+package com.supwisdom.dlpay.api.bean;
+
+import lombok.*;
+
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+@ToString
+public class QueryPersonResponse extends ApiResponse {
+  QueryPersonInfo person;
+}
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 c803535..55aa02e 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,11 @@
 
 import com.supwisdom.dlpay.api.bean.*;
 import org.springframework.cloud.openfeign.FeignClient;
-import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import java.util.Map;
 
 @FeignClient(value = "userProxy", url = "${payapi.url}")
 public interface UserProxy {
@@ -27,11 +29,30 @@
   ApiResponse testmsg();
 
   @PostMapping("/api/user/userTask")
-  ApiResponse userTask();
+  ApiResponse userTask(@RequestBody UserTaskParam param);
 
   @PostMapping("/api/user/getTask")
-  ApiResponse getTPointsTaskNoPage();
+  Map<String, Object> getTPointsTaskNoPage();
 
   @PostMapping("/api/user/getUserPoints")
-  ApiResponse getUserPoints(@RequestBody UserPointsParam param);
+  Map<String, Object> getUserPoints(@RequestBody UserPointsParam param);
+
+  @PostMapping("/api/user/queryPersonDtl")
+  Map<String, Object> queryPersonDtl(@RequestBody QueryPersonDtlParam param);
+
+  @PostMapping("/api/user/billcount")
+  Map<String, Object> billCount(@RequestParam("userid") String userid,@RequestParam("month") String month);
+
+  @PostMapping("/api/user/queryPerson")
+  QueryPersonResponse queryPerson(@RequestParam("userid") String userid);
+
+  @PostMapping("/api/user/queryCard")
+  QueryCardResponse queryCard(@RequestBody QueryCardParam param);
+
+  @PostMapping("/api/user/updateCardSign")
+  ApiResponse updateCardSign(@RequestParam("cardno") String cardno,@RequestParam("signed") Boolean signed);
+
+  @PostMapping("/api/user/updateCardTransStatus")
+  ApiResponse updateCardTransStatus(@RequestParam("cardno") String cardno,@RequestParam("status") String status);
+
 }
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/api/dao/PersondtlDao.java b/payapi/src/main/java/com/supwisdom/dlpay/api/dao/PersondtlDao.java
index 1826197..0f39c37 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/api/dao/PersondtlDao.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/api/dao/PersondtlDao.java
@@ -15,6 +15,7 @@
 @Repository
 public interface PersondtlDao extends JpaRepository<TPersondtl, String>,JpaSpecificationExecutor<TPersondtl> {
     Page<TPersondtl> findByUseridAndStatus(String userid,String status, Pageable pageable);
+    Page<TPersondtl> findByUseridAndStatusAndTransdateBetween(String userid, String status,String startdate,String enddate, Pageable pageable);
 
     @Query("select count(t.refno) as totalcnt,sum(t.amount) as totalamt from TPersondtl t where t.status='success' and t.accdate=?1 and t.sourceType=?2 and t.tenantid=?3 ")
     CountAmountBean getPersondtlSumInfo(String accdate, String sourcetype, String tenantid);
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/framework/domain/TPointsTask.java b/payapi/src/main/java/com/supwisdom/dlpay/framework/domain/TPointsTask.java
index a0b32d3..3bfb71b 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/framework/domain/TPointsTask.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/framework/domain/TPointsTask.java
@@ -34,6 +34,9 @@
   @Column(name = "ENABLE")
   private String enable;
 
+  @Column(name = "ORDERNUM")
+  private Integer ordernum;
+
   public Integer getTaskid() {
     return taskid;
   }
@@ -97,4 +100,12 @@
   public void setEnable(String enable) {
     this.enable = enable;
   }
+
+  public Integer getOrdernum() {
+    return ordernum;
+  }
+
+  public void setOrdernum(Integer ordernum) {
+    this.ordernum = ordernum;
+  }
 }
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/framework/domain/TPointsdtl.java b/payapi/src/main/java/com/supwisdom/dlpay/framework/domain/TPointsdtl.java
index 8d42159..34c2f98 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/framework/domain/TPointsdtl.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/framework/domain/TPointsdtl.java
@@ -52,6 +52,17 @@
   @Transient
   private TPointsMain tPointsMain;
 
+  @Transient
+  private String typename;
+
+  public String getTypename() {
+    return typename;
+  }
+
+  public void setTypename(String typename) {
+    this.typename = typename;
+  }
+
   public TPointsMain gettPointsMain() {
     return tPointsMain;
   }
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/framework/util/TradeDict.java b/payapi/src/main/java/com/supwisdom/dlpay/framework/util/TradeDict.java
index 891af93..161b1c7 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/framework/util/TradeDict.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/framework/util/TradeDict.java
@@ -127,6 +127,9 @@
   public static final String TASK_FLAG_FINISH = "task";     //任务
   public static final String CONSUME_FLAG_OUTPOINTS = "outpoints";     //过期积分
 
+
+  public static final String DICT_POINTSDTL_TYPE = "pointsDtlTypeName";     //字典表类型
+
   //积分任务表的类型tb_points_task
   public static final String TASK_FLAG_FIRST = "first";
   public static final String TASK_FLAG_EVEDAY = "everyday";
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 8bf82ae..c65cd8c 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
@@ -147,7 +147,7 @@
     tPointsMain.setName(param.getName());
     tPointsMain.setCardno(param.getIdno());
     tPointsMain.setLevelname(tPersonLevel.getName());
-    Pageable pageable = PageRequest.of(param.getPageNo() - 1, param.getPageSize());
+    Pageable pageable = PageRequest.of(param.getPageNo() - 1, param.getPageSize(), Sort.by(Sort.Direction.DESC, "id"));
 
 //    Page<TPointsdtl> page = pointsDtlDao.findAllByUserid(tCard.getUserid(),pageable);
 
@@ -175,6 +175,10 @@
 /*      page.getContent().get(0).settPointsMain(tPointsMain);*/
       for (TPointsdtl temp:page.getContent()){
         temp.settPointsMain(tPointsMain);
+        TDictionary byDicttypeAndDictval = dictionaryDao.getByDicttypeAndDictval(TradeDict.DICT_POINTSDTL_TYPE, temp.getType());
+        if (byDicttypeAndDictval != null) {
+          temp.setTypename(byDicttypeAndDictval.getDicttypename());
+        }
       }
     }
     return new PageResult<>(page);
@@ -237,7 +241,7 @@
       if (rate < Double.parseDouble(noActivetemp.getRate())) {
         String noStartdate = noActivetemp.getStartdate();
         String noEnddate = noActivetemp.getEnddate();
-        if (DateUtil.compareDatetime(nowDateTemp, noStartdate) >= 0 && DateUtil.compareDatetime(noEnddate, nowDateTemp) >= 0) {
+        if (DateUtil.compareDatetime(DateUtil.getNow("yyyyMMddHHmmss"), noStartdate+"000000") >= 0 && DateUtil.compareDatetime(noEnddate+"235959", DateUtil.getNow("yyyyMMddHHmmss")) >= 0) {
           rate = Double.parseDouble(noActivetemp.getRate());
         }
       }
@@ -249,7 +253,8 @@
         String yearStartdate = yearActivetemp.getStartdate();
         String yearEnddate = yearActivetemp.getEnddate();
         String yearDateTemp = DateUtil.getNow("MMdd");
-        if (DateUtil.compareDatetime(yearDateTemp, yearStartdate) >= 0 && DateUtil.compareDatetime(yearEnddate, yearDateTemp) >= 0) {
+        String yearTemp = DateUtil.getNow("yyyy");
+        if (DateUtil.compareDatetime(yearTemp+yearDateTemp+"000000", yearTemp+yearStartdate+"000000") >= 0 && DateUtil.compareDatetime(yearTemp+yearEnddate+"000000", yearTemp+yearDateTemp+"000000") >= 0) {
           rate = Double.parseDouble(yearActivetemp.getRate());
         }
       }
@@ -786,10 +791,18 @@
       public Predicate toPredicate(Root<TPointsdtl> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
         List<Predicate> predicates = new ArrayList<>();
         if (!StringUtil.isEmpty(param.getStartDate())) {
-          predicates.add(criteriaBuilder.ge(root.get("transdate").as(Long.class), Long.valueOf(DateUtil.formatDateStr(param.getStartDate(), "yyyy年MM月dd日", "yyyyMMdd"))));
+          if (param.getStartDate().length() == 8) {
+            predicates.add(criteriaBuilder.ge(root.get("transdate").as(Long.class), Long.valueOf(param.getStartDate())));
+          } else {
+            predicates.add(criteriaBuilder.ge(root.get("transdate").as(Long.class), Long.valueOf(DateUtil.formatDateStr(param.getStartDate(), "yyyy年MM月dd日", "yyyyMMdd"))));
+          }
         }
         if (!StringUtil.isEmpty(param.getEndDate())) {
-          predicates.add(criteriaBuilder.le(root.get("transdate").as(Long.class), Long.valueOf(DateUtil.formatDateStr(param.getEndDate(), "yyyy年MM月dd日", "yyyyMMdd"))));
+          if (param.getStartDate().length() == 8) {
+            predicates.add(criteriaBuilder.le(root.get("transdate").as(Long.class), Long.valueOf(param.getEndDate())));
+          } else {
+            predicates.add(criteriaBuilder.le(root.get("transdate").as(Long.class), Long.valueOf(DateUtil.formatDateStr(param.getEndDate(), "yyyy年MM月dd日", "yyyyMMdd"))));
+          }
         }
         if (param.getRefno() != null) {
           predicates.add(criteriaBuilder.equal(root.get("refno").as(Integer.class), param.getRefno()));
@@ -910,7 +923,7 @@
 
   @Override
   public JsonResult getTPointsTaskNoPage() {
-    return JsonResult.ok().put("dataList",pointsTaskDao.findAll());
+    return JsonResult.ok().put("dataList",pointsTaskDao.findAll(Sort.by(Sort.Direction.ASC,"ordernum")));
   }
 
   @Override
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/bean/DtlGroupResultBean.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/bean/DtlGroupResultBean.kt
new file mode 100644
index 0000000..0e7ab74
--- /dev/null
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/bean/DtlGroupResultBean.kt
@@ -0,0 +1,8 @@
+package com.supwisdom.dlpay.api.bean
+
+import java.math.BigDecimal
+
+class DtlGroupResultBean {
+    var transtype:String = ""
+    var amount:BigDecimal = BigDecimal(0)
+}
\ No newline at end of file
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 94b077b..14a7bf8 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
@@ -6,18 +6,15 @@
 import com.supwisdom.dlpay.api.service.KafkaSendMsgService
 import com.supwisdom.dlpay.api.service.UserService
 import com.supwisdom.dlpay.exception.TransactionException
-import com.supwisdom.dlpay.exception.TransactionProcessException
 import com.supwisdom.dlpay.framework.ResponseBodyBuilder
-import com.supwisdom.dlpay.framework.service.CommonService
 import com.supwisdom.dlpay.framework.util.TradeErrorCode
 import com.supwisdom.dlpay.system.bean.LevelBean
 import com.supwisdom.dlpay.system.service.PointsService
+import org.apache.commons.beanutils.BeanUtils
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.http.ResponseEntity
 import org.springframework.web.bind.annotation.*
 import java.net.URLDecoder
-import javax.servlet.http.HttpServletRequest
-import javax.servlet.http.HttpServletResponse
 
 @RestController
 @RequestMapping("/api/user")
@@ -167,7 +164,10 @@
         val ret = pointsService.finishTask(param.userid, param.taskid)
         return if(ret.get("code")==200){
             ResponseEntity.ok(ResponseBodyBuilder.create()
-                    .success("ok"))
+                    .success(ApiResponse().apply {
+                        this.retcode = 0
+                        this.retmsg = "ok"
+                    }, "ok"))
         }else{
             ResponseEntity.ok(ResponseBodyBuilder.create()
                     .fail(500, ret.get("msg") as String))
@@ -177,7 +177,7 @@
     fun getTPointsTaskNoPage(): ResponseEntity<Any> {
         val ret = pointsService.getTPointsTaskNoPage()
         return if(ret.get("code")==200){
-            ResponseEntity.ok(ResponseBodyBuilder.create().data("ret", ret.get("dataList")!!)
+            ResponseEntity.ok(ResponseBodyBuilder.create().data("data", ret.get("dataList")!!)
                     .success("ok"))
         }else{
             ResponseEntity.ok(ResponseBodyBuilder.create()
@@ -195,4 +195,72 @@
         return  ResponseEntity.ok(ResponseBodyBuilder.create().data("page", ret!!)
                     .success("ok"))
     }
+
+    @PostMapping("/queryPersonDtl")
+    fun queryPersonDtl(@RequestBody param: QueryPersonDtlParam): ResponseEntity<Any> {
+        val page = useService.findPersondtlByUseridAndMonth(param)
+        return  ResponseEntity.ok(ResponseBodyBuilder.create().data("data", page)
+                .success("ok"))
+    }
+
+    @PostMapping("/billcount")
+    fun billCount(userid:String,month:String): ResponseEntity<Any> {
+        val page = useService.findDtlMonthCountByUserid(userid,month)
+        return  ResponseEntity.ok(ResponseBodyBuilder.create().data("data", page!!)
+                .success("ok"))
+    }
+
+    @PostMapping("/queryPerson")
+    fun queryPersonDtl( userid:String ): ResponseEntity<Any> {
+        val person = useService.findPersonByUserid(userid)
+                ?:return ResponseEntity.ok(ResponseBodyBuilder.create()
+                        .fail(500, "未找到[userid=${userid}]的用户"))
+        return  ResponseEntity.ok(ResponseBodyBuilder.create()
+                .success(QueryPersonResponse().apply{
+                    this.retcode = 0
+                    this.retmsg = "ok"
+                    val personInfo = QueryPersonInfo()
+                    BeanUtils.copyProperties(personInfo,person)
+                    this.person = personInfo
+                },"ok"))
+    }
+
+    @PostMapping("/queryCard")
+    fun queryCard(@RequestBody param: QueryCardParam): ResponseEntity<Any> {
+        val card = cardService.getCardByCardNoOrUserid(param)
+                ?:return ResponseEntity.ok(ResponseBodyBuilder.create()
+                        .fail(500, "未找到指定条件的卡片"))
+        return  ResponseEntity.ok(ResponseBodyBuilder.create()
+                .success(QueryCardResponse().apply {
+                    this.retcode = 0
+                    this.retmsg = "ok"
+                    val cardInfo = QueryCardInfo()
+                    BeanUtils.copyProperties(cardInfo,card)
+                    this.card = cardInfo
+                },"ok"))
+    }
+
+    @PostMapping("/updateCardSign")
+    fun updateCardSign(cardno:String,signed:Boolean):ResponseEntity<Any>{
+        val ret = cardService.updateCardSign(cardno, signed)
+        return if(ret.retcode==0){
+            ResponseEntity.ok(ResponseBodyBuilder.create()
+                    .success(ret,"ok"))
+        }else{
+            ResponseEntity.ok(ResponseBodyBuilder.create()
+                    .fail(ret.retcode, ret.retmsg))
+        }
+    }
+
+    @PostMapping("/updateCardTransStatus")
+    fun updateCardTransStatus(cardno:String,status:String):ResponseEntity<Any>{
+        val ret = cardService.updateCardTransStatus(cardno, status)
+        return if(ret.retcode==0){
+            ResponseEntity.ok(ResponseBodyBuilder.create()
+                    .success(ret,"ok"))
+        }else{
+            ResponseEntity.ok(ResponseBodyBuilder.create()
+                    .fail(ret.retcode, ret.retmsg))
+        }
+    }
 }
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/card_service.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/card_service.kt
index b262bbb..e99baab 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/card_service.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/card_service.kt
@@ -1,6 +1,8 @@
 package com.supwisdom.dlpay.api.service
 
+import com.supwisdom.dlpay.api.bean.ApiResponse
 import com.supwisdom.dlpay.api.bean.CardsResponse
+import com.supwisdom.dlpay.api.bean.QueryCardParam
 import com.supwisdom.dlpay.api.bean.UserInforResponse
 import com.supwisdom.dlpay.api.domain.TCard
 import com.supwisdom.dlpay.api.domain.TPerson
@@ -22,4 +24,13 @@
 
     @Transactional(rollbackFor = arrayOf(Exception::class), readOnly = true)
     fun getPersonByUserid(userid: String): UserInforResponse
+
+    @Transactional(rollbackFor = arrayOf(Exception::class), readOnly = true)
+    fun getCardByCardNoOrUserid(param: QueryCardParam): TCard?
+
+    @Transactional(rollbackFor = arrayOf(Exception::class))
+    fun updateCardSign(cardno:String,signed:Boolean): ApiResponse
+
+    @Transactional(rollbackFor = arrayOf(Exception::class))
+    fun updateCardTransStatus(cardno:String,status:String): ApiResponse
 }
\ No newline at end of file
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 095115d..9a0c135 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
@@ -1,14 +1,13 @@
 package com.supwisdom.dlpay.api.service.impl
 
-import com.supwisdom.dlpay.api.bean.CardsResponse
-import com.supwisdom.dlpay.api.bean.CitizenCardInfo
-import com.supwisdom.dlpay.api.bean.UserInforResponse
+import com.supwisdom.dlpay.api.bean.*
 import com.supwisdom.dlpay.api.dao.CardDao
 import com.supwisdom.dlpay.api.dao.PersonDao
 import com.supwisdom.dlpay.api.domain.TCard
 import com.supwisdom.dlpay.api.domain.TPerson
 import com.supwisdom.dlpay.api.service.CardService
 import com.supwisdom.dlpay.exception.TransactionProcessException
+import com.supwisdom.dlpay.framework.util.StringUtil
 import com.supwisdom.dlpay.framework.util.TradeDict
 import com.supwisdom.dlpay.framework.util.TradeErrorCode
 import com.supwisdom.dlpay.util.ConstantUtil
@@ -161,4 +160,43 @@
         resp.retmsg = "查询成功"
         return resp
     }
+
+    override fun getCardByCardNoOrUserid(param: QueryCardParam): TCard? {
+        if (!StringUtil.isEmpty(param.cardno)) {
+            return cardDao.findCardByCardnoAndCardtype(param.cardno,param.cardtype)
+        }else if (!StringUtil.isEmpty(param.userid)) {
+            return cardDao.findCardByUseridAndCardtype(param.userid,param.cardtype)
+        }
+        return null
+    }
+
+    override fun updateCardSign(cardno: String, signed: Boolean): ApiResponse {
+        val result = ApiResponse().apply {
+            this.retcode = 1
+            this.retmsg = "卡片不存在"
+        }
+        val card = cardDao.findCardByCardnoAndCardtype(cardno, ConstantUtil.CARDTYPE_BANKCARD)
+                ?: return result
+        card.signed = signed
+        cardDao.save(card)
+        return result.apply {
+            this.retcode = 0
+            this.retmsg = "ok"
+        }
+    }
+
+    override fun updateCardTransStatus(cardno: String, status: String): ApiResponse {
+        val result = ApiResponse().apply {
+            this.retcode = 1
+            this.retmsg = "卡片不存在"
+        }
+        val card = cardDao.findCardByCardnoAndCardtype(cardno, ConstantUtil.CARDTYPE_BANKCARD)
+                ?: return result
+        card.transStatus = status
+        cardDao.save(card)
+        return result.apply {
+            this.retcode = 0
+            this.retmsg = "ok"
+        }
+    }
 }
\ No newline at end of file
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/user_service_impl.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/user_service_impl.kt
index 3256e61..ce708b1 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/user_service_impl.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/user_service_impl.kt
@@ -1,17 +1,25 @@
 package com.supwisdom.dlpay.api.service.impl
 
+import com.supwisdom.dlpay.api.bean.DtlGroupResultBean
 import com.supwisdom.dlpay.api.bean.ModifyUserParam
 import com.supwisdom.dlpay.api.bean.OpenUserParam
+import com.supwisdom.dlpay.api.bean.QueryPersonDtlParam
 import com.supwisdom.dlpay.api.dao.*
 import com.supwisdom.dlpay.api.domain.*
-import com.supwisdom.dlpay.framework.service.SystemUtilService
 import com.supwisdom.dlpay.api.service.UserService
 import com.supwisdom.dlpay.exception.TransactionProcessException
+import com.supwisdom.dlpay.framework.service.SystemUtilService
 import com.supwisdom.dlpay.framework.util.*
+import org.hibernate.query.NativeQuery
+import org.hibernate.transform.Transformers
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.data.domain.PageRequest
 import org.springframework.data.domain.Sort
 import org.springframework.stereotype.Service
+import java.math.BigDecimal
+import javax.persistence.EntityManager
+import javax.persistence.PersistenceContext
+import javax.persistence.Query
 
 /**
  * Created by shuwei on 2019/4/15.
@@ -30,6 +38,8 @@
     private lateinit var systemUtilService: SystemUtilService
     @Autowired
     private lateinit var persondtlDao: PersondtlDao
+    @PersistenceContext
+    private lateinit var em: EntityManager
 
 
     override fun registerUser(param: OpenUserParam): TPerson {
@@ -179,6 +189,36 @@
         return PageResult<TPersondtl>(persondtlDao.findByUseridAndStatus(userid,TradeDict.DTL_STATUS_SUCCESS,pageable))
     }
 
+    override fun findPersondtlByUseridAndMonth(param: QueryPersonDtlParam): PageResult<TPersondtl> {
+        var pageable = PageRequest.of(param.pageno - 1, param.pagesize, Sort.Direction.DESC, "transdate","transtime")
+        return PageResult<TPersondtl>(persondtlDao.findByUseridAndStatusAndTransdateBetween(param.userid,TradeDict.DTL_STATUS_SUCCESS,param.month+"00",param.month+"32",pageable))
+    }
+
+    @Suppress("JpaQueryApiInspection")
+    override fun findDtlMonthCountByUserid(userid: String, month: String): Map<String, Any>? {
+        val totalSql = "select sum(cast(amount as decimal(18,2))) total from tb_persondtl where userid =:userid and transdate between :startdate and :enddate and status = 'success' and tradeflag = 'out'"
+        val totalQuery: Query = em.createNativeQuery(totalSql)
+        totalQuery.setParameter("userid", userid)
+        totalQuery.setParameter("startdate", month + "00")
+        totalQuery.setParameter("enddate", month + "32")
+        val list = totalQuery.resultList
+        val result = HashMap<String,Any>()
+        if (list.isNotEmpty()&&list[0]!=null) {
+            result["total"] = list[0] as BigDecimal
+            val groupSql = "select transdesc transtype,sum(cast(amount as decimal(18,2))) amount from tb_persondtl where userid =:userid and transdate between :startdate and :enddate and status = 'success' and tradeflag = 'out' group by transdesc"
+            val groupQuery = em.createNativeQuery(groupSql)
+            groupQuery.setParameter("userid", userid)
+            groupQuery.setParameter("startdate", month + "00")
+            groupQuery.setParameter("enddate", month + "32")
+            val nativeQuery = groupQuery.unwrap(NativeQuery::class.java)
+            nativeQuery.setResultTransformer(Transformers.aliasToBean(DtlGroupResultBean::class.java))
+            result["group"] = nativeQuery.resultList
+        } else {
+            result["total"] = 0
+        }
+        return result
+    }
+
     override fun findPersondtlDetailByUserid(userid: String, billno: String): TPersondtl? {
         var dtl = persondtlDao.findById(billno)
         if(dtl.isPresent){
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/user_service.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/user_service.kt
index f758859..26fc2ff 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/user_service.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/user_service.kt
@@ -2,6 +2,7 @@
 
 import com.supwisdom.dlpay.api.bean.ModifyUserParam
 import com.supwisdom.dlpay.api.bean.OpenUserParam
+import com.supwisdom.dlpay.api.bean.QueryPersonDtlParam
 import com.supwisdom.dlpay.api.domain.*
 import com.supwisdom.dlpay.framework.util.PageResult
 import org.springframework.transaction.annotation.Propagation
@@ -45,6 +46,12 @@
     fun findPersondtlByUserid(userid:String, pageno :Int) : PageResult<TPersondtl>
 
     @Transactional(propagation = Propagation.REQUIRED, rollbackFor = arrayOf(Exception::class), readOnly = true)
+    fun findPersondtlByUseridAndMonth(param: QueryPersonDtlParam) : PageResult<TPersondtl>
+
+    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = arrayOf(Exception::class), readOnly = true)
+    fun findDtlMonthCountByUserid(userid:String,month: String) : Map<String,Any>?
+
+    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = arrayOf(Exception::class), readOnly = true)
     fun findPersondtlDetailByUserid(userid:String, billno :String) : TPersondtl?
 
 }
\ No newline at end of file