Kaynağa Gözat

充值流程

wujiefeng 1 yıl önce
ebeveyn
işleme
38ee143b0c
31 değiştirilmiş dosya ile 605 ekleme ve 414 silme
  1. 2 0
      PaymentClient/src/main/java/com/zhongshu/payment/client/model/RechargeRecordModel.java
  2. 3 0
      PaymentClient/src/main/java/com/zhongshu/payment/client/model/param/GetWalletParam.java
  3. 2 2
      PaymentClient/src/main/java/com/zhongshu/payment/client/model/param/OrderParam.java
  4. 8 8
      PaymentClient/src/main/java/com/zhongshu/payment/client/model/param/RechargeParam.java
  5. 15 5
      PaymentClient/src/main/java/com/zhongshu/payment/client/model/param/RecordSearchParam.java
  6. 5 0
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/controller/RechargeController.java
  7. 36 0
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/controller/TradeManageController.java
  8. 7 11
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/controller/TransferController.java
  9. 12 7
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/controller/WalletController.java
  10. 4 6
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/controller/test/TestController.java
  11. 5 4
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/controller/wxPaymentV3/WechatNotifyController.java
  12. 5 7
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/controller/wxPaymentV3/WechatPayV3Controller.java
  13. 3 0
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/dao/RechargeRecordDao.java
  14. 0 12
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/dao/TradebillDao.java
  15. 4 0
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/dao/WalletDao.java
  16. 6 2
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/dao/extend/RechargeRecordDaoExtend.java
  17. 44 10
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/dao/impl/RechargeRecordDaoImpl.java
  18. 0 54
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/domain/tradebill/Tradebill.java
  19. 24 0
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/domain/wallet/RechargeRecord.java
  20. 12 0
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/domain/wallet/Wallet.java
  21. 7 0
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/domain/wallet/WalletFlow.java
  22. 0 68
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/domain/wechatPay/WxOrder.java
  23. 67 53
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/service/RechargeService.java
  24. 57 0
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/service/TradeManageService.java
  25. 18 14
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/service/TransferService.java
  26. 32 37
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/service/wallet/WalletService.java
  27. 29 22
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/service/wxPaymentV3/WxPayNotifyService.java
  28. 75 65
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/service/wxPaymentV3/WxPaymentService.java
  29. 35 27
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/service/wxPaymentV3/WxTransferBatchService.java
  30. 64 0
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/timer/ComplexTimer.java
  31. 24 0
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/utils/DateUtils.java

+ 2 - 0
PaymentClient/src/main/java/com/zhongshu/payment/client/model/RechargeRecordModel.java

@@ -58,4 +58,6 @@ public class RechargeRecordModel {
     private TransferModel transferModel;
 
     private String remark;
+
+    private WalletModel walletModel;
 }

+ 3 - 0
PaymentClient/src/main/java/com/zhongshu/payment/client/model/param/GetWalletParam.java

@@ -16,4 +16,7 @@ public class GetWalletParam {
 
     @Schema(name = "walletType", description = "钱包类型:Shop, User", example = "User")
     private WalletType walletType;
+
+    @Schema(name = "shopId", description = "商户oid")
+    private String shopId;
 }

+ 2 - 2
PaymentClient/src/main/java/com/zhongshu/payment/client/model/param/OrderParam.java

@@ -14,8 +14,8 @@ public class OrderParam {
     @Schema(name = "outTradeNo", description = "商户订单号(必填)")
     private String outTradeNo;
 
-    @Schema(name = "jscode", description = "微信用户授权码", example = "123456")
-    private String jscode;
+    @Schema(name = "openid", description = "微信用户openid", example = "123456")
+    private String openid;
 
     @Schema(name = "appid", description = "appid", example = "123456")
     private String appid;

+ 8 - 8
PaymentClient/src/main/java/com/zhongshu/payment/client/model/param/RechargeParam.java

@@ -11,30 +11,30 @@ import lombok.Data;
 @Data
 public class RechargeParam {
 
-    @Schema(name = "oid", description = "项目id",required = true, example = "")
+    @Schema(name = "oid", description = "项目id", example = "")
     private String oid;
 
-    @Schema(name = "schoolId", description = "学校id",required = true, example = "")
+    @Schema(name = "schoolId", description = "学校id", example = "")
     private String schoolId;
 
     @Schema(name = "appid", description = "appid")
     private String appid;
 
-    @Schema(name = "walletId", description = "钱包id",required = true, example = "")
+    @Schema(name = "walletId", description = "钱包id", example = "")
     private String walletId;
 
-    @Schema(name = "paymentType", description = "支付方式", required = true, example = "WeChat")
+    @Schema(name = "paymentType", description = "支付方式", example = "WeChat")
     private PaymentType paymentType;
 
     // 商品描述(必填)
-    @Schema(name = "description", description = "商品描述(必填)", required = true, example = "充值服务")
+    @Schema(name = "description", description = "商品描述(必填)", example = "充值服务")
     private String description;
 
     // 订单金额(必填)
-    @Schema(name = "total", description = "订单金额",required = true, example = "")
+    @Schema(name = "total", description = "订单金额", example = "")
     private Integer total;
 
-//    @Schema(name = "jscode", description = "微信用户授权码", example = "123456")
-//    private String jscode;
+    @Schema(name = "openid", description = "微信用户openid", example = "123456")
+    private String openid;
 
 }

+ 15 - 5
PaymentClient/src/main/java/com/zhongshu/payment/client/model/param/TransferSearchParam.java → PaymentClient/src/main/java/com/zhongshu/payment/client/model/param/RecordSearchParam.java

@@ -1,6 +1,8 @@
 package com.zhongshu.payment.client.model.param;
 
+import com.zhongshu.payment.client.types.PaymentType;
 import com.zhongshu.payment.client.types.RechargeState;
+import com.zhongshu.payment.client.types.TradeType;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 
@@ -9,10 +11,10 @@ import lombok.Data;
  * @date 2024/7/31
  */
 @Data
-public class TransferSearchParam {
+    public class RecordSearchParam {
 
-    @Schema(description = "项目id")
-    private String oid;
+    @Schema(description = "项目oid")
+    private String projectOid;
 
     @Schema(description = "部门id")
     private String departmentId;
@@ -20,17 +22,25 @@ public class TransferSearchParam {
     @Schema(description = "用户id")
     private String userId;
 
-    @Schema(description = "商户id")
+    @Schema(description = "商户oid")
     private String shopId;
 
+    @Schema(description = "学校oid")
+    private String schoolId;
+
+    @Schema(description = "支付方式")
+    private PaymentType paymentType;
+
     @Schema(description = "支付状态")
     private RechargeState rechargeState;
 
+    @Schema(description = "交易类型")
+    private TradeType tradeType;
+
     @Schema(description = "订单号")
     private String outTradeNo;
 
     @Schema(description = "人员编号")
     private String userCode;
 
-    private String schoolId;
 }

+ 5 - 0
PaymentServer/src/main/java/com/zhongshu/payment/server/core/controller/RechargeController.java

@@ -9,6 +9,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.MediaType;
+import org.springframework.util.Assert;
 import org.springframework.web.bind.annotation.*;
 
 /**
@@ -42,6 +43,7 @@ public class RechargeController {
     @Operation(summary = "查询订单支付状态", description = "查询订单支付状态")
     @GetMapping(value = "queryTradeState")
     public Object queryTradeState(@RequestParam("outTradeNo") String outTradeNo){
+        Assert.notNull(outTradeNo, "必填参数校验:缺少必填参数\"outTradeNo\"");
         return rechargeService.queryTradeState(outTradeNo);
     }
 
@@ -49,6 +51,7 @@ public class RechargeController {
     @Operation(summary = "关闭充值订单", description = "关闭充值订单")
     @PostMapping(value = "close")
     public Object close(@RequestParam("outTradeNo") String outTradeNo){
+        Assert.notNull(outTradeNo, "必填参数校验:缺少必填参数\"outTradeNo\"");
         return rechargeService.close(outTradeNo);
     }
 
@@ -56,6 +59,7 @@ public class RechargeController {
     @Operation(summary = "查询充值订单列表", description = "查询充值订单列表")
     @PostMapping(value = "queryListByWallet")
     public Object queryListByWallet(@RequestBody QueryWalletParam param){
+        Assert.notNull(param.getWalletId(), "必填参数校验:缺少必填参数\"walletId\"");
         return rechargeService.queryListByWallet(param.getWalletId(), param.getYear(), param.getMonth());
     }
 
@@ -63,6 +67,7 @@ public class RechargeController {
     @Operation(summary = "查询充值订单详情", description = "查询充值订单详情")
     @GetMapping(value = "queryInfoById")
     public Object queryInfoById(@RequestParam("outTradeNo") String outTradeNo){
+        Assert.notNull(outTradeNo, "必填参数校验:缺少必填参数\"outTradeNo\"");
         return rechargeService.queryInfoById(outTradeNo);
     }
 }

+ 36 - 0
PaymentServer/src/main/java/com/zhongshu/payment/server/core/controller/TradeManageController.java

@@ -0,0 +1,36 @@
+package com.zhongshu.payment.server.core.controller;
+
+import com.zhongshu.payment.client.model.param.RecordSearchParam;
+import com.zhongshu.payment.server.core.service.TradeManageService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.web.PageableDefault;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author wjf
+ * @date 2024/8/2
+ */
+@Slf4j
+@RestController
+@RequestMapping("/tradeManage")
+@Tag(name = "校园端-交易管理")
+public class TradeManageController {
+
+    @Autowired
+    TradeManageService tradeManageService;
+
+    @Operation(summary = "充值/提现交易查询-分页查询", description = "充值/提现交易查询-分页查询")
+    @RequestMapping(value = {"pageTradeRecord"}, method = {RequestMethod.POST})
+    public Object pageProject(
+            @Parameter(hidden = true) @PageableDefault(page = 0, size = 10) Pageable pageable,
+            @Parameter(required = false) RecordSearchParam param) {
+        return tradeManageService.pageTradeRecord(pageable, param);
+    }
+}

+ 7 - 11
PaymentServer/src/main/java/com/zhongshu/payment/server/core/controller/TransferController.java

@@ -1,15 +1,11 @@
 package com.zhongshu.payment.server.core.controller;
 
 import com.zhongshu.payment.client.model.param.RechargeParam;
-import com.zhongshu.payment.client.model.param.TransferSearchParam;
 import com.zhongshu.payment.server.core.service.TransferService;
 import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.Parameter;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.domain.Pageable;
-import org.springframework.data.web.PageableDefault;
 import org.springframework.http.MediaType;
 import org.springframework.web.bind.annotation.*;
 
@@ -52,13 +48,13 @@ public class TransferController {
 //    public Object refuseTransfer(@RequestBody ExamineParam param){
 //        return transferService.refuseTransfer(param);
 //    }
-    @Operation(summary = "提现查询-分页查询", description = "项目列表-分页查询")
-    @RequestMapping(value = {"pageTransfer"}, method = {RequestMethod.POST})
-    public Object pageProject(
-            @Parameter(hidden = true) @PageableDefault(page = 0, size = 10) Pageable pageable,
-            @Parameter(required = false) TransferSearchParam param) {
-        return transferService.pageTransfer(pageable, param);
-    }
+//    @Operation(summary = "提现查询-分页查询", description = "项目列表-分页查询")
+//    @RequestMapping(value = {"pageTransfer"}, method = {RequestMethod.POST})
+//    public Object pageProject(
+//            @Parameter(hidden = true) @PageableDefault(page = 0, size = 10) Pageable pageable,
+//            @Parameter(required = false) RecordSearchParam param) {
+//        return transferService.pageTransfer(pageable, param);
+//    }
 
     @Operation(summary = "获取提现转账状态", description = "获取提现转账状态")
     @GetMapping(value = "getTransferState")

+ 12 - 7
PaymentServer/src/main/java/com/zhongshu/payment/server/core/controller/WalletController.java

@@ -1,11 +1,14 @@
 package com.zhongshu.payment.server.core.controller;
 
+import com.github.microservice.auth.security.annotations.ResourceAuth;
+import com.github.microservice.auth.security.type.AuthType;
 import com.zhongshu.payment.client.model.param.GetWalletParam;
 import com.zhongshu.payment.server.core.service.wallet.WalletService;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.Assert;
 import org.springframework.web.bind.annotation.*;
 
 /**
@@ -21,23 +24,25 @@ public class WalletController {
     @Autowired
     WalletService walletService;
 
-    /** 获取钱包微信授权状态 */
-    @Operation(summary = "获取钱包微信授权状态", description = "获取钱包微信授权状态")
-    @GetMapping("getWeChatAuthState")
-    public Object getWeChatAuthState(@RequestParam(name = "walletId") String walletId){
-        return walletService.getWeChatAuthState(walletId);
-    }
+//    /** 获取钱包微信授权状态 */
+//    @Operation(summary = "获取钱包微信授权状态", description = "获取钱包微信授权状态")
+//    @GetMapping("getWeChatAuthState")
+//    public Object getWeChatAuthState(@RequestParam(name = "walletId") String walletId){
+//        return walletService.getWeChatAuthState(walletId);
+//    }
 
     /** 获取(开通)当前用户钱包信息 */
     @Operation(summary = "获取(开通)当前用户钱包信息", description = "获取(开通)当前用户钱包信息")
+    @ResourceAuth(value = "user", type = AuthType.User)
     @PostMapping("getWallet")
     public Object getWalletByUser(@RequestBody GetWalletParam param){
-        return walletService.getWalletByUser(param.getAppid(), param.getWalletType(), null);
+        return walletService.getWalletByUser(param);
     }
 
     @Operation(summary = "获取可提现金额及订单数量", description = "获取可提现金额及订单数量")
     @GetMapping("getTransferTotal")
     public Object getTransferTotal(@RequestParam(name = "walletId") String walletId){
+        Assert.notNull(walletId, "必填参数校验:缺少必填参数\"walletId\"");
         return walletService.getTransferTotal(walletId);
     }
 }

+ 4 - 6
PaymentServer/src/main/java/com/zhongshu/payment/server/core/controller/test/TestController.java

@@ -8,9 +8,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
 @RestController
 @RequestMapping("test")
@@ -26,8 +24,8 @@ public class TestController {
     RechargeRecordDao rechargeRecordDao;
 
     @Operation(summary = "测试接口", description = "测试接口")
-    @RequestMapping(value = "text", method = {RequestMethod.GET})
-    public ResultContent text() {
+    @PostMapping(value = "text/{appid}")
+    public ResultContent text(@PathVariable(name = "appid", required = false) String appid) {
 //        SendMessageModel sendMessageModel = new SendMessageModel();
 //        sendMessageModel.setMessage(JsonUtil.toJson(Map.of("status", 1, "outTradeNo", 1)));
 //
@@ -35,7 +33,7 @@ public class TestController {
 //        sendMessageModel.setTopic(topic);
 //        sendMessageModel.setUserId("665fc0389083d203896d3541");
 
-
+        log.info("appid:{}",appid);
         return null;
     }
 

+ 5 - 4
PaymentServer/src/main/java/com/zhongshu/payment/server/core/controller/wxPaymentV3/WechatNotifyController.java

@@ -7,6 +7,7 @@ import jakarta.servlet.http.HttpServletRequest;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
@@ -26,9 +27,9 @@ public class WechatNotifyController {
 
 
     @Operation(summary = "支付通知回调")
-    @PostMapping(value = "payNotify", consumes = MediaType.APPLICATION_JSON_VALUE)
-    public void payNotify(HttpServletRequest request){
-        log.info("收到微信支付通知");
-        wxPayNotifyService.payNotify(request);
+    @PostMapping(value = "payNotify/{outTradeNo}", consumes = MediaType.APPLICATION_JSON_VALUE)
+    public void payNotify(HttpServletRequest request, @PathVariable(name = "outTradeNo") String outTradeNo){
+        log.info("收到微信支付通知 appid:{}", outTradeNo);
+        wxPayNotifyService.payNotify(request, outTradeNo);
     }
 }

+ 5 - 7
PaymentServer/src/main/java/com/zhongshu/payment/server/core/controller/wxPaymentV3/WechatPayV3Controller.java

@@ -4,7 +4,6 @@ import com.zhongshu.card.client.model.feign.ProjectWxPayParam;
 import com.zhongshu.card.client.model.payment.paySetting.WxPayConfigModel;
 import com.zhongshu.card.client.ret.ResultContent;
 import com.zhongshu.card.client.service.ProjectPaySettingFeignService;
-import com.zhongshu.payment.client.model.param.WxPrepayParam;
 import com.zhongshu.payment.server.core.dataConfig.WxV3PayConfig;
 import com.zhongshu.payment.server.core.service.wxPaymentV3.WxPaymentService;
 import io.swagger.v3.oas.annotations.Hidden;
@@ -14,7 +13,6 @@ import io.swagger.v3.oas.annotations.tags.Tag;
 import jline.internal.Log;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.MediaType;
 import org.springframework.web.bind.annotation.*;
 
 /**
@@ -46,11 +44,11 @@ public class WechatPayV3Controller {
         return ResultContent.buildSuccess();
     }
 
-    @Operation(summary = "充值下单(测试)")
-    @PostMapping(value = "transactions", consumes = MediaType.APPLICATION_JSON_VALUE)
-    public Object testPrepay(@RequestBody WxPrepayParam param){
-        return wxPaymentService.testPrepay(param);
-    }
+//    @Operation(summary = "充值下单(测试)")
+//    @PostMapping(value = "transactions", consumes = MediaType.APPLICATION_JSON_VALUE)
+//    public Object testPrepay(@RequestBody WxPrepayParam param){
+//        return wxPaymentService.testPrepay(param);
+//    }
 
     @Operation(summary = "获取openid")
     @GetMapping (value = "getOpenid")

+ 3 - 0
PaymentServer/src/main/java/com/zhongshu/payment/server/core/dao/RechargeRecordDao.java

@@ -14,9 +14,12 @@ public interface RechargeRecordDao extends MongoDao<RechargeRecord>, RechargeRec
 
     RechargeRecord findByOutTradeNo(String outTradeNo);
 
+    boolean existsByOutTradeNo(String outTradeNo);
+
     List<RechargeRecord> findByOutTradeNoIn(List<String> outTradeNo);
 
     RechargeRecord findTop1ById(String id);
 
     Integer countByWallet_Id(String walletId);
+
 }

+ 0 - 12
PaymentServer/src/main/java/com/zhongshu/payment/server/core/dao/TradebillDao.java

@@ -1,12 +0,0 @@
-package com.zhongshu.payment.server.core.dao;
-
-import com.github.microservice.components.data.mongo.mongo.dao.MongoDao;
-import com.zhongshu.payment.server.core.dao.extend.TradebillDaoExtend;
-import com.zhongshu.payment.server.core.domain.tradebill.Tradebill;
-
-/**
- * @author wjf
- * @date 2024/7/24
- */
-public interface TradebillDao extends MongoDao<Tradebill>, TradebillDaoExtend {
-}

+ 4 - 0
PaymentServer/src/main/java/com/zhongshu/payment/server/core/dao/WalletDao.java

@@ -18,6 +18,10 @@ public interface WalletDao extends MongoDao<Wallet> {
 
     Wallet findByShopIdAndOidAndWalletType(String shopId, String oid, WalletType walletType);
 
+    boolean existsByUserIdAndOidAndWalletType(String userId, String oid, WalletType walletType);
+
+    boolean existsByShopIdAndOidAndWalletType(String shopId, String oid, WalletType walletType);
+
     Wallet findTop1ById(String id);
 
     List<Wallet> findByIdIn(List<String> idList);

+ 6 - 2
PaymentServer/src/main/java/com/zhongshu/payment/server/core/dao/extend/RechargeRecordDaoExtend.java

@@ -1,6 +1,6 @@
 package com.zhongshu.payment.server.core.dao.extend;
 
-import com.zhongshu.payment.client.model.param.TransferSearchParam;
+import com.zhongshu.payment.client.model.param.RecordSearchParam;
 import com.zhongshu.payment.client.types.RechargeState;
 import com.zhongshu.payment.client.types.TradeType;
 import com.zhongshu.payment.server.core.domain.wallet.RechargeRecord;
@@ -18,7 +18,11 @@ public interface RechargeRecordDaoExtend {
 
     List<RechargeRecord> ListByWallet(Wallet wallet, Long startTime, Long endTime);
 
-    Page<RechargeRecord> pageTransfer(Pageable pageable, TransferSearchParam param);
+    Page<RechargeRecord> pageRecord(Pageable pageable, RecordSearchParam param);
 
     public Integer sumTotalByWalletId(String walletId, RechargeState RechargeState, TradeType tradeType, Long startTime, Long endTime);
+
+    List<RechargeRecord> listByState(RechargeState rechargeState);
+
+    List<RechargeRecord> listTimeOut(RechargeState rechargeState);
 }

+ 44 - 10
PaymentServer/src/main/java/com/zhongshu/payment/server/core/dao/impl/RechargeRecordDaoImpl.java

@@ -1,9 +1,10 @@
 package com.zhongshu.payment.server.core.dao.impl;
 
 import ch.qos.logback.core.util.StringUtil;
+import cn.hutool.core.date.DateUtil;
 import com.github.microservice.components.data.mongo.mongo.helper.DBHelper;
 import com.zhongshu.payment.client.model.TotalStatisticsModel;
-import com.zhongshu.payment.client.model.param.TransferSearchParam;
+import com.zhongshu.payment.client.model.param.RecordSearchParam;
 import com.zhongshu.payment.client.types.RechargeState;
 import com.zhongshu.payment.client.types.TradeType;
 import com.zhongshu.payment.server.core.dao.extend.RechargeRecordDaoExtend;
@@ -23,6 +24,7 @@ import org.springframework.data.mongodb.core.query.Criteria;
 import org.springframework.data.mongodb.core.query.Query;
 
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.List;
 
 /**
@@ -61,9 +63,12 @@ public class RechargeRecordDaoImpl implements RechargeRecordDaoExtend {
     }
 
     @Override
-    public Page<RechargeRecord> pageTransfer(Pageable pageable, TransferSearchParam param) {
+    public Page<RechargeRecord> pageRecord(Pageable pageable, RecordSearchParam param) {
         Criteria criteria = new Criteria();
-        //筛选条件
+        //交易类型
+        if (param.getTradeType()!=null){
+            criteria.and("tradeType").is(param.getTradeType());
+        }
         //部门
         if (StringUtil.notNullNorEmpty(param.getDepartmentId())){
             criteria.and("userInfo.department.id").is(param.getDepartmentId());
@@ -73,12 +78,13 @@ public class RechargeRecordDaoImpl implements RechargeRecordDaoExtend {
             criteria.and("userId").is(param.getUserId());
         }
         //商户
-
+        if (StringUtil.notNullNorEmpty(param.getShopId())){
+            criteria.and("wallet.shopId").is(param.getShopId());
+        }
         //支付状态
         if (param.getRechargeState()!=null){
-
+            criteria.and("rechargeState").is(param.getRechargeState());
         }
-
         //订单号
         if (StringUtil.notNullNorEmpty(param.getOutTradeNo())){
             criteria.and("outTradeNo").is(param.getOutTradeNo());
@@ -87,11 +93,12 @@ public class RechargeRecordDaoImpl implements RechargeRecordDaoExtend {
         if (StringUtil.notNullNorEmpty(param.getOutTradeNo())){
             criteria.and("userInfo.code").is(param.getUserCode());
         }
-        if (StringUtil.notNullNorEmpty(param.getOid())){
-            criteria.and("oid").is(param.getOid());
+        //项目id
+        if (StringUtil.notNullNorEmpty(param.getProjectOid())){
+            criteria.and("oid").is(param.getProjectOid());
         }
-
-        if (StringUtil.notNullNorEmpty(param.getOid())){
+        //学校id
+        if (StringUtil.notNullNorEmpty(param.getSchoolId())){
             criteria.and("schoolId").is(param.getSchoolId());
         }
         Query query = Query.query(criteria);
@@ -140,4 +147,31 @@ public class RechargeRecordDaoImpl implements RechargeRecordDaoExtend {
         return groupList.getMappedResults().get(0).getTotalAmount();
 
     }
+
+    @Override
+    public List<RechargeRecord> listByState(RechargeState rechargeState) {
+        Criteria criteria = new  Criteria();
+
+        if (rechargeState!=null){
+            criteria.and("rechargeState").is(rechargeState);
+        }
+        Query query = Query.query(criteria);
+        query.with(Sort.by(Sort.Order.asc("createTime")));
+        return mongoTemplate.find(query, RechargeRecord.class);
+    }
+
+    @Override
+    public List<RechargeRecord> listTimeOut(RechargeState rechargeState) {
+        Criteria criteria = new  Criteria();
+
+        if (rechargeState!=null){
+            criteria.and("rechargeState").is(rechargeState);
+        }
+
+        criteria.and("createTime").lte(DateUtil.offsetMinute(new Date(), -15).getTime());
+
+        Query query = Query.query(criteria);
+        query.with(Sort.by(Sort.Order.asc("createTime")));
+        return mongoTemplate.find(query, RechargeRecord.class);
+    }
 }

+ 0 - 54
PaymentServer/src/main/java/com/zhongshu/payment/server/core/domain/tradebill/Tradebill.java

@@ -1,54 +0,0 @@
-package com.zhongshu.payment.server.core.domain.tradebill;
-
-import com.github.microservice.components.data.mongo.mongo.domain.SuperEntity;
-import com.zhongshu.payment.client.types.PaymentType;
-import com.zhongshu.payment.server.core.domain.wallet.Wallet;
-import com.zhongshu.payment.server.core.domain.wechatPay.WxOrder;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-import org.springframework.data.mongodb.core.mapping.DBRef;
-import org.springframework.data.mongodb.core.mapping.Document;
-
-import java.math.BigDecimal;
-
-/**
- * 账单
- * @author wjf
- * @date 2024/7/24
- */
-@Data
-@Builder
-@Document
-@AllArgsConstructor
-@NoArgsConstructor
-public class Tradebill extends SuperEntity {
-
-    @DBRef(lazy = true)
-    @Schema(name = "关联账户")
-    private Wallet wallet;
-
-    @Schema(name = "支付类型")
-    private PaymentType paymentType;
-
-    @Schema(name = "交易金额(分)")
-    private BigDecimal amount = BigDecimal.ZERO;
-
-    @Schema(name = "订单状态")
-    private String state;
-
-    @Schema(name = "收入/支出")
-    private String s;
-
-    @Schema(name = "交易时间")
-    private Long tradeTime;
-
-    @Schema(name = "关联微信订单")
-    @DBRef(lazy = true)
-    private WxOrder wxOrder;
-
-    @Schema(name = "关联银联订单")
-    private WxOrder unionOrder;
-}

+ 24 - 0
PaymentServer/src/main/java/com/zhongshu/payment/server/core/domain/wallet/RechargeRecord.java

@@ -9,6 +9,8 @@ import com.zhongshu.payment.client.types.RechargeState;
 import com.zhongshu.payment.client.types.TradeType;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
+import org.springframework.data.mongodb.core.index.Indexed;
+import org.springframework.data.mongodb.core.mapping.DBRef;
 import org.springframework.data.mongodb.core.mapping.Document;
 
 import java.math.BigDecimal;
@@ -23,23 +25,33 @@ import java.math.BigDecimal;
 public class RechargeRecord extends SuperEntity {
 
     @Schema(name = "oid", description = "项目id")
+    @Indexed
     private String oid;
 
     @Schema(name = "userId", description = "用户id")
+    @Indexed
     private String userId;
 
     @Schema(name = "schoolId", description = "学校id")
+    @Indexed
     private String schoolId;
 
     @Schema(name = "appid", description = "appid")
+    @Indexed
     private String appid;
 
     @Schema(name = "钱包信息", description = "钱包信息")
+    @DBRef(lazy = true)
     private Wallet wallet;
 
     @Schema(name = "paymentType", description = "支付方式")
+    @Indexed
     private PaymentType paymentType;
 
+    @Schema(name = "openid", description = "微信用户openid")
+    @Indexed
+    private String openid;
+
     @Schema(name = "description", description = "商品描述(必填)")
     private String description;
 
@@ -47,21 +59,31 @@ public class RechargeRecord extends SuperEntity {
     private BigDecimal total = BigDecimal.ZERO;
 
     @Schema(name = "outTradeNo", description = "商户订单号(必填)")
+    @Indexed(unique = true)
     private String outTradeNo;
 
     @Schema(name = "rechargeState", description = "订单状态")
+    @Indexed
     private RechargeState rechargeState;
 
+    @Schema(name = "expireTime", description = "失效时间")
+    private Long expireTime;
+
+    @Schema(name = "commit", description = "是否提交到支付渠道")
+    private boolean commit;
+
     @Schema(name = "rechargeStateDesc", description = "订单状态描述")
     private String rechargeStateDesc;
 
     @Schema(name = "tradeTime", description = "交易时间")
+    @Indexed
     private Long tradeTime;
 
     @Schema(name = "prePayModel", description = "调用微信支付参数")
     private PrePayModel prePayModel;
 
     @Schema(name = "tradeType", description = "交易类型")
+    @Indexed
     private TradeType tradeType;
 
     @Schema(name = "failReason", description = "失败原因")
@@ -69,6 +91,8 @@ public class RechargeRecord extends SuperEntity {
 
     private TransferModel transferModel;
 
+    @Schema(name = "userInfo", description = "用户信息")
+    @Indexed
     private OrganizationUserModel userInfo;
 
     private String remark;

+ 12 - 0
PaymentServer/src/main/java/com/zhongshu/payment/server/core/domain/wallet/Wallet.java

@@ -1,6 +1,7 @@
 package com.zhongshu.payment.server.core.domain.wallet;
 
 import com.github.microservice.components.data.mongo.mongo.domain.SuperEntity;
+import com.zhongshu.card.client.model.org.OrganizationUserModel;
 import com.zhongshu.payment.client.types.DataState;
 import com.zhongshu.payment.client.types.WalletType;
 import io.swagger.v3.oas.annotations.media.Schema;
@@ -8,6 +9,7 @@ import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
+import org.springframework.data.mongodb.core.index.Indexed;
 import org.springframework.data.mongodb.core.mapping.Document;
 
 import java.math.BigDecimal;
@@ -26,12 +28,15 @@ import java.math.BigDecimal;
 public class Wallet extends SuperEntity {
 
     @Schema(description = "项目id")
+    @Indexed
     private String oid;
 
     @Schema(description = "用户userId")
+    @Indexed
     private String userId;
 
     @Schema(description = "商户Id")
+    @Indexed
     private String shopId;
 
     @Schema(description = "可用金额,单位:分")
@@ -41,11 +46,18 @@ public class Wallet extends SuperEntity {
     private BigDecimal totalAmount = BigDecimal.ZERO;
 
     @Schema(description = "钱包状态:是否可用")
+    @Indexed
     private DataState dataState = DataState.Enable;
 
     @Schema(description = "钱包类型")
+    @Indexed
     private WalletType walletType;
 
     @Schema(description = "openid")
+    @Indexed
     private String openid;
+
+    @Schema(name = "userInfo", description = "用户信息")
+    @Indexed
+    private OrganizationUserModel userInfo;
 }

+ 7 - 0
PaymentServer/src/main/java/com/zhongshu/payment/server/core/domain/wallet/WalletFlow.java

@@ -4,6 +4,7 @@ import com.github.microservice.components.data.mongo.mongo.domain.SuperEntity;
 import com.zhongshu.payment.client.types.TradeType;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
+import org.springframework.data.mongodb.core.index.Indexed;
 import org.springframework.data.mongodb.core.mapping.DBRef;
 import org.springframework.data.mongodb.core.mapping.Document;
 
@@ -18,20 +19,26 @@ import java.math.BigDecimal;
 public class WalletFlow extends SuperEntity {
 
     @DBRef(lazy = true)
+    @Indexed
     private Wallet wallet;
 
     @Schema(description = "学校id")
+    @Indexed
     private String schoolId;
 
     @Schema(description = "订单号")
+    @Indexed
     private String outTradeNo;
 
     @Schema(description = "金额")
+    @Indexed
     private BigDecimal total;
 
     @Schema(description = "流水类型:充值/消费/提现")
+    @Indexed
     private TradeType tradeType;
 
     @Schema(description = "附加数据")
+    @Indexed
     private Object attach;
 }

+ 0 - 68
PaymentServer/src/main/java/com/zhongshu/payment/server/core/domain/wechatPay/WxOrder.java

@@ -1,68 +0,0 @@
-package com.zhongshu.payment.server.core.domain.wechatPay;
-
-import com.github.microservice.components.data.mongo.mongo.domain.SuperEntity;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-import org.springframework.data.mongodb.core.mapping.Document;
-
-/**
- * 预支付交易单
- * @author wjf
- * @date 2024/7/22
- */
-@Data
-@Builder
-@Document
-@AllArgsConstructor
-@NoArgsConstructor
-public class WxOrder extends SuperEntity {
-
-//    @Schema(description = "项目id")
-//    private String oid;
-//
-//    @Schema(description = "用户id")
-//    private String userId;
-
-    @Schema(description = "appId")
-    private String appId;
-
-    @Schema(description = "直连商户号")
-    private String mchId;
-
-    @Schema(description = "商品描述")
-    private String description;
-
-    @Schema(description = "充值订单号")
-    private String outTradeNo;
-
-    @Schema(description = "交易结束时间(订单失效时间)")
-    private String expireTime;
-
-    @Schema(description = "附加数据")
-    private String attach;
-
-    @Schema(description = "回调通知地址")
-    private String notifyUrl;
-
-    @Schema(description = "订单优惠标记")
-    private String goodsTag;
-
-    @Schema(description = "电子发票入口开放标识")
-    private Boolean supportFapiao;
-
-    @Schema(description = "金额(分)")
-    private Integer total;
-
-    @Schema(name = "货币种类:境内支持人民币(CNY)")
-    private String currency = "CNY";
-
-    @Schema(description = "openId")
-    private String openId;
-
-    @Schema(description = "支付时间")
-    private Long payTime;
-
-}

+ 67 - 53
PaymentServer/src/main/java/com/zhongshu/payment/server/core/service/RechargeService.java

@@ -18,12 +18,13 @@ import com.zhongshu.payment.client.model.RechargeRecordModel;
 import com.zhongshu.payment.client.model.param.OrderParam;
 import com.zhongshu.payment.client.model.param.RechargeParam;
 import com.zhongshu.payment.client.ret.ResultContent;
+import com.zhongshu.payment.client.types.DataState;
 import com.zhongshu.payment.client.types.RechargeState;
 import com.zhongshu.payment.client.types.TradeType;
+import com.zhongshu.payment.client.types.WalletType;
 import com.zhongshu.payment.server.core.dao.RechargeRecordDao;
 import com.zhongshu.payment.server.core.dao.WalletDao;
 import com.zhongshu.payment.server.core.dao.WxPayConfigDao;
-import com.zhongshu.payment.server.core.dataConfig.WxV3PayConfig;
 import com.zhongshu.payment.server.core.domain.wallet.RechargeRecord;
 import com.zhongshu.payment.server.core.domain.wallet.Wallet;
 import com.zhongshu.payment.server.core.service.impl.WalletFeignServiceImpl;
@@ -78,6 +79,14 @@ public class RechargeService {
     @Autowired
     OrganizationFeignService organizationFeignService;
 
+//    private String buildOutTradeNo(){
+//
+//        if (rechargeRecordDao.existsByOutTradeNo(outTradeNo)){
+//            buildOutTradeNo();
+//        }
+//        return outTradeNo;
+//    }
+
     /** 创建充值订单 */
     public Object create(RechargeParam param){
         String userId = authHelper.getCurrentUser().getUserId();
@@ -87,17 +96,26 @@ public class RechargeService {
             return ResultContent.buildFail("用户钱包未开通");
         }
 
+        if (userWallet.getDataState().equals(DataState.Disable)){
+            return ResultContent.buildFail("钱包已停用");
+        }
+
+        if (userWallet.getWalletType().equals(WalletType.Shop)){
+            return ResultContent.buildFail("商户提现暂未开通线上充值功能");
+        }
+
         RechargeRecord rechargeRecord = new RechargeRecord();
         org.springframework.beans.BeanUtils.copyProperties(param, rechargeRecord, "total");
-        String outTradeNo = CommonUtil.UUID();
+        String outTradeNo =CommonUtil.UUID();
         rechargeRecord.setOutTradeNo(outTradeNo);
         rechargeRecord.setTotal(BigDecimal.valueOf(param.getTotal()));
         rechargeRecord.setOid(userWallet.getOid());
         rechargeRecord.setTradeType(TradeType.Charge);
         rechargeRecord.setUserId(userId);
+        rechargeRecord.setCommit(false);
 
         OrgUserDetailParam orgUserDetailParam = new OrgUserDetailParam();
-        orgUserDetailParam.setOid(userWallet.getOid());
+        orgUserDetailParam.setOid(param.getSchoolId());
         orgUserDetailParam.setUserId(userWallet.getUserId());
         com.zhongshu.card.client.ret.ResultContent<OrganizationUserModel> orgUserDetail = organizationFeignService.getOrgUserDetail(orgUserDetailParam);
         if (orgUserDetail.isFailed()){
@@ -106,6 +124,9 @@ public class RechargeService {
         rechargeRecord.setUserInfo(orgUserDetail.getContent());
         rechargeRecord.setRechargeState(RechargeState.NOTPAY);
         rechargeRecord.setWallet(userWallet);
+        long createTIme = System.currentTimeMillis();
+        rechargeRecord.setCreateTime(createTIme);
+        rechargeRecord.setExpireTime(createTIme + 15*60*1000);
         RechargeRecord record = rechargeRecordDao.save(rechargeRecord);
         RechargeRecordModel model = toModel(record);
         return ResultContent.buildSuccess(model);
@@ -129,58 +150,55 @@ public class RechargeService {
         if (record==null){
             return ResultContent.buildFail("充值订单:"+param.getOutTradeNo()+"不存在");
         }
-        Wallet userWallet = walletDao.findTop1ById(record.getWallet().getId());
-        String openId;
-        if (StringUtil.notNullNorEmpty(param.getJscode())){
-            openId = getOpenId(param.getJscode());
-        }else {
-            openId = userWallet.getOpenid();
-        }
-        if (StringUtil.isNullOrEmpty(openId)){
-            return ResultContent.buildFail("获取openid失败");
+
+        if (StringUtil.isNullOrEmpty(param.getOpenid())){
+            return ResultContent.buildFail("缺少用户授权参数");
         }
 
-        userWallet.setOpenid(openId);
-        walletDao.save(userWallet);
+        ProjectWxPayParam wxPayParam = new ProjectWxPayParam();
+        wxPayParam.setAppId(record.getAppid());
+        com.zhongshu.card.client.ret.ResultContent<WxPayConfigModel> paySetResult = paySettingFeignService.getProjectWxPayConfig(wxPayParam);
+        if (paySetResult.isFailed()){
+            return ResultContent.buildFail("获取微信支付配置失败");
+        }
 
-        //判断微信支付配置
-//        WxPayConfig config = wxPayConfigDao.findByOid(record.getOid());
         //调用微信支付--下单接口
         PrepayRequest request = new PrepayRequest();
-//        request.setMchid(config.getMchId());
-//        request.setAppid(config.getAppid());
-//        request.setNotifyUrl(config.getNotifyUrl());
         Amount amount = new Amount();
         amount.setTotal(record.getTotal().intValue());
         request.setAmount(amount);
         request.setDescription(record.getDescription());
         request.setOutTradeNo(param.getOutTradeNo());
         //设置交易失效时间,15分钟
-        request.setTimeExpire(DateUtils.paresTime(System.currentTimeMillis() + 15*60*1000, DateUtils.patternWx));
+        request.setTimeExpire(DateUtils.paresTime(record.getExpireTime(), DateUtils.patternWx));
         Payer payer = new Payer();
-        payer.setOpenid(openId);
+        payer.setOpenid(param.getOpenid());
         request.setPayer(payer);
 
-        ProjectWxPayParam wxPayParam = new ProjectWxPayParam();
-        wxPayParam.setAppId(record.getAppid());
-        com.zhongshu.card.client.ret.ResultContent<WxPayConfigModel> paySetResult = paySettingFeignService.getProjectWxPayConfig(wxPayParam);
-        if (paySetResult.isFailed()){
-            return ResultContent.buildFail("获取微信支付配置失败");
-        }
         ResultContent<PrePayModel> prepayResult = wxPaymentService.prepay(request, paySetResult.getContent());
         if (prepayResult.isFailed()){
             return prepayResult;
         }
+        record.setOpenid(param.getOpenid());
         record.setPrePayModel(prepayResult.getContent());
-        record.setRechargeState(RechargeState.RECHARGING);
+        record.setRechargeState(RechargeState.NOTPAY);
+        record.setCommit(true);
         rechargeRecordDao.save(record);
         return prepayResult;
     }
 
     /** 查询订单支付状态 */
     public Object queryTradeState(String outTradeNo){
+        RechargeRecord record = rechargeRecordDao.findByOutTradeNo(outTradeNo);
+        if (record==null){
+            return ResultContent.buildFail("充值订单:"+outTradeNo+"不存在");
+        }
+        if (record.getRechargeState().equals(RechargeState.NOTPAY) && !record.isCommit()){
+            return ResultContent.buildSuccess(RechargeState.NOTPAY.name());
+        }
+
         ProjectWxPayParam wxPayParam = new ProjectWxPayParam();
-        wxPayParam.setAppId(WxV3PayConfig.APP_ID);
+        wxPayParam.setAppId(record.getAppid());
         com.zhongshu.card.client.ret.ResultContent<WxPayConfigModel> paySetResult = paySettingFeignService.getProjectWxPayConfig(wxPayParam);
         if (paySetResult.isFailed()){
             return ResultContent.buildFail("获取微信支付配置失败");
@@ -192,48 +210,44 @@ public class RechargeService {
         return queryResult;
     }
 
-    /** 得到支付结果后处理 */
-    private void update(Transaction transaction){
-        RechargeRecord record = rechargeRecordDao.findByOutTradeNo(transaction.getOutTradeNo());
-        if (record == null){
-            log.error("微信支付通知回调错误:找不到订单outTradeNo:{}", transaction.getOutTradeNo());
-            return;
+
+    /** 关闭充值订单 */
+    public Object close(String outTradeNo){
+        RechargeRecord record = rechargeRecordDao.findByOutTradeNo(outTradeNo);
+        if (record==null){
+            return ResultContent.buildFail("充值订单:"+outTradeNo+"不存在");
         }
-        if (transaction.getTradeState().equals(Transaction.TradeStateEnum.SUCCESS)){
-            //更新订单状态
-            record.setRechargeState(RechargeState.SUCCESS);
-            record.setTradeTime(DateUtils.timeToLong(transaction.getSuccessTime(), DateUtils.patternWx));
-            rechargeRecordDao.save(record);
-            //todo 账户可用余额 增加
-        }else {
-            record.setRechargeState(RechargeState.valueOf(transaction.getTradeState().name()));
+
+        if (record.getRechargeState().equals(RechargeState.NOTPAY)){
+            record.setRechargeState(RechargeState.CLOSED);
             rechargeRecordDao.save(record);
+            return ResultContent.buildSuccess();
         }
-    }
 
-    /** 关闭充值订单 */
-    public Object close(String outTradeNo){
         ProjectWxPayParam wxPayParam = new ProjectWxPayParam();
-        wxPayParam.setAppId(WxV3PayConfig.APP_ID);
+        wxPayParam.setAppId(record.getAppid());
         com.zhongshu.card.client.ret.ResultContent<WxPayConfigModel> paySetResult = paySettingFeignService.getProjectWxPayConfig(wxPayParam);
         if (paySetResult.isFailed()){
             return ResultContent.buildFail("获取微信支付配置失败");
         }
+        record.setRechargeState(RechargeState.CLOSED);
+        rechargeRecordDao.save(record);
+        return wxPaymentService.closeOrder(outTradeNo, paySetResult.getContent());
+    }
+
+    public Object closeNoPay(String outTradeNo){
         RechargeRecord record = rechargeRecordDao.findByOutTradeNo(outTradeNo);
         if (record==null){
             return ResultContent.buildFail("充值订单:"+outTradeNo+"不存在");
         }
-        if (record.getRechargeState().equals(RechargeState.NOTPAY)){
-            record.setRechargeState(RechargeState.CLOSED);
-            rechargeRecordDao.save(record);
-            return ResultContent.buildSuccess(toModel(record));
+        if (!record.getRechargeState().equals(RechargeState.NOTPAY)){
+            return ResultContent.buildSuccess("订单状态不是未支付");
         }
         record.setRechargeState(RechargeState.CLOSED);
         rechargeRecordDao.save(record);
-        return wxPaymentService.closeOrder(outTradeNo, paySetResult.getContent());
+        return ResultContent.buildSuccess();
     }
 
-
     /** 查询充值订单列表 */
     public Object queryListByWallet(String walletId, Integer year, Integer month){
 

+ 57 - 0
PaymentServer/src/main/java/com/zhongshu/payment/server/core/service/TradeManageService.java

@@ -0,0 +1,57 @@
+package com.zhongshu.payment.server.core.service;
+
+import com.github.microservice.components.data.base.util.PageEntityUtil;
+import com.zhongshu.payment.client.model.RechargeRecordModel;
+import com.zhongshu.payment.client.model.WalletModel;
+import com.zhongshu.payment.client.model.param.RecordSearchParam;
+import com.zhongshu.payment.client.ret.ResultContent;
+import com.zhongshu.payment.server.core.dao.RechargeRecordDao;
+import com.zhongshu.payment.server.core.domain.wallet.RechargeRecord;
+import com.zhongshu.payment.server.core.domain.wallet.Wallet;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.stereotype.Service;
+
+/**
+ * 校园端-交易管理
+ * @author wjf
+ * @date 2024/8/2
+ */
+
+@Slf4j
+@Service
+public class TradeManageService {
+
+    @Autowired
+    RechargeRecordDao rechargeRecordDao;
+
+    public Object pageTradeRecord(Pageable pageable, RecordSearchParam param){
+        Page<RechargeRecord> page = rechargeRecordDao.pageRecord(pageable, param);
+        Page<RechargeRecordModel> pageModel = PageEntityUtil.concurrent2PageModel(page, this::toModel);
+        return ResultContent.buildContent(pageModel);
+    }
+
+//    public Object pageWallet(Pageable pageable, )
+
+    public RechargeRecordModel toModel(RechargeRecord record){
+        RechargeRecordModel model = new RechargeRecordModel();
+        if (record!=null){
+            BeanUtils.copyProperties(record, model, "total", "wallet", "openid", "prePayModel");
+            model.setTotal(record.getTotal().intValue());
+            model.setUserInfo(record.getUserInfo());
+            model.setWalletModel(toWalletModel(record.getWallet()));
+        }
+        return model;
+    }
+
+    private WalletModel toWalletModel(Wallet wallet){
+        WalletModel model = new WalletModel();
+        if (wallet!=null){
+            com.zhongshu.payment.server.core.utils.BeanUtils.copyPropertiesWithoutNull(wallet, model);
+        }
+        return model;
+    }
+}

+ 18 - 14
PaymentServer/src/main/java/com/zhongshu/payment/server/core/service/TransferService.java

@@ -1,7 +1,6 @@
 package com.zhongshu.payment.server.core.service;
 
 import com.github.microservice.auth.security.helper.AuthHelper;
-import com.github.microservice.components.data.base.util.PageEntityUtil;
 import com.wechat.pay.java.service.transferbatch.model.*;
 import com.zhongshu.card.client.model.feign.ProjectWxPayParam;
 import com.zhongshu.card.client.model.org.OrgUserDetailParam;
@@ -14,10 +13,11 @@ import com.zhongshu.payment.client.model.TransferModel;
 import com.zhongshu.payment.client.model.param.AmountUpdateParam;
 import com.zhongshu.payment.client.model.param.ExamineParam;
 import com.zhongshu.payment.client.model.param.RechargeParam;
-import com.zhongshu.payment.client.model.param.TransferSearchParam;
 import com.zhongshu.payment.client.ret.ResultContent;
+import com.zhongshu.payment.client.types.DataState;
 import com.zhongshu.payment.client.types.RechargeState;
 import com.zhongshu.payment.client.types.TradeType;
+import com.zhongshu.payment.client.types.WalletType;
 import com.zhongshu.payment.server.core.dao.RechargeRecordDao;
 import com.zhongshu.payment.server.core.dao.WalletDao;
 import com.zhongshu.payment.server.core.domain.wallet.RechargeRecord;
@@ -28,8 +28,6 @@ import com.zhongshu.payment.server.core.utils.CommonUtil;
 import io.netty.util.internal.StringUtil;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.Pageable;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -74,6 +72,14 @@ public class TransferService {
             return ResultContent.buildFail("用户钱包未开通");
         }
 
+        if (userWallet.getDataState().equals(DataState.Disable)){
+            return ResultContent.buildFail("钱包已停用");
+        }
+
+        if (userWallet.getWalletType().equals(WalletType.Shop)){
+            return ResultContent.buildFail("商户提现暂未开通线上提现功能");
+        }
+
         //判断微信支付配置
         ProjectWxPayParam wxPayParam = new ProjectWxPayParam();
         wxPayParam.setAppId(param.getAppid());
@@ -84,7 +90,7 @@ public class TransferService {
 
         //设置人员信息
         OrgUserDetailParam orgUserDetailParam = new OrgUserDetailParam();
-        orgUserDetailParam.setOid(userWallet.getOid());
+        orgUserDetailParam.setOid(param.getSchoolId());
         orgUserDetailParam.setUserId(userWallet.getUserId());
         com.zhongshu.card.client.ret.ResultContent<OrganizationUserModel> orgUserDetail = organizationFeignService.getOrgUserDetail(orgUserDetailParam);
         if (orgUserDetail.isFailed()){
@@ -111,10 +117,11 @@ public class TransferService {
         request.setBatchRemark("余额提现");
         request.setTotalAmount(rechargeRecord.getTotal().longValue());
         request.setTotalNum(1);
+        request.setBatchName("余额提现");
 
         TransferDetailInput transferDetailInput = new TransferDetailInput();
         //todo openid
-        transferDetailInput.setOpenid(userWallet.getOpenid());
+        transferDetailInput.setOpenid(param.getOpenid());
         transferDetailInput.setOutDetailNo(rechargeRecord.getOutTradeNo());
         transferDetailInput.setTransferAmount(rechargeRecord.getTotal().longValue());
         transferDetailInput.setTransferRemark("余额提现");
@@ -127,7 +134,7 @@ public class TransferService {
         }
         request.setTransferDetailList(List.of(transferDetailInput));
         //todo 设置转账场景id
-        request.setTransferSceneId("");
+        request.setTransferSceneId("1001");
 
         InitiateBatchTransferResponse initiateBatchTransferResponse = wxTransferBatchService.InitiateBatchTransferResponse(request, paySetResult.getContent());
         TransferModel transferModel = new TransferModel();
@@ -196,6 +203,7 @@ public class TransferService {
         rechargeRecord.setRechargeState(RechargeState.TakeReview);
         rechargeRecord.setWallet(userWallet);
         rechargeRecord.setUserId(userId);
+        rechargeRecord.setOpenid(param.getOpenid());
 
         rechargeRecord.setUserInfo(orgUserDetail.getContent());
 
@@ -240,7 +248,7 @@ public class TransferService {
         request.setTotalNum(1);
 
         TransferDetailInput transferDetailInput = new TransferDetailInput();
-        transferDetailInput.setOpenid(userWallet.getOpenid());
+        transferDetailInput.setOpenid(record.getOpenid());
         transferDetailInput.setOutDetailNo(record.getOutTradeNo());
         transferDetailInput.setTransferAmount(record.getTotal().longValue());
         transferDetailInput.setTransferRemark(param.getRemark());
@@ -260,7 +268,7 @@ public class TransferService {
         BeanUtils.copyProperties(initiateBatchTransferResponse, transferModel);
         record.setTransferModel(transferModel);
         if (initiateBatchTransferResponse.getBatchStatus().equals("ACCEPTED")){
-            record.setRechargeState(RechargeState.RECHARGING);
+//            record.setRechargeState(RechargeState.RECHARGING);
         }
         if (initiateBatchTransferResponse.getBatchStatus().equals("PROCESSING")){
             record.setRechargeState(RechargeState.Taking);
@@ -295,11 +303,7 @@ public class TransferService {
         return ResultContent.buildSuccess(toModel(record));
     }
 
-    public Object pageTransfer(Pageable pageable, TransferSearchParam param){
-        Page<RechargeRecord> page = rechargeRecordDao.pageTransfer(pageable, param);
-        Page<RechargeRecordModel> pageModel = PageEntityUtil.concurrent2PageModel(page, this::toModel);
-        return ResultContent.buildContent(pageModel);
-    }
+
 
     @Transactional
     public Object getTransferState(String outTradeNo){

+ 32 - 37
PaymentServer/src/main/java/com/zhongshu/payment/server/core/service/wallet/WalletService.java

@@ -2,17 +2,14 @@ package com.zhongshu.payment.server.core.service.wallet;
 
 import ch.qos.logback.core.util.StringUtil;
 import com.github.microservice.auth.security.helper.AuthHelper;
-import com.github.microservice.auth.security.type.AuthType;
 import com.zhongshu.card.client.model.feign.ProjectWxPayParam;
-import com.zhongshu.card.client.model.org.OrgUserDetailParam;
-import com.zhongshu.card.client.model.org.OrganizationUserModel;
 import com.zhongshu.card.client.model.payment.paySetting.WxPayConfigModel;
 import com.zhongshu.card.client.service.OrganizationFeignService;
 import com.zhongshu.card.client.service.ProjectPaySettingFeignService;
 import com.zhongshu.payment.client.model.WalletModel;
 import com.zhongshu.payment.client.model.WalletOrderModel;
+import com.zhongshu.payment.client.model.param.GetWalletParam;
 import com.zhongshu.payment.client.ret.ResultContent;
-import com.zhongshu.payment.client.ret.ResultState;
 import com.zhongshu.payment.client.types.DataState;
 import com.zhongshu.payment.client.types.WalletType;
 import com.zhongshu.payment.server.core.dao.RechargeRecordDao;
@@ -50,60 +47,58 @@ public class WalletService {
     RechargeRecordDao rechargeRecordDao;
 
 
-    /** 获取钱包微信授权状态 */
-    public Object getWeChatAuthState(String walletId){
-        Wallet wallet = walletDao.findTop1ById(walletId);
-        if (wallet==null){
-            return ResultContent.buildFail("钱包未开通");
-        }
-        if (StringUtil.isNullOrEmpty(wallet.getOpenid())){
-            return ResultContent.buildContent(ResultState.NOT_WECHAT_AUTH);
-        }
-        return ResultContent.buildSuccess();
-    }
+//    /** 获取钱包微信授权状态 */
+//    public Object getWeChatAuthState(String walletId){
+//        Wallet wallet = walletDao.findTop1ById(walletId);
+//        if (wallet==null){
+//            return ResultContent.buildFail("钱包未开通");
+//        }
+//        if (StringUtil.isNullOrEmpty(wallet.getOpenid())){
+//            return ResultContent.buildContent(ResultState.NOT_WECHAT_AUTH);
+//        }
+//        return ResultContent.buildSuccess();
+//    }
 
     /** 查询用户钱包 */
-    public Object getWalletByUser(String appid, WalletType walletType, String userId){
+    public Object getWalletByUser(GetWalletParam param){
+        String userId = authHelper.getCurrentUser().getUserId();
 
-        ProjectWxPayParam param = new ProjectWxPayParam();
-        param.setAppId(appid);
-        com.zhongshu.card.client.ret.ResultContent<WxPayConfigModel> payConfigResult = paySettingFeignService.getProjectWxPayConfig(param);
+        ProjectWxPayParam projectWxPayParam = new ProjectWxPayParam();
+        projectWxPayParam.setAppId(param.getAppid());
+        com.zhongshu.card.client.ret.ResultContent<WxPayConfigModel> payConfigResult = paySettingFeignService.getProjectWxPayConfig(projectWxPayParam);
         if (payConfigResult.isFailed()){
             return ResultContent.buildFail("获取支付配置信息失败");
         }
+
         String oid = payConfigResult.getContent().getProjectOid();
 
-        if (StringUtil.isNullOrEmpty(userId)){
-            userId = authHelper.getCurrentUser().getUserId();
+        if (param.getWalletType().equals(WalletType.User) && walletDao.existsByUserIdAndOidAndWalletType(userId, oid, WalletType.User)){
+            return ResultContent.buildContent(toModel(walletDao.findByUserIdAndOidAndWalletType(userId, oid, param.getWalletType())));
         }
-
-        Wallet wallet = walletDao.findByUserIdAndOid(userId, oid);
-        if (wallet!=null){
-            return ResultContent.buildSuccess(toModel(wallet));
+        if (param.getWalletType().equals(WalletType.Shop) && walletDao.existsByShopIdAndOidAndWalletType(param.getShopId(), oid, WalletType.Shop)){
+            if (StringUtil.isNullOrEmpty(param.getShopId())){
+                return ResultContent.buildFail("钱包类型为Shop时,shopId不能为空");
+            }
+            return ResultContent.buildContent(toModel(walletDao.findByShopIdAndOidAndWalletType(param.getShopId(), oid, param.getWalletType())));
         }
-        wallet = new Wallet();
+
+        Wallet wallet = new Wallet();
         wallet.setOid(oid);
         wallet.setUserId(userId);
         wallet.setAmount(BigDecimal.ZERO);
         wallet.setAmount(BigDecimal.ZERO);
         wallet.setDataState(DataState.Enable);
-
-        OrgUserDetailParam orgUserDetailParam = new OrgUserDetailParam();
-        orgUserDetailParam.setOid(oid);
-        orgUserDetailParam.setUserId(userId);
-        com.zhongshu.card.client.ret.ResultContent<OrganizationUserModel> orgUserDetail = organizationFeignService.getOrgUserDetail(orgUserDetailParam);
-        if (orgUserDetail.isFailed()){
-            return ResultContent.buildFail("获取用户信息失败");
-        }
-        if (orgUserDetail.getContent().getAuthType().equals(AuthType.Shop)){
-            wallet.setWalletType(walletType);
-        }
+        wallet.setShopId(param.getShopId());
+        wallet.setWalletType(param.getWalletType());
         walletDao.save(wallet);
         return ResultContent.buildSuccess(toModel(wallet));
     }
 
     public Object getTransferTotal(String walletId){
         Wallet wallet = walletDao.findTop1ById(walletId);
+        if (wallet==null){
+            return ResultContent.buildFail("钱包未开通");
+        }
         WalletOrderModel walletOrderModel = new WalletOrderModel();
         walletOrderModel.setTotal(wallet.getAmount().intValue());
 

+ 29 - 22
PaymentServer/src/main/java/com/zhongshu/payment/server/core/service/wxPaymentV3/WxPayNotifyService.java

@@ -6,13 +6,15 @@ import com.wechat.pay.java.core.notification.NotificationConfig;
 import com.wechat.pay.java.core.notification.NotificationParser;
 import com.wechat.pay.java.core.notification.RequestParam;
 import com.wechat.pay.java.service.payments.model.Transaction;
+import com.zhongshu.card.client.model.feign.ProjectWxPayParam;
 import com.zhongshu.card.client.model.mqtt.SendMessageModel;
+import com.zhongshu.card.client.model.payment.paySetting.WxPayConfigModel;
 import com.zhongshu.card.client.service.MqttFeignService;
+import com.zhongshu.card.client.service.ProjectPaySettingFeignService;
 import com.zhongshu.payment.client.model.param.AmountUpdateParam;
 import com.zhongshu.payment.client.ret.ResultContent;
 import com.zhongshu.payment.client.types.RechargeState;
 import com.zhongshu.payment.server.core.dao.RechargeRecordDao;
-import com.zhongshu.payment.server.core.dataConfig.WxV3PayConfig;
 import com.zhongshu.payment.server.core.domain.wallet.RechargeRecord;
 import com.zhongshu.payment.server.core.service.impl.WalletFeignServiceImpl;
 import com.zhongshu.payment.server.core.utils.DateUtils;
@@ -20,6 +22,7 @@ import jakarta.servlet.ServletInputStream;
 import jakarta.servlet.http.HttpServletRequest;
 import jline.internal.Log;
 import lombok.extern.slf4j.Slf4j;
+import org.jetbrains.annotations.NotNull;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -45,9 +48,14 @@ public class WxPayNotifyService {
 
     @Autowired
     MqttFeignService mqttFeignService;
+    
+    @Autowired
+    ProjectPaySettingFeignService paySettingFeignService;
 
-    public void payNotify(HttpServletRequest request) {
+    public void payNotify(HttpServletRequest request, String outTradeNo) {
         try {
+            //获取微信配置
+            WxPayConfigModel configModel = getWxPayConfigModelResultContent(outTradeNo);
             //读取请求体的信息
             ServletInputStream inputStream = request.getInputStream();
             StringBuffer stringBuffer = new StringBuffer();
@@ -66,11 +74,16 @@ public class WxPayNotifyService {
             // 如果已经初始化了 RSAAutoCertificateConfig,可直接使用
             // 没有的话,则构造一个
 //            log.error(JSON.toJSONString(wxPayV3Bean));
+            String privateKeyPath = configModel.getPrivateKeyPath();
+            if (configModel.getPrivateKeyType().equals("local")){
+                privateKeyPath = Thread.currentThread().getContextClassLoader().getResource("").getPath() + configModel.getPrivateKeyPath();
+            }
+
             NotificationConfig config = new RSAAutoCertificateConfig.Builder()
-                    .merchantId(WxV3PayConfig.Mch_ID)
-                    .privateKeyFromPath(WxV3PayConfig.privateKeyPath)
-                    .merchantSerialNumber(WxV3PayConfig.mchSerialNo)
-                    .apiV3Key(WxV3PayConfig.apiV3Key)
+                    .merchantId(configModel.getMchId())
+                    .privateKeyFromPath(privateKeyPath)
+                    .merchantSerialNumber(configModel.getMchSerialNo())
+                    .apiV3Key(configModel.getApiV3Key())
                     .build();
             // 初始化 NotificationParser
             NotificationParser parser = new NotificationParser(config);
@@ -114,7 +127,6 @@ public class WxPayNotifyService {
                 record.setRechargeState(RechargeState.valueOf(transaction.getTradeState().name()));
                 rechargeRecordDao.save(record);
             }
-            Log.info("微信支付异常:{}", transaction.getTradeState());
             SendMessageModel sendMessageModel = new SendMessageModel();
             sendMessageModel.setMessage(JsonUtil.toJson(Map.of("status", transaction.getTradeState().name(), "outTradeNo", transaction.getOutTradeNo())));
             String userId = record.getUserId();
@@ -129,21 +141,16 @@ public class WxPayNotifyService {
         }
     }
 
-    public void update(Transaction transaction){
-        RechargeRecord record = rechargeRecordDao.findByOutTradeNo(transaction.getOutTradeNo());
-        if (record == null){
-            log.error("微信支付通知回调错误:找不到订单outTradeNo:{}", transaction.getOutTradeNo());
-            return;
-        }
-        if (transaction.getTradeState().equals(Transaction.TradeStateEnum.SUCCESS)){
-            //更新订单状态
-            record.setRechargeState(RechargeState.SUCCESS);
-            record.setTradeTime(DateUtils.timeToLong(transaction.getSuccessTime(), DateUtils.patternWx));
-            rechargeRecordDao.save(record);
-            //todo 账户可用余额 增加
-        }else {
-            record.setRechargeState(RechargeState.valueOf(transaction.getTradeState().name()));
-            rechargeRecordDao.save(record);
+    @NotNull
+    private WxPayConfigModel getWxPayConfigModelResultContent(String outTradeNo) {
+        RechargeRecord recordByOutTradeNo = rechargeRecordDao.findByOutTradeNo(outTradeNo);
+        ProjectWxPayParam wxPayParam = new ProjectWxPayParam();
+        wxPayParam.setAppId(recordByOutTradeNo.getAppid());
+        com.zhongshu.card.client.ret.ResultContent<WxPayConfigModel> paySetResult = paySettingFeignService.getProjectWxPayConfig(wxPayParam);
+        if (paySetResult.isFailed()){
+            log.error("获取微信支付配置失败 \"outTradeNo\": {}", outTradeNo);
         }
+        return paySetResult.getContent();
     }
+
 }

+ 75 - 65
PaymentServer/src/main/java/com/zhongshu/payment/server/core/service/wxPaymentV3/WxPaymentService.java

@@ -12,9 +12,7 @@ import com.wechat.pay.java.service.payments.model.Transaction;
 import com.zhongshu.card.client.model.payment.paySetting.WxPayConfigModel;
 import com.zhongshu.card.client.model.wechat.MiniAppUserInfoVo;
 import com.zhongshu.payment.client.model.PrePayModel;
-import com.zhongshu.payment.client.model.param.WxPrepayParam;
 import com.zhongshu.payment.client.ret.ResultContent;
-import com.zhongshu.payment.server.core.dataConfig.WxV3PayConfig;
 import com.zhongshu.payment.server.core.service.base.SuperService;
 import com.zhongshu.payment.server.core.utils.wx.WechatCUtil;
 import io.netty.util.internal.StringUtil;
@@ -75,60 +73,60 @@ public class WxPaymentService extends SuperService {
         return miniAppUserInfo.getOpenid();
     }
 
-    public ResultContent<PrePayModel> testPrepay(WxPrepayParam param){
-
-
-        // 初始化商户配置
-        Config config = RSAAutoCertificateConfig(WxV3PayConfig.Mch_ID, WxV3PayConfig.privateKeyPath, WxV3PayConfig.mchSerialNo, WxV3PayConfig.apiV3Key);
-        // 初始化服务
-        service = new com.wechat.pay.java.service.payments.jsapi.JsapiService.Builder().config(config).build();
-        // ... 调用接口
-        try {
-            // 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
-            PrepayRequest request = new PrepayRequest();
-            request.setAppid("wx92ae04fb0f325887");
-            request.setMchid("1680033836");
-            request.setDescription("充值服务");
-            request.setOutTradeNo("A111112");
-            request.setNotifyUrl("https://api.dev.qk.zonelife.cn/paymentserver-wjf/wechat/v3/notify/payNotify");
-            Amount amount = new Amount();
-            amount.setTotal(1);
-            amount.setCurrency("CNY");
-            request.setAmount(amount);
-            Payer payer = new Payer();
-            payer.setOpenid("oSd8L7Wlucyn7a8g3SZCOeLrSUKY");
-            request.setPayer(payer);
-            // 调用接口
-            PrepayResponse response = service.prepay(request);
-
-            PrePayModel prePayModel = new PrePayModel();
-            prePayModel.setNonceStr(NonceUtil.createNonce(10));
-            prePayModel.setPackAge("prepay_id=" + response.getPrepayId());
-            prePayModel.setSignType("RSA");
-            long timeStamp = System.currentTimeMillis() / 1000;
-            prePayModel.setTimeStamp(Long.toString(timeStamp));
-
-            String sign = buildMessage(WxV3PayConfig.APP_ID, timeStamp, prePayModel.getNonceStr(), prePayModel.getPackAge());
-            String signature = sign(WxV3PayConfig.privateKeyPath, sign.getBytes("utf-8"));
-            prePayModel.setPaySign(signature);
-            return ResultContent.buildContent(prePayModel);
-        } catch (HttpException e) { // 发送HTTP请求失败
-            // 调用e.getHttpRequest()获取请求打印日志或上报监控,更多方法见HttpException定义
-            log.info("请求失败1:{}", e.getHttpRequest());
-            return ResultContent.buildFail("发送HTTP请求失败");
-        } catch (ServiceException e) { // 服务返回状态小于200或大于等于300,例如500
-            // 调用e.getResponseBody()获取返回体打印日志或上报监控,更多方法见ServiceException定义
-            log.info("请求失败2:{}", e.getResponseBody());
-            return ResultContent.buildFail(e.getErrorMessage());
-        } catch (MalformedMessageException e) { // 服务返回成功,返回体类型不合法,或者解析返回体失败
-            // 调用e.getMessage()获取信息打印日志或上报监控,更多方法见MalformedMessageException定义
-            log.info("请求失败3:{}", e.getMessage());
-            return ResultContent.buildFail("服务返回成功,返回体类型不合法,或者解析返回体失败");
-        } catch (UnsupportedEncodingException e) {
-            log.info("请求失败4:{}", e.getMessage());
-            return ResultContent.buildFail("编码错误");
-        }
-    }
+//    public ResultContent<PrePayModel> testPrepay(WxPrepayParam param){
+//
+//
+//        // 初始化商户配置
+//        Config config = RSAAutoCertificateConfig(WxV3PayConfig.Mch_ID, WxV3PayConfig.privateKeyPath, WxV3PayConfig.mchSerialNo, WxV3PayConfig.apiV3Key);
+//        // 初始化服务
+//        service = new com.wechat.pay.java.service.payments.jsapi.JsapiService.Builder().config(config).build();
+//        // ... 调用接口
+//        try {
+//            // 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
+//            PrepayRequest request = new PrepayRequest();
+//            request.setAppid("wx92ae04fb0f325887");
+//            request.setMchid("1680033836");
+//            request.setDescription("充值服务");
+//            request.setOutTradeNo("A111112");
+//            request.setNotifyUrl("https://api.dev.qk.zonelife.cn/paymentserver-wjf/wechat/v3/notify/payNotify");
+//            Amount amount = new Amount();
+//            amount.setTotal(1);
+//            amount.setCurrency("CNY");
+//            request.setAmount(amount);
+//            Payer payer = new Payer();
+//            payer.setOpenid("oSd8L7Wlucyn7a8g3SZCOeLrSUKY");
+//            request.setPayer(payer);
+//            // 调用接口
+//            PrepayResponse response = service.prepay(request);
+//
+//            PrePayModel prePayModel = new PrePayModel();
+//            prePayModel.setNonceStr(NonceUtil.createNonce(10));
+//            prePayModel.setPackAge("prepay_id=" + response.getPrepayId());
+//            prePayModel.setSignType("RSA");
+//            long timeStamp = System.currentTimeMillis() / 1000;
+//            prePayModel.setTimeStamp(Long.toString(timeStamp));
+//
+//            String sign = buildMessage(WxV3PayConfig.APP_ID, timeStamp, prePayModel.getNonceStr(), prePayModel.getPackAge());
+//            String signature = sign(WxV3PayConfig.privateKeyPath, sign.getBytes("utf-8"));
+//            prePayModel.setPaySign(signature);
+//            return ResultContent.buildContent(prePayModel);
+//        } catch (HttpException e) { // 发送HTTP请求失败
+//            // 调用e.getHttpRequest()获取请求打印日志或上报监控,更多方法见HttpException定义
+//            log.info("请求失败1:{}", e.getHttpRequest());
+//            return ResultContent.buildFail("发送HTTP请求失败");
+//        } catch (ServiceException e) { // 服务返回状态小于200或大于等于300,例如500
+//            // 调用e.getResponseBody()获取返回体打印日志或上报监控,更多方法见ServiceException定义
+//            log.info("请求失败2:{}", e.getResponseBody());
+//            return ResultContent.buildFail(e.getErrorMessage());
+//        } catch (MalformedMessageException e) { // 服务返回成功,返回体类型不合法,或者解析返回体失败
+//            // 调用e.getMessage()获取信息打印日志或上报监控,更多方法见MalformedMessageException定义
+//            log.info("请求失败3:{}", e.getMessage());
+//            return ResultContent.buildFail("服务返回成功,返回体类型不合法,或者解析返回体失败");
+//        } catch (UnsupportedEncodingException e) {
+//            log.info("请求失败4:{}", e.getMessage());
+//            return ResultContent.buildFail("编码错误");
+//        }
+//    }
 
     /** @Author wjf
      * @Description //TODO 预支付下单
@@ -138,7 +136,10 @@ public class WxPaymentService extends SuperService {
     **/
     public ResultContent<PrePayModel> prepay(PrepayRequest request, WxPayConfigModel configModel){
 
-        String privateKeyPath = Thread.currentThread().getContextClassLoader().getResource("").getPath() + configModel.getPrivateKeyPath();
+        String privateKeyPath = configModel.getPrivateKeyPath();
+        if (configModel.getPrivateKeyType().equals("local")){
+            privateKeyPath = Thread.currentThread().getContextClassLoader().getResource("").getPath() + configModel.getPrivateKeyPath();
+        }
 
         // 初始化商户配置
         Config config = RSAAutoCertificateConfig(configModel.getMchId(), privateKeyPath, configModel.getMchSerialNo(), configModel.getApiV3Key());
@@ -149,7 +150,7 @@ public class WxPaymentService extends SuperService {
             // 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
             request.setAppid(configModel.getAppId());
             request.setMchid(configModel.getMchId());
-            request.setNotifyUrl("https://api.dev.qk.zonelife.cn/paymentserver/wechat/v3/notify/payNotify");
+            request.setNotifyUrl("https://api.dev.qk.zonelife.cn/paymentserver/wechat/v3/notify/payNotify/" + request.getOutTradeNo());
 //            request.setNotifyUrl(configModel.getNotifyUrl());
             // 调用接口
             PrepayResponse response = service.prepay(request);
@@ -161,7 +162,7 @@ public class WxPaymentService extends SuperService {
             long timeStamp = System.currentTimeMillis() / 1000;
             prePayModel.setTimeStamp(Long.toString(timeStamp));
 
-            String sign = buildMessage(WxV3PayConfig.APP_ID, timeStamp, prePayModel.getNonceStr(), prePayModel.getPackAge());
+            String sign = buildMessage(configModel.getAppId(), timeStamp, prePayModel.getNonceStr(), prePayModel.getPackAge());
             String signature = sign(privateKeyPath, sign.getBytes("utf-8"));
             prePayModel.setPaySign(signature);
             return ResultContent.buildContent(prePayModel);
@@ -190,7 +191,10 @@ public class WxPaymentService extends SuperService {
      * @return
     **/
     public ResultContent closeOrder(String outTradeNo, WxPayConfigModel configModel){
-        String privateKeyPath = Thread.currentThread().getContextClassLoader().getResource("").getPath() + configModel.getPrivateKeyPath();
+        String privateKeyPath = configModel.getPrivateKeyPath();
+        if (configModel.getPrivateKeyType().equals("local")){
+            privateKeyPath = Thread.currentThread().getContextClassLoader().getResource("").getPath() + configModel.getPrivateKeyPath();
+        }
 
         // 初始化商户配置
         Config config = RSAAutoCertificateConfig(configModel.getMchId(), privateKeyPath, configModel.getMchSerialNo(), configModel.getApiV3Key());
@@ -200,7 +204,7 @@ public class WxPaymentService extends SuperService {
             CloseOrderRequest request = new CloseOrderRequest();
             // 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
             // 调用接口
-            request.setMchid(WxV3PayConfig.Mch_ID);
+            request.setMchid(configModel.getMchId());
             request.setOutTradeNo(outTradeNo);
             service.closeOrder(request);
             return ResultContent.buildSuccess();
@@ -225,7 +229,10 @@ public class WxPaymentService extends SuperService {
      * @return
      **/
     public ResultContent<Transaction> queryOrderByOutTradeNo(String outTradeNo, WxPayConfigModel configModel){
-        String privateKeyPath = Thread.currentThread().getContextClassLoader().getResource("").getPath() + configModel.getPrivateKeyPath();
+        String privateKeyPath = configModel.getPrivateKeyPath();
+        if (configModel.getPrivateKeyType().equals("local")){
+            privateKeyPath = Thread.currentThread().getContextClassLoader().getResource("").getPath() + configModel.getPrivateKeyPath();
+        }
 
         // 初始化商户配置
         Config config = RSAAutoCertificateConfig(configModel.getMchId(), privateKeyPath, configModel.getMchSerialNo(), configModel.getApiV3Key());
@@ -235,7 +242,7 @@ public class WxPaymentService extends SuperService {
             QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
             // 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
             // 调用接口
-            request.setMchid(WxV3PayConfig.Mch_ID);
+            request.setMchid(configModel.getMchId());
             request.setOutTradeNo(outTradeNo);
             Transaction transaction = service.queryOrderByOutTradeNo(request);
             return ResultContent.buildSuccess(transaction);
@@ -260,7 +267,10 @@ public class WxPaymentService extends SuperService {
      * @return
      **/
     public ResultContent queryOrderById(String transactionId, WxPayConfigModel configModel){
-        String privateKeyPath = Thread.currentThread().getContextClassLoader().getResource("").getPath() + configModel.getPrivateKeyPath();
+        String privateKeyPath = configModel.getPrivateKeyPath();
+        if (configModel.getPrivateKeyType().equals("local")){
+            privateKeyPath = Thread.currentThread().getContextClassLoader().getResource("").getPath() + configModel.getPrivateKeyPath();
+        }
 
         // 初始化商户配置
         Config config = RSAAutoCertificateConfig(configModel.getMchId(), privateKeyPath, configModel.getMchSerialNo(), configModel.getApiV3Key());
@@ -270,7 +280,7 @@ public class WxPaymentService extends SuperService {
             QueryOrderByIdRequest request = new QueryOrderByIdRequest();
             // 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
             // 调用接口
-            request.setMchid(WxV3PayConfig.Mch_ID);
+            request.setMchid(configModel.getMchId());
             request.setTransactionId(transactionId);
             Transaction transaction = service.queryOrderById(request);
             return ResultContent.buildSuccess(transaction);

+ 35 - 27
PaymentServer/src/main/java/com/zhongshu/payment/server/core/service/wxPaymentV3/WxTransferBatchService.java

@@ -31,41 +31,49 @@ public class WxTransferBatchService {
     }
 
     /** 发起商家转账 */
-    public InitiateBatchTransferResponse InitiateBatchTransferResponse(InitiateBatchTransferRequest request, WxPayConfigModel wxPayConfigModel){
-        Config config = RSAAutoCertificateConfig(wxPayConfigModel.getMchId(), wxPayConfigModel.getPrivateKeyPath(), wxPayConfigModel.getMchSerialNo(), wxPayConfigModel.getApiV3Key());
+    public InitiateBatchTransferResponse InitiateBatchTransferResponse(InitiateBatchTransferRequest request, WxPayConfigModel configModel){
+        String privateKeyPath = configModel.getPrivateKeyPath();
+        if (configModel.getPrivateKeyType().equals("local")){
+            privateKeyPath = Thread.currentThread().getContextClassLoader().getResource("").getPath() + configModel.getPrivateKeyPath();
+        }
+        Config config = RSAAutoCertificateConfig(configModel.getMchId(), privateKeyPath, configModel.getMchSerialNo(), configModel.getApiV3Key());
         // 初始化服务
         service = new TransferBatchService.Builder().config(config).build();
         // ... 调用接口
         return service.initiateBatchTransfer(request);
     }
 
-    /** 通过微信批次单号查询批次单 */
-    public TransferBatchEntity getTransferBatchByNo(GetTransferBatchByNoRequest request, WxPayConfigModel wxPayConfigModel) {
-        Config config = RSAAutoCertificateConfig(wxPayConfigModel.getMchId(), wxPayConfigModel.getPrivateKeyPath(), wxPayConfigModel.getMchSerialNo(), wxPayConfigModel.getApiV3Key());
-        // 初始化服务
-        service = new TransferBatchService.Builder().config(config).build();
-        return service.getTransferBatchByNo(request);
-    }
-
-    /** 通过商家批次单号查询批次单 */
-    public TransferBatchEntity getTransferBatchByOutNo(GetTransferBatchByOutNoRequest request, WxPayConfigModel wxPayConfigModel) {
-        Config config = RSAAutoCertificateConfig(wxPayConfigModel.getMchId(), wxPayConfigModel.getPrivateKeyPath(), wxPayConfigModel.getMchSerialNo(), wxPayConfigModel.getApiV3Key());
-        // 初始化服务
-        service = new TransferBatchService.Builder().config(config).build();
-        return service.getTransferBatchByOutNo(request);
-    }
-
-    /** 通过微信明细单号查询明细单 */
-    public TransferDetailEntity getTransferDetailByNo(GetTransferDetailByNoRequest request, WxPayConfigModel wxPayConfigModel) {
-        Config config = RSAAutoCertificateConfig(wxPayConfigModel.getMchId(), wxPayConfigModel.getPrivateKeyPath(), wxPayConfigModel.getMchSerialNo(), wxPayConfigModel.getApiV3Key());
-        // 初始化服务
-        service = new TransferBatchService.Builder().config(config).build();
-        return service.getTransferDetailByNo(request);
-    }
+//    /** 通过微信批次单号查询批次单 */
+//    public TransferBatchEntity getTransferBatchByNo(GetTransferBatchByNoRequest request, WxPayConfigModel wxPayConfigModel) {
+//        Config config = RSAAutoCertificateConfig(wxPayConfigModel.getMchId(), wxPayConfigModel.getPrivateKeyPath(), wxPayConfigModel.getMchSerialNo(), wxPayConfigModel.getApiV3Key());
+//        // 初始化服务
+//        service = new TransferBatchService.Builder().config(config).build();
+//        return service.getTransferBatchByNo(request);
+//    }
+//
+//    /** 通过商家批次单号查询批次单 */
+//    public TransferBatchEntity getTransferBatchByOutNo(GetTransferBatchByOutNoRequest request, WxPayConfigModel wxPayConfigModel) {
+//        Config config = RSAAutoCertificateConfig(wxPayConfigModel.getMchId(), wxPayConfigModel.getPrivateKeyPath(), wxPayConfigModel.getMchSerialNo(), wxPayConfigModel.getApiV3Key());
+//        // 初始化服务
+//        service = new TransferBatchService.Builder().config(config).build();
+//        return service.getTransferBatchByOutNo(request);
+//    }
+//
+//    /** 通过微信明细单号查询明细单 */
+//    public TransferDetailEntity getTransferDetailByNo(GetTransferDetailByNoRequest request, WxPayConfigModel wxPayConfigModel) {
+//        Config config = RSAAutoCertificateConfig(wxPayConfigModel.getMchId(), wxPayConfigModel.getPrivateKeyPath(), wxPayConfigModel.getMchSerialNo(), wxPayConfigModel.getApiV3Key());
+//        // 初始化服务
+//        service = new TransferBatchService.Builder().config(config).build();
+//        return service.getTransferDetailByNo(request);
+//    }
 
     /** 通过商家明细单号查询明细单 */
-    public TransferDetailEntity getTransferDetailByOutNo(GetTransferDetailByOutNoRequest request, WxPayConfigModel wxPayConfigModel) {
-        Config config = RSAAutoCertificateConfig(wxPayConfigModel.getMchId(), wxPayConfigModel.getPrivateKeyPath(), wxPayConfigModel.getMchSerialNo(), wxPayConfigModel.getApiV3Key());
+    public TransferDetailEntity getTransferDetailByOutNo(GetTransferDetailByOutNoRequest request, WxPayConfigModel configModel) {
+        String privateKeyPath = configModel.getPrivateKeyPath();
+        if (configModel.getPrivateKeyType().equals("local")){
+            privateKeyPath = Thread.currentThread().getContextClassLoader().getResource("").getPath() + configModel.getPrivateKeyPath();
+        }
+        Config config = RSAAutoCertificateConfig(configModel.getMchId(), privateKeyPath, configModel.getMchSerialNo(), configModel.getApiV3Key());
         // 初始化服务
         service = new TransferBatchService.Builder().config(config).build();
         return service.getTransferDetailByOutNo(request);

+ 64 - 0
PaymentServer/src/main/java/com/zhongshu/payment/server/core/timer/ComplexTimer.java

@@ -0,0 +1,64 @@
+package com.zhongshu.payment.server.core.timer;
+
+import com.zhongshu.payment.client.types.RechargeState;
+import com.zhongshu.payment.server.core.dao.RechargeRecordDao;
+import com.zhongshu.payment.server.core.domain.wallet.RechargeRecord;
+import com.zhongshu.payment.server.core.service.RechargeService;
+import com.zhongshu.payment.server.core.service.TransferService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * @author wjf
+ * @date 2024/8/1
+ */
+@Slf4j
+@Component
+public class ComplexTimer implements ApplicationRunner {
+
+    @Autowired
+    RechargeRecordDao rechargeRecordDao;
+
+    @Autowired
+    TransferService transferService;
+
+    @Autowired
+    RechargeService rechargeService;
+
+
+//    @Scheduled(fixedRate = 5000)
+    public void transferResult() {
+
+        List<RechargeRecord> transferList = rechargeRecordDao.listByState(RechargeState.Taking);
+        for (RechargeRecord transfer : transferList){
+            try {
+                transferService.getTransferState(transfer.getOutTradeNo());
+            }catch (Exception e){
+                e.printStackTrace();
+            }
+        }
+    }
+
+    //    @Scheduled(fixedRate = 5000)
+    public void closeNoPay() {
+
+        List<RechargeRecord> list = rechargeRecordDao.listTimeOut(RechargeState.NOTPAY);
+        for (RechargeRecord noPay : list){
+            try {
+                rechargeService.closeNoPay(noPay.getOutTradeNo());
+            }catch (Exception e){
+                e.printStackTrace();
+            }
+        }
+    }
+
+    @Override
+    public void run(ApplicationArguments args) throws Exception {
+
+    }
+}

+ 24 - 0
PaymentServer/src/main/java/com/zhongshu/payment/server/core/utils/DateUtils.java

@@ -725,6 +725,30 @@ public class DateUtils {
         log.info("本月开始时间:{},结束时间:{}", paresTime(getMonthStartTime(2024, 7), FORMAT_LONG), paresTime(getMonthEndTime(2024, 7), FORMAT_LONG));
         Integer weekNumber = getWeekOfYear(System.currentTimeMillis());
         log.info("本年一共{}周,本周是第{}周,本周时间区间:{}-{}", getYearWeekCount(2023), weekNumber, paresTime(getWeekStartTime(2023, weekNumber), FORMAT_LONG), paresTime(getWeekEndTime(2023, weekNumber), FORMAT_LONG));
+        log.info(String.format("%s%s", DateUtils.paresTime(new Date().getTime(), DateUtils.pattern1), CommonUtil.UUID()));
+
+
+
+        Calendar c = Calendar.getInstance();
+
+        if (c.get(Calendar.MONTH)== Calendar.FEBRUARY){
+            c.add(Calendar.MONTH, 1);
+            c.set(Calendar.DAY_OF_MONTH, 0);
+
+            c.set(Calendar.HOUR_OF_DAY, 23);
+            c.set(Calendar.MINUTE, 59);
+            c.set(Calendar.SECOND, 59);
+        }
+
+        c.add(Calendar.MONTH, 1);
+        c.set(Calendar.DATE, 31);
+
+        c.set(Calendar.HOUR_OF_DAY, 0);
+        c.set(Calendar.MINUTE, 0);
+        c.set(Calendar.SECOND, 0);
+
+
+        log.info(paresTime(c.getTimeInMillis(), patternyyyySSS));
         log.info(Thread.currentThread().getContextClassLoader().getResource("").getPath());
     }
 }