Jelajahi Sumber

充值流程

wujiefeng 1 tahun lalu
induk
melakukan
de8ae2bebe
31 mengubah file dengan 1000 tambahan dan 61 penghapusan
  1. 1 0
      PaymentClient/src/main/java/com/zhongshu/payment/client/model/PrePayModel.java
  2. 38 0
      PaymentClient/src/main/java/com/zhongshu/payment/client/model/RechargeRecordModel.java
  3. 37 0
      PaymentClient/src/main/java/com/zhongshu/payment/client/model/WalletModel.java
  4. 19 0
      PaymentClient/src/main/java/com/zhongshu/payment/client/model/param/OrderParam.java
  5. 31 0
      PaymentClient/src/main/java/com/zhongshu/payment/client/model/param/RechargeParam.java
  6. 37 0
      PaymentClient/src/main/java/com/zhongshu/payment/client/model/param/WxPayConfigParam.java
  7. 9 12
      PaymentClient/src/main/java/com/zhongshu/payment/client/model/param/WxPrepayParam.java
  8. 11 0
      PaymentClient/src/main/java/com/zhongshu/payment/client/model/param/WxTransferBatchParam.java
  9. 1 0
      PaymentClient/src/main/java/com/zhongshu/payment/client/ret/ResultState.java
  10. 27 0
      PaymentClient/src/main/java/com/zhongshu/payment/client/types/RechargeState.java
  11. 27 0
      PaymentClient/src/main/java/com/zhongshu/payment/client/types/TradeState.java
  12. 1 1
      PaymentClient/src/main/java/com/zhongshu/payment/client/types/WalletType.java
  13. 0 1
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/controller/wxPaymentV3/WechatNotifyController.java
  14. 4 4
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/controller/wxPaymentV3/WechatPayV3Controller.java
  15. 13 0
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/dao/RechargeRecordDao.java
  16. 14 0
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/dao/WalletDao.java
  17. 14 0
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/dao/WxPayConfigDao.java
  18. 8 0
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/dao/extend/WxPayConfigDaoExtend.java
  19. 10 0
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/dao/impl/WxPayConfigDaoImpl.java
  20. 44 0
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/domain/wallet/RechargeRecord.java
  21. 12 2
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/domain/wallet/Wallet.java
  22. 30 0
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/domain/wallet/WalletFlow.java
  23. 42 0
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/domain/wechatPay/WxPayConfig.java
  24. 171 0
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/service/RechargeService.java
  25. 58 0
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/service/wallet/WalletService.java
  26. 31 0
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/service/wxPaymentV3/WxPayConfigService.java
  27. 47 8
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/service/wxPaymentV3/WxPayNotifyService.java
  28. 108 33
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/service/wxPaymentV3/WxPaymentService.java
  29. 74 0
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/service/wxPaymentV3/WxTransferBatchService.java
  30. 78 0
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/utils/BeanUtils.java
  31. 3 0
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/utils/DateUtils.java

+ 1 - 0
PaymentClient/src/main/java/com/zhongshu/payment/client/model/PrePayModel.java

@@ -3,6 +3,7 @@ package com.zhongshu.payment.client.model;
 import lombok.Data;
 
 /**
+ * 用户下单后返回给前端调用支付所属参数
  * @author wjf
  * @date 2024/7/24
  */

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

@@ -0,0 +1,38 @@
+package com.zhongshu.payment.client.model;
+
+import com.zhongshu.payment.client.types.PaymentType;
+import com.zhongshu.payment.client.types.RechargeState;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+/**
+ * @author wjf
+ * @date 2024/7/25
+ */
+@Data
+public class RechargeRecordModel {
+
+    @Schema(name = "oid", description = "项目id")
+    private String oid;
+
+    @Schema(name = "userId", description = "用户id")
+    private String userId;
+
+    @Schema(name = "paymentType", description = "支付方式")
+    private PaymentType paymentType;
+
+    @Schema(name = "description", description = "商品描述(必填)")
+    private String description;
+
+    @Schema(name = "amount", description = "订单金额")
+    private Integer total;
+
+    @Schema(name = "outTradeNo", description = "商户订单号(必填)")
+    private String outTradeNo;
+
+    @Schema(name = "rechargeState", description = "订单状态")
+    private RechargeState rechargeState;
+
+    @Schema(name = "tradeTime", description = "交易时间")
+    private Long tradeTime;
+}

+ 37 - 0
PaymentClient/src/main/java/com/zhongshu/payment/client/model/WalletModel.java

@@ -0,0 +1,37 @@
+package com.zhongshu.payment.client.model;
+
+import com.zhongshu.payment.client.types.DataState;
+import com.zhongshu.payment.client.types.WalletType;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * @author wjf
+ * @date 2024/7/26
+ */
+@Data
+public class WalletModel {
+
+    @Schema(description = "项目id")
+    private String oid;
+
+    @Schema(description = "用户userId")
+    private String userId;
+
+    @Schema(description = "可用金额,单位:分")
+    private BigDecimal amount = BigDecimal.ZERO;
+
+    @Schema(description = "账户金额,单位:分")
+    private BigDecimal totalAmount = BigDecimal.ZERO;
+
+    @Schema(description = "钱包状态:是否可用")
+    private DataState dataState = DataState.Enable;
+
+    @Schema(description = "钱包类型")
+    private WalletType walletType;
+
+    @Schema(description = "openid")
+    private String openid;
+}

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

@@ -0,0 +1,19 @@
+package com.zhongshu.payment.client.model.param;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+/**
+ * 充值下单参数
+ * @author wjf
+ * @date 2024/7/25
+ */
+@Data
+public class OrderParam {
+
+    @Schema(name = "outTradeNo", description = "商户订单号(必填)")
+    private String outTradeNo;
+
+    @Schema(name = "jscode", description = "微信用户授权码", example = "123456")
+    private String jscode;
+}

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

@@ -0,0 +1,31 @@
+package com.zhongshu.payment.client.model.param;
+
+import com.zhongshu.payment.client.types.PaymentType;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+/**
+ * @author wjf
+ * @date 2024/7/25
+ */
+@Data
+public class RechargeParam {
+
+    @Schema(name = "oid", description = "项目id",required = true, example = "oid")
+    private String oid;
+
+    @Schema(name = "paymentType", description = "支付方式", required = true, example = "WeChat")
+    private PaymentType paymentType;
+
+    // 商品描述(必填)
+    @Schema(name = "description", description = "商品描述(必填)", required = true, example = "充值服务")
+    private String description;
+
+    // 订单金额(必填)
+    @Schema(name = "amount", description = "订单金额",required = true, example = "{\"total\":100,\"currency\":\"CNY\"}")
+    private Integer total;
+
+    @Schema(name = "jscode", description = "微信用户授权码", example = "123456")
+    private String jscode;
+
+}

+ 37 - 0
PaymentClient/src/main/java/com/zhongshu/payment/client/model/param/WxPayConfigParam.java

@@ -0,0 +1,37 @@
+package com.zhongshu.payment.client.model.param;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+/**
+ * 项目绑定微信支付参数
+ * @author wjf
+ * @date 2024/7/25
+ */
+@Data
+public class WxPayConfigParam {
+
+    @Schema(description = "项目id")
+    private String oid;
+
+    @Schema(description = "appid")
+    private String appid;
+
+    @Schema(description = "商户证书序列号")
+    public String mchSerialNo;
+
+    @Schema(description = "商户id")
+    public String mchId;
+
+    @Schema(description = "API V3密钥")
+    public String apiV3Key;
+
+    @Schema(description = "认证类型")
+    public String AuthenticationType;
+
+    @Schema(description = "私钥地址")
+    public String privateKeyPath;
+
+    @Schema(description = "回调地址")
+    private String notifyUrl;
+}

+ 9 - 12
PaymentClient/src/main/java/com/zhongshu/payment/client/model/param/WxTransactionsParam.java → PaymentClient/src/main/java/com/zhongshu/payment/client/model/param/WxPrepayParam.java

@@ -1,14 +1,10 @@
 package com.zhongshu.payment.client.model.param;
 
-import com.wechat.pay.java.service.refund.model.Amount;
-import com.zhongshu.payment.client.types.WxPayType;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.AllArgsConstructor;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
-import java.util.Map;
-
 /**
  * 微信支付下单参数
  * @author wjf
@@ -17,7 +13,7 @@ import java.util.Map;
 @Data
 @NoArgsConstructor
 @AllArgsConstructor
-public class WxTransactionsParam {
+public class WxPrepayParam {
 
 //    // 公众号ID(必填)
 //    private String appid;
@@ -26,13 +22,14 @@ public class WxTransactionsParam {
 //    private String mchid;
 
     // 项目id
+    @Schema(name = "oid", description = "项目id", required = true, example = "123456")
     private String oid;
 
-    @Schema(name = "微信授权code",required = true, example = "21321")
+    @Schema(name = "jscode", description = "微信授权code", required = true, example = "123456")
     private String jscode;
 
     // 商品描述(必填)
-    @Schema(name = "商品描述",required = true, example = "充值服务")
+    @Schema(name = "description", description = "商品描述(必填)", required = true, example = "充值服务")
     private String description;
 
 //    // 商户订单号(必填)
@@ -42,25 +39,25 @@ public class WxTransactionsParam {
 //    private String timeExpire;
 
     // 附加数据
-    @Schema(name = "附加数据",required = false, example = "备注")
+    @Schema(name = "attach", description = "附加数据", required = false, example = "附加数据")
     private String attach;
 
 //    // 通知地址(必填)
 //    private String notifyUrl;
 
     // 订单金额(必填)
-    @Schema(name = "订单金额",required = true, example = "")
+    @Schema(name = "amount", description = "订单金额",required = true, example = "{\"total\":100,\"currency\":\"CNY\"}")
     private WxAmount amount;
 
 //    // 支付者信息:openid(必填)
 //    private WxPayer payer;
 
     // 交易地点
-    @Schema(name = "附加数据",required = true)
+    @Schema(name = "sceneInfo", description = "交易地点",required = true, example = "云芯客--钱包--微信充值")
     private String sceneInfo;
 
-    //下单类型
-    private WxPayType wxPayType;
+//    //下单类型
+//    private WxPayType wxPayType;
 
 
 }

+ 11 - 0
PaymentClient/src/main/java/com/zhongshu/payment/client/model/param/WxTransferBatchParam.java

@@ -0,0 +1,11 @@
+package com.zhongshu.payment.client.model.param;
+
+import lombok.Data;
+
+/**
+ * @author wjf
+ * @date 2024/7/24
+ */
+@Data
+public class WxTransferBatchParam {
+}

+ 1 - 0
PaymentClient/src/main/java/com/zhongshu/payment/client/ret/ResultState.java

@@ -27,6 +27,7 @@ public enum ResultState {
     AccountNotNull("账户不能为空"),
     AccountExists("用户存在"),
     AccountNotExists("账户不存在"),
+    NOT_WECHAT_AUTH("用户微信未授权"),
     ;
 
     @Getter

+ 27 - 0
PaymentClient/src/main/java/com/zhongshu/payment/client/types/RechargeState.java

@@ -0,0 +1,27 @@
+package com.zhongshu.payment.client.types;
+
+import lombok.Getter;
+
+/**
+ * @author wjf
+ * @date 2024/7/25
+ */
+public enum RechargeState {
+
+    SUCCESS("支付成功"),
+    REFUND("转入退款"),
+    NOTPAY("未支付"),
+    RECHARGING("充值中"),
+    CLOSED("已关闭"),
+    REVOKED(":已撤销(付款码支付)"),
+    USERPAYING("用户支付中(付款码支付)"),
+    PAYERROR("支付失败(其他原因,如银行返回失败)")
+    ;
+
+    @Getter
+    private String remark;
+
+    RechargeState(String remark) {
+        this.remark = remark;
+    }
+}

+ 27 - 0
PaymentClient/src/main/java/com/zhongshu/payment/client/types/TradeState.java

@@ -0,0 +1,27 @@
+package com.zhongshu.payment.client.types;
+
+import lombok.Getter;
+
+/**
+ * @author wjf
+ * @date 2024/7/25
+ */
+public enum TradeState {
+
+    SUCCESS("支付成功"),
+    REFUND("转入退款"),
+    NOTPAY("未支付"),
+    RECHARGING("充值中"),
+    CLOSED("已关闭"),
+    REVOKED(":已撤销(付款码支付)"),
+    USERPAYING("用户支付中(付款码支付)"),
+    PAYERROR("支付失败(其他原因,如银行返回失败)")
+    ;
+
+    @Getter
+    private String remark;
+
+    TradeState(String remark) {
+        this.remark = remark;
+    }
+}

+ 1 - 1
PaymentClient/src/main/java/com/zhongshu/payment/client/types/WalletType.java

@@ -10,7 +10,7 @@ public enum WalletType {
 
     Project("项目(商户)"),
     SubProject("子项目(子商户)"),
-    H5("h5"),
+    User("用户"),
     ;
 
     @Getter

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

@@ -8,7 +8,6 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.MediaType;
 import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 

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

@@ -1,7 +1,6 @@
 package com.zhongshu.payment.server.core.controller.wxPaymentV3;
 
-import com.zhongshu.payment.client.model.param.WxTransactionsParam;
-import com.zhongshu.payment.client.ret.ResultContent;
+import com.zhongshu.payment.client.model.param.WxPrepayParam;
 import com.zhongshu.payment.server.core.service.wxPaymentV3.WxPaymentService;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
@@ -26,8 +25,9 @@ public class WechatPayV3Controller {
 
     @Operation(summary = "下单")
     @PostMapping(value = "transactions", consumes = MediaType.APPLICATION_JSON_VALUE)
-    public Object transactions(@RequestBody WxTransactionsParam param){
-        return wxPaymentService.prepay(param);
+    public Object transactions(@RequestBody WxPrepayParam param){
+//        return wxPaymentService.prepay(param);
+        return null;
     }
 
     @Operation(summary = "获取openid")

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

@@ -0,0 +1,13 @@
+package com.zhongshu.payment.server.core.dao;
+
+import com.github.microservice.components.data.mongo.mongo.dao.MongoDao;
+import com.zhongshu.payment.server.core.domain.wallet.RechargeRecord;
+
+/**
+ * @author wjf
+ * @date 2024/7/25
+ */
+public interface RechargeRecordDao extends MongoDao<RechargeRecord> {
+
+    RechargeRecord findByOutTradeNo(String outTradeNo);
+}

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

@@ -0,0 +1,14 @@
+package com.zhongshu.payment.server.core.dao;
+
+import com.github.microservice.components.data.mongo.mongo.dao.MongoDao;
+import com.zhongshu.payment.server.core.domain.wallet.Wallet;
+
+/**
+ * @author wjf
+ * @date 2024/7/25
+ */
+public interface WalletDao extends MongoDao<Wallet> {
+
+    Wallet findByUserIdAndOid(String userId, String oid);
+
+}

+ 14 - 0
PaymentServer/src/main/java/com/zhongshu/payment/server/core/dao/WxPayConfigDao.java

@@ -0,0 +1,14 @@
+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.WxPayConfigDaoExtend;
+import com.zhongshu.payment.server.core.domain.wechatPay.WxPayConfig;
+
+/**
+ * @author wjf
+ * @date 2024/7/25
+ */
+public interface WxPayConfigDao extends MongoDao<WxPayConfig>, WxPayConfigDaoExtend {
+
+    WxPayConfig findByOid(String oid);
+}

+ 8 - 0
PaymentServer/src/main/java/com/zhongshu/payment/server/core/dao/extend/WxPayConfigDaoExtend.java

@@ -0,0 +1,8 @@
+package com.zhongshu.payment.server.core.dao.extend;
+
+/**
+ * @author wjf
+ * @date 2024/7/25
+ */
+public interface WxPayConfigDaoExtend {
+}

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

@@ -0,0 +1,10 @@
+package com.zhongshu.payment.server.core.dao.impl;
+
+import com.zhongshu.payment.server.core.dao.extend.WxPayConfigDaoExtend;
+
+/**
+ * @author wjf
+ * @date 2024/7/25
+ */
+public class WxPayConfigDaoImpl implements WxPayConfigDaoExtend {
+}

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

@@ -0,0 +1,44 @@
+package com.zhongshu.payment.server.core.domain.wallet;
+
+import com.github.microservice.components.data.mongo.mongo.domain.SuperEntity;
+import com.zhongshu.payment.client.types.PaymentType;
+import com.zhongshu.payment.client.types.RechargeState;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import java.math.BigDecimal;
+
+/**
+ * 充值记录
+ * @author wjf
+ * @date 2024/7/25
+ */
+@Data
+@Document
+public class RechargeRecord extends SuperEntity {
+
+    @Schema(name = "oid", description = "项目id")
+    private String oid;
+
+    @Schema(name = "userId", description = "用户id")
+    private String userId;
+
+    @Schema(name = "paymentType", description = "支付方式")
+    private PaymentType paymentType;
+
+    @Schema(name = "description", description = "商品描述(必填)")
+    private String description;
+
+    @Schema(name = "amount", description = "订单金额")
+    private BigDecimal total = BigDecimal.ZERO;
+
+    @Schema(name = "outTradeNo", description = "商户订单号(必填)")
+    private String outTradeNo;
+
+    @Schema(name = "rechargeState", description = "订单状态")
+    private RechargeState rechargeState;
+
+    @Schema(name = "tradeTime", description = "交易时间")
+    private Long tradeTime;
+}

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

@@ -1,8 +1,8 @@
 package com.zhongshu.payment.server.core.domain.wallet;
 
+import com.github.microservice.components.data.mongo.mongo.domain.SuperEntity;
 import com.zhongshu.payment.client.types.DataState;
 import com.zhongshu.payment.client.types.WalletType;
-import com.zhongshu.payment.server.core.domain.base.SuperMain;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.AllArgsConstructor;
 import lombok.Builder;
@@ -23,7 +23,10 @@ import java.math.BigDecimal;
 @Document
 @AllArgsConstructor
 @NoArgsConstructor
-public class Wallet extends SuperMain {
+public class Wallet extends SuperEntity {
+
+    @Schema(description = "项目id")
+    private String oid;
 
     @Schema(description = "用户userId")
     private String userId;
@@ -31,8 +34,15 @@ public class Wallet extends SuperMain {
     @Schema(description = "可用金额,单位:分")
     private BigDecimal amount = BigDecimal.ZERO;
 
+    @Schema(description = "账户金额,单位:分")
+    private BigDecimal totalAmount = BigDecimal.ZERO;
+
     @Schema(description = "钱包状态:是否可用")
     private DataState dataState = DataState.Enable;
 
+    @Schema(description = "钱包类型")
     private WalletType walletType;
+
+    @Schema(description = "openid")
+    private String openid;
 }

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

@@ -0,0 +1,30 @@
+package com.zhongshu.payment.server.core.domain.wallet;
+
+import com.github.microservice.components.data.mongo.mongo.domain.SuperEntity;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+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/26
+ */
+@Data
+@Document
+public class WalletFlow extends SuperEntity {
+
+    @DBRef(lazy = true)
+    private Wallet wallet;
+
+    @Schema(description = "订单号")
+    private String outTradeNo;
+
+    @Schema(description = "金额")
+    private BigDecimal total;
+
+    @Schema(description = "流水类型:充值/消费/提现")
+    private String walletFlow;
+}

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

@@ -0,0 +1,42 @@
+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.Data;
+import org.springframework.data.mongodb.core.index.Indexed;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+/**
+ * @author wjf
+ * @date 2024/7/25
+ */
+@Data
+@Document
+public class WxPayConfig extends SuperEntity {
+
+    @Schema(description = "项目id")
+    @Indexed(unique = true)
+    private String oid;
+
+    @Schema(description = "appid")
+    private String appid;
+
+    @Schema(description = "商户证书序列号")
+    private String mchSerialNo;
+
+    @Schema(description = "商户id")
+    private String mchId;
+
+    @Schema(description = "API V3密钥")
+    private String apiV3Key;
+
+    @Schema(description = "认证类型")
+    private String AuthenticationType;
+
+    @Schema(description = "私钥地址")
+    private String privateKeyPath;
+
+    @Schema(description = "回调地址")
+    private String notifyUrl;
+
+}

+ 171 - 0
PaymentServer/src/main/java/com/zhongshu/payment/server/core/service/RechargeService.java

@@ -0,0 +1,171 @@
+package com.zhongshu.payment.server.core.service;
+
+import ch.qos.logback.core.util.StringUtil;
+import com.github.microservice.auth.security.helper.AuthHelper;
+import com.wechat.pay.java.service.payments.jsapi.model.Amount;
+import com.wechat.pay.java.service.payments.jsapi.model.Payer;
+import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest;
+import com.wechat.pay.java.service.payments.model.Transaction;
+import com.zhongshu.card.client.model.wechat.MiniAppUserInfoVo;
+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.RechargeState;
+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.domain.wallet.RechargeRecord;
+import com.zhongshu.payment.server.core.domain.wallet.Wallet;
+import com.zhongshu.payment.server.core.domain.wechatPay.WxPayConfig;
+import com.zhongshu.payment.server.core.service.wxPaymentV3.WxPaymentService;
+import com.zhongshu.payment.server.core.utils.BeanUtils;
+import com.zhongshu.payment.server.core.utils.CommonUtil;
+import com.zhongshu.payment.server.core.utils.DateUtils;
+import com.zhongshu.payment.server.core.utils.wx.WechatCUtil;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+
+/**
+ * 充值服务
+ * @author wjf
+ * @date 2024/7/25
+ */
+@Slf4j
+@Service
+public class RechargeService {
+
+    @Autowired
+    AuthHelper authHelper;
+
+    @Autowired
+    WxPaymentService wxPaymentService;
+
+    @Autowired
+    WechatCUtil wechatCUtil;
+
+    @Autowired
+    WalletDao walletDao;
+
+    @Autowired
+    WxPayConfigDao wxPayConfigDao;
+
+    @Autowired
+    RechargeRecordDao rechargeRecordDao;
+
+    /** 创建充值订单 */
+    public Object create(RechargeParam param){
+        String userId = authHelper.getCurrentUser().getUser();
+        Wallet userWallet = walletDao.findByUserIdAndOid(userId, param.getOid());
+        //判断钱包是否初始化
+        if (userWallet==null){
+            return ResultContent.buildFail("用户钱包未开通");
+        }
+        RechargeRecord rechargeRecord = new RechargeRecord();
+        BeanUtils.copyPropertiesWithoutNull(param, rechargeRecord);
+        String outTradeNo = CommonUtil.UUID();
+        rechargeRecord.setOutTradeNo(outTradeNo);
+        rechargeRecord.setTotal(BigDecimal.valueOf(param.getTotal()));
+
+        rechargeRecord.setRechargeState(RechargeState.NOTPAY);
+        RechargeRecord record = rechargeRecordDao.save(rechargeRecord);
+        RechargeRecordModel model = toModel(record);
+        return ResultContent.buildSuccess(model);
+    }
+
+    private RechargeRecordModel toModel(RechargeRecord record) {
+        RechargeRecordModel model = new RechargeRecordModel();
+        if (record!=null){
+            BeanUtils.copyPropertiesWithoutNull(record, model);
+            model.setTotal(record.getTotal().intValue());
+        }
+        return model;
+    }
+
+    /** 下单 */
+    public Object order(OrderParam param){
+        String userId = authHelper.getCurrentUser().getUser();
+
+        RechargeRecord record = rechargeRecordDao.findByOutTradeNo(param.getOutTradeNo());
+        Wallet userWallet = walletDao.findByUserIdAndOid(userId, record.getOid());
+        String openId;
+        if (StringUtil.notNullNorEmpty(param.getJscode())){
+            openId = getOpenId(param.getJscode());
+        }else {
+            openId = userWallet.getOpenid();
+        }
+        if (StringUtil.isNullOrEmpty(openId)){
+            return ResultContent.buildFail("获取openid失败");
+        }
+
+        //判断微信支付配置
+        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());
+        //生成商户订单号
+        String outTradeNo = CommonUtil.UUID();
+        request.setOutTradeNo(outTradeNo);
+        //设置交易失效时间,15分钟
+        request.setTimeExpire(DateUtils.paresTime(System.currentTimeMillis() + 15*60*1000, DateUtils.patternWx));
+        Payer payer = new Payer();
+        payer.setOpenid(openId);
+        request.setPayer(payer);
+        return wxPaymentService.prepay(request);
+    }
+
+    /** 查询订单支付状态 */
+    public Object queryTradeState(String outTradeNo){
+        ResultContent<Transaction> queryResult = wxPaymentService.queryOrderByOutTradeNo(outTradeNo);
+        if (queryResult.isSuccess()){
+            return ResultContent.buildSuccess(queryResult.getContent().getTradeState().name());
+        }
+        return queryResult;
+    }
+
+    /** 得到支付结果后处理 */
+    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);
+        }
+    }
+
+    /** 关闭充值订单 */
+    public Object closer(String outTradeNo){
+        return wxPaymentService.closeOrder(outTradeNo);
+    }
+
+    /** 获取用户openid */
+    @SneakyThrows
+    public String getOpenId(String jscode){
+        MiniAppUserInfoVo miniAppUserInfo = wechatCUtil.getMiniAppUserInfo(jscode);
+        if (miniAppUserInfo==null || io.netty.util.internal.StringUtil.isNullOrEmpty(miniAppUserInfo.getOpenid())){
+            log.info("无法获取用户信息");
+            return null;
+        }
+        log.info("用户openid:{}", miniAppUserInfo.getOpenid());
+        return miniAppUserInfo.getOpenid();
+    }
+}

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

@@ -1,8 +1,21 @@
 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.zhongshu.payment.client.model.WalletModel;
+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.WalletDao;
+import com.zhongshu.payment.server.core.domain.wallet.Wallet;
+import com.zhongshu.payment.server.core.utils.BeanUtils;
 import groovy.util.logging.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.math.BigDecimal;
+
 /**
  * @author wjf
  * @date 2024/7/24
@@ -11,4 +24,49 @@ import org.springframework.stereotype.Service;
 @Slf4j
 @Service
 public class WalletService {
+
+    @Autowired
+    WalletDao walletDao;
+
+    @Autowired
+    AuthHelper authHelper;
+
+    /** 获取用户微信授权状态 */
+    public Object getWeChatAuthState(String oid){
+        String userId = authHelper.getCurrentUser().getUser();
+        Wallet wallet = walletDao.findByUserIdAndOid(userId, oid);
+        if (wallet==null){
+            return ResultContent.build(ResultState.NOT_WECHAT_AUTH);
+        }
+        return ResultContent.buildSuccess();
+    }
+
+    /** 查询用户钱包 */
+    public Object getWallet(String oid, WalletType walletType, String userId){
+        if (StringUtil.isNullOrEmpty(userId)){
+            userId = authHelper.getCurrentUser().getUser();
+        }
+
+        Wallet wallet = walletDao.findByUserIdAndOid(userId, oid);
+        if (wallet!=null){
+            return ResultContent.buildSuccess(toModel(wallet));
+        }
+        wallet = new Wallet();
+        wallet.setOid(oid);
+        wallet.setUserId(userId);
+        wallet.setAmount(BigDecimal.ZERO);
+        wallet.setAmount(BigDecimal.ZERO);
+        wallet.setDataState(DataState.Enable);
+        wallet.setWalletType(walletType);
+        walletDao.save(wallet);
+        return ResultContent.buildSuccess(toModel(wallet));
+    }
+
+    private WalletModel toModel(Wallet wallet){
+        WalletModel model = new WalletModel();
+        if (wallet!=null){
+            BeanUtils.copyPropertiesWithoutNull(wallet, model);
+        }
+        return model;
+    }
 }

+ 31 - 0
PaymentServer/src/main/java/com/zhongshu/payment/server/core/service/wxPaymentV3/WxPayConfigService.java

@@ -0,0 +1,31 @@
+package com.zhongshu.payment.server.core.service.wxPaymentV3;
+
+import com.zhongshu.payment.client.model.param.WxPayConfigParam;
+import com.zhongshu.payment.server.core.dao.WxPayConfigDao;
+import com.zhongshu.payment.server.core.domain.wechatPay.WxPayConfig;
+import com.zhongshu.payment.server.core.utils.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 微信支付配置服务
+ * @author wjf
+ * @date 2024/7/25
+ */
+@Service
+public class WxPayConfigService {
+
+    @Autowired
+    WxPayConfigDao wxPayConfigDao;
+
+    /** 创建/修改项目微信支付配置 */
+    public Object update(WxPayConfigParam param){
+        WxPayConfig wxPayConfig = wxPayConfigDao.findByOid(param.getOid());
+        if (wxPayConfig==null){
+            wxPayConfig = new WxPayConfig();
+        }
+        BeanUtils.copyPropertiesWithoutNull(param, wxPayConfig);
+        wxPayConfigDao.save(wxPayConfig);
+        return null;
+    }
+}

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

@@ -4,19 +4,23 @@ import com.wechat.pay.java.core.RSAAutoCertificateConfig;
 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.partnerpayments.app.model.Transaction;
+import com.wechat.pay.java.service.payments.model.Transaction;
+import com.zhongshu.payment.client.types.RechargeState;
+import com.zhongshu.payment.server.core.dao.RechargeRecordDao;
 import com.zhongshu.payment.server.core.dataConfig.WxV3PayConfig;
-import groovy.util.logging.Slf4j;
+import com.zhongshu.payment.server.core.domain.wallet.RechargeRecord;
+import com.zhongshu.payment.server.core.utils.DateUtils;
 import jakarta.servlet.ServletInputStream;
 import jakarta.servlet.http.HttpServletRequest;
 import jline.internal.Log;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import java.io.BufferedReader;
 import java.io.InputStreamReader;
 
 import static com.wechat.pay.contrib.apache.httpclient.constant.WechatPayHttpHeaders.*;
-import static com.wechat.pay.contrib.apache.httpclient.constant.WechatPayHttpHeaders.WECHAT_PAY_SIGNATURE;
 
 /**
  * @author wjf
@@ -26,6 +30,9 @@ import static com.wechat.pay.contrib.apache.httpclient.constant.WechatPayHttpHea
 @Slf4j
 public class WxPayNotifyService {
 
+    @Autowired
+    RechargeRecordDao rechargeRecordDao;
+
     public void payNotify(HttpServletRequest request) {
         try {
             //读取请求体的信息
@@ -63,16 +70,48 @@ public class WxPayNotifyService {
                     .signType(signType)
                     .body(body)
                     .build();
-            Transaction parse = parser.parse(requestParam, Transaction.class);
-            System.out.println("parse = " + parse);
+            Transaction transaction = parser.parse(requestParam, Transaction.class);
+            System.out.println("parse = " + transaction);
+
+            RechargeRecord record = rechargeRecordDao.findByOutTradeNo(transaction.getOutTradeNo());
+            if (record == null){
+                log.error("微信支付通知回调错误:找不到订单outTradeNo:{}", transaction.getOutTradeNo());
+                return;
+            }
             //parse.getTradeState().equals("SUCCESS");说明支付成功
-            if (parse.getTradeState().equals(Transaction.TradeStateEnum.SUCCESS)){
+            if (transaction.getTradeState().equals(Transaction.TradeStateEnum.SUCCESS)){
                 //你的业务代码
-                Log.info("微信支付成功");
+                log.info("微信支付成功");
+                record.setRechargeState(RechargeState.SUCCESS);
+                record.setTradeTime(DateUtils.timeToLong(transaction.getSuccessTime(), DateUtils.patternWx));
+                rechargeRecordDao.save(record);
+                //todo 账户可用余额 增加
+            }else {
+                log.info("微信支付异常:{}", transaction.getTradeState());
+                record.setRechargeState(RechargeState.valueOf(transaction.getTradeState().name()));
+                rechargeRecordDao.save(record);
             }
-            Log.info("微信支付异常:{}", parse.getTradeState());
+            Log.info("微信支付异常:{}", transaction.getTradeState());
         } catch (Exception e) {
             Log.info("微信支付回调验签错误:{}", e.getMessage());
         }
     }
+
+    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);
+        }
+    }
 }

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

@@ -5,46 +5,27 @@ import com.wechat.pay.java.core.RSAAutoCertificateConfig;
 import com.wechat.pay.java.core.exception.HttpException;
 import com.wechat.pay.java.core.exception.MalformedMessageException;
 import com.wechat.pay.java.core.exception.ServiceException;
-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.core.util.NonceUtil;
 import com.wechat.pay.java.core.util.PemUtil;
-import com.wechat.pay.java.service.partnerpayments.app.model.Transaction;
-import com.wechat.pay.java.service.payments.jsapi.model.Amount;
-import com.wechat.pay.java.service.payments.jsapi.model.Payer;
-import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest;
-import com.wechat.pay.java.service.payments.jsapi.model.PrepayResponse;
+import com.wechat.pay.java.service.payments.jsapi.model.*;
+import com.wechat.pay.java.service.payments.model.Transaction;
 import com.zhongshu.card.client.model.wechat.MiniAppUserInfoVo;
 import com.zhongshu.payment.client.model.PrePayModel;
-import com.zhongshu.payment.client.model.param.WxTransactionsParam;
 import com.zhongshu.payment.client.ret.ResultContent;
-import com.zhongshu.payment.client.ret.ResultState;
 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;
-import jakarta.servlet.ServletInputStream;
-import jakarta.servlet.http.HttpServletRequest;
-import jline.internal.Log;
 import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
 import java.io.UnsupportedEncodingException;
 import java.security.PrivateKey;
 import java.security.Signature;
 import java.util.Base64;
-import java.util.HashMap;
-import java.util.Map;
 
-import static cn.hutool.crypto.SignUtil.sign;
-import static cn.hutool.crypto.SignUtil.signParamsSha256;
-import static com.wechat.pay.contrib.apache.httpclient.constant.WechatPayHttpHeaders.*;
-import static com.wechat.pay.contrib.apache.httpclient.constant.WechatPayHttpHeaders.WECHAT_PAY_SIGNATURE;
 
 /**
  * @author TRX
@@ -60,7 +41,7 @@ public class WxPaymentService extends SuperService {
     public static com.wechat.pay.java.service.payments.jsapi.JsapiService service;
 
     // 初始化商户配置
-    public Config RSAAutoCertificateConfig(){
+    public static Config RSAAutoCertificateConfig(){
         return new RSAAutoCertificateConfig.Builder()
                 .merchantId(WxV3PayConfig.Mch_ID)
                 // 使用 com.wechat.pay.java.core.util 中的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名
@@ -98,21 +79,16 @@ public class WxPaymentService extends SuperService {
      * @Param
      * @return
     **/
-    public ResultContent prepay(WxTransactionsParam param){
+    public ResultContent<PrePayModel> prepay(PrepayRequest request){
+
 
-        String openId = getOpenId(param.getJscode());
-        if (StringUtil.isNullOrEmpty(openId)){
-            return ResultContent.buildFail("获取用户openid失败");
-        }
         // 初始化商户配置
         Config config = RSAAutoCertificateConfig();
         // 初始化服务
         service = new com.wechat.pay.java.service.payments.jsapi.JsapiService.Builder().config(config).build();
         // ... 调用接口
         try {
-            PrepayRequest request = new PrepayRequest();
             // 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
-            // 调用接口
             request.setAppid("wx92ae04fb0f325887");
             request.setMchid("1680033836");
             request.setDescription("充值服务");
@@ -125,6 +101,7 @@ public class WxPaymentService extends SuperService {
             Payer payer = new Payer();
             payer.setOpenid("oSd8L7Wlucyn7a8g3SZCOeLrSUKY");
             request.setPayer(payer);
+            // 调用接口
             PrepayResponse response = service.prepay(request);
 
             PrePayModel prePayModel = new PrePayModel();
@@ -140,22 +117,120 @@ public class WxPaymentService extends SuperService {
             return ResultContent.buildContent(prePayModel);
         } catch (HttpException e) { // 发送HTTP请求失败
             // 调用e.getHttpRequest()获取请求打印日志或上报监控,更多方法见HttpException定义
-            Log.info("请求失败1:", e.getHttpRequest());
+            log.info("请求失败1:{}", e.getHttpRequest());
             return ResultContent.buildFail("发送HTTP请求失败");
         } catch (ServiceException e) { // 服务返回状态小于200或大于等于300,例如500
             // 调用e.getResponseBody()获取返回体打印日志或上报监控,更多方法见ServiceException定义
-            Log.info("请求失败2:", e.getResponseBody());
+            log.info("请求失败2:{}", e.getResponseBody());
             return ResultContent.buildFail(e.getErrorMessage());
         } catch (MalformedMessageException e) { // 服务返回成功,返回体类型不合法,或者解析返回体失败
             // 调用e.getMessage()获取信息打印日志或上报监控,更多方法见MalformedMessageException定义
-            Log.info("请求失败3:", e.getMessage());
+            log.info("请求失败3:{}", e.getMessage());
             return ResultContent.buildFail("服务返回成功,返回体类型不合法,或者解析返回体失败");
         } catch (UnsupportedEncodingException e) {
-            Log.info("请求失败4:", e.getMessage());
+            log.info("请求失败4:{}", e.getMessage());
             return ResultContent.buildFail("编码错误");
         }
     }
 
+    /** @Author wjf
+     * @Description //TODO 关闭订单
+     * @Date 2024/7/24
+     * @Param 商户订单号 outTradeNo
+     * @return
+    **/
+    public ResultContent closeOrder(String outTradeNo){
+        Config config = RSAAutoCertificateConfig();
+        // 初始化服务
+        service = new com.wechat.pay.java.service.payments.jsapi.JsapiService.Builder().config(config).build();
+        try {
+            CloseOrderRequest request = new CloseOrderRequest();
+            // 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
+            // 调用接口
+            request.setMchid(WxV3PayConfig.Mch_ID);
+            request.setOutTradeNo(outTradeNo);
+            service.closeOrder(request);
+            return ResultContent.buildSuccess();
+        } catch (HttpException e) { // 发送HTTP请求失败
+            // 调用e.getHttpRequest()获取请求打印日志或上报监控,更多方法见HttpException定义
+            log.info("请求失败1:{}", e.getHttpRequest());
+            return ResultContent.buildFail("发送HTTP请求失败");
+        } catch (ServiceException e) { // 服务返回状态小于200或大于等于300,例如500
+            log.info("请求失败2:{}", e.getResponseBody());
+            return ResultContent.buildFail(e.getErrorMessage());
+        } catch (MalformedMessageException e) { // 服务返回成功,返回体类型不合法,或者解析返回体失败
+            // 调用e.getMessage()获取信息打印日志或上报监控,更多方法见MalformedMessageException定义
+            log.info("请求失败3:{}", e.getMessage());
+            return ResultContent.buildFail("服务返回成功,返回体类型不合法,或者解析返回体失败");
+        }
+    }
+
+    /** @Author wjf
+     * @Description //TODO 商户订单号查询订单
+     * @Date 2024/7/24
+     * @Param 商户订单号 outTradeNo
+     * @return
+     **/
+    public ResultContent<Transaction> queryOrderByOutTradeNo(String outTradeNo){
+        Config config = RSAAutoCertificateConfig();
+        // 初始化服务
+        service = new com.wechat.pay.java.service.payments.jsapi.JsapiService.Builder().config(config).build();
+        try {
+            QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
+            // 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
+            // 调用接口
+            request.setMchid(WxV3PayConfig.Mch_ID);
+            request.setOutTradeNo(outTradeNo);
+            Transaction transaction = service.queryOrderByOutTradeNo(request);
+            return ResultContent.buildSuccess(transaction);
+        } catch (HttpException e) { // 发送HTTP请求失败
+            // 调用e.getHttpRequest()获取请求打印日志或上报监控,更多方法见HttpException定义
+            log.info("请求失败1:{}", e.getHttpRequest());
+            return ResultContent.buildFail("发送HTTP请求失败");
+        } catch (ServiceException e) { // 服务返回状态小于200或大于等于300,例如500
+            log.info("请求失败2:{}", e.getResponseBody());
+            return ResultContent.buildFail(e.getErrorMessage());
+        } catch (MalformedMessageException e) { // 服务返回成功,返回体类型不合法,或者解析返回体失败
+            // 调用e.getMessage()获取信息打印日志或上报监控,更多方法见MalformedMessageException定义
+            log.info("请求失败3:{}", e.getMessage());
+            return ResultContent.buildFail("服务返回成功,返回体类型不合法,或者解析返回体失败");
+        }
+    }
+
+    /** @Author wjf
+     * @Description //TODO 微信支付订单号查询订单
+     * @Date 2024/7/24
+     * @Param 商户订单号 outTradeNo
+     * @return
+     **/
+    public ResultContent queryOrderById(String transactionId){
+        Config config = RSAAutoCertificateConfig();
+        // 初始化服务
+        service = new com.wechat.pay.java.service.payments.jsapi.JsapiService.Builder().config(config).build();
+        try {
+            QueryOrderByIdRequest request = new QueryOrderByIdRequest();
+            // 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
+            // 调用接口
+            request.setMchid(WxV3PayConfig.Mch_ID);
+            request.setTransactionId(transactionId);
+            Transaction transaction = service.queryOrderById(request);
+            return ResultContent.buildSuccess(transaction);
+        } catch (HttpException e) { // 发送HTTP请求失败
+            // 调用e.getHttpRequest()获取请求打印日志或上报监控,更多方法见HttpException定义
+            log.info("请求失败1:{}", e.getHttpRequest());
+            return ResultContent.buildFail("发送HTTP请求失败");
+        } catch (ServiceException e) { // 服务返回状态小于200或大于等于300,例如500
+            log.info("请求失败2:{}", e.getResponseBody());
+            return ResultContent.buildFail(e.getErrorMessage());
+        } catch (MalformedMessageException e) { // 服务返回成功,返回体类型不合法,或者解析返回体失败
+            // 调用e.getMessage()获取信息打印日志或上报监控,更多方法见MalformedMessageException定义
+            log.info("请求失败3:{}", e.getMessage());
+            return ResultContent.buildFail("服务返回成功,返回体类型不合法,或者解析返回体失败");
+        }
+    }
+
+
+
     @SneakyThrows
     public String sign(String privateKeyPath, byte[] message){
         Signature sign = Signature.getInstance("SHA256withRSA");

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

@@ -0,0 +1,74 @@
+package com.zhongshu.payment.server.core.service.wxPaymentV3;
+
+import com.wechat.pay.java.core.Config;
+import com.wechat.pay.java.core.RSAAutoCertificateConfig;
+import com.wechat.pay.java.service.transferbatch.TransferBatchService;
+import com.wechat.pay.java.service.transferbatch.model.*;
+import com.zhongshu.payment.server.core.dataConfig.WxV3PayConfig;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+/**
+ * 微信支付--商家转账到零钱服务
+ * @author wjf
+ * @date 2024/7/24
+ */
+@Slf4j
+@Service
+public class WxTransferBatchService {
+
+    public static TransferBatchService service;
+
+    // 初始化商户配置
+    public  Config RSAAutoCertificateConfig(){
+        return new RSAAutoCertificateConfig.Builder()
+                .merchantId(WxV3PayConfig.Mch_ID)
+                // 使用 com.wechat.pay.java.core.util 中的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名
+                .privateKeyFromPath(WxV3PayConfig.privateKeyPath)
+                .merchantSerialNumber(WxV3PayConfig.mchSerialNo)
+                .apiV3Key(WxV3PayConfig.apiV3Key)
+                .build();
+    }
+
+    /** 发起商家转账 */
+    public InitiateBatchTransferResponse InitiateBatchTransferResponse(InitiateBatchTransferRequest request){
+        Config config = RSAAutoCertificateConfig();
+        // 初始化服务
+        service = new TransferBatchService.Builder().config(config).build();
+        // ... 调用接口
+        return service.initiateBatchTransfer(request);
+    }
+
+    /** 通过微信批次单号查询批次单 */
+    public TransferBatchEntity getTransferBatchByNo(GetTransferBatchByNoRequest request) {
+        Config config = RSAAutoCertificateConfig();
+        // 初始化服务
+        service = new TransferBatchService.Builder().config(config).build();
+        return service.getTransferBatchByNo(request);
+    }
+
+    /** 通过商家批次单号查询批次单 */
+    public TransferBatchEntity getTransferBatchByOutNo(GetTransferBatchByOutNoRequest request) {
+        Config config = RSAAutoCertificateConfig();
+        // 初始化服务
+        service = new TransferBatchService.Builder().config(config).build();
+        return service.getTransferBatchByOutNo(request);
+    }
+
+    /** 通过微信明细单号查询明细单 */
+    public TransferDetailEntity getTransferDetailByNo(GetTransferDetailByNoRequest request) {
+        Config config = RSAAutoCertificateConfig();
+        // 初始化服务
+        service = new TransferBatchService.Builder().config(config).build();
+        return service.getTransferDetailByNo(request);
+    }
+
+    /** 通过商家明细单号查询明细单 */
+    public TransferDetailEntity getTransferDetailByOutNo(GetTransferDetailByOutNoRequest request) {
+        Config config = RSAAutoCertificateConfig();
+        // 初始化服务
+        service = new TransferBatchService.Builder().config(config).build();
+        return service.getTransferDetailByOutNo(request);
+    }
+
+}

+ 78 - 0
PaymentServer/src/main/java/com/zhongshu/payment/server/core/utils/BeanUtils.java

@@ -0,0 +1,78 @@
+package com.zhongshu.payment.server.core.utils;
+
+import org.springframework.beans.FatalBeanException;
+import org.springframework.cglib.beans.BeanMap;
+
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.springframework.beans.BeanUtils.getPropertyDescriptor;
+import static org.springframework.beans.BeanUtils.getPropertyDescriptors;
+
+
+/**
+ * @author wjf
+ * @date 2024/7/25
+ */
+public class BeanUtils {
+    /**
+     * 将对象属性转化为map结合
+     */
+    public static <T> Map<String, Object> beanToMap(T bean) {
+        Map<String, Object> map = new HashMap<>();
+        if (bean != null) {
+            BeanMap beanMap = BeanMap.create(bean);
+            for (Object key : beanMap.keySet()) {
+                map.put(key+"", beanMap.get(key));
+            }
+        }
+        return map;
+    }
+
+    public static void copyPropertiesWithoutNull(Object source, Object target) {
+        if(source == null || target == null){
+            return;
+        }
+        Class<?> actualEditable = target.getClass();
+        Class<?> sourceClass = source.getClass();
+        PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
+        for (PropertyDescriptor targetPd : targetPds) {
+            if(targetPd.getWriteMethod() == null) {
+                continue;
+            }
+            PropertyDescriptor sourcePd = getPropertyDescriptor(sourceClass, targetPd.getName());
+            if(sourcePd == null || sourcePd.getReadMethod() == null) {
+                continue;
+            }
+            try {
+                Method readMethod = sourcePd.getReadMethod();
+                if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
+                    readMethod.setAccessible(true);
+                }
+                Object value = readMethod.invoke(source);
+                setValue(target, targetPd, value);
+            } catch (Exception ex) {
+                throw new FatalBeanException("Could not copy properties from source to target", ex);
+            }
+        }
+    }
+
+    private static void setValue(Object target, PropertyDescriptor targetPd, Object value) throws IllegalAccessException, InvocationTargetException {
+        // 这里判断以下value是否为空
+        if ("".equals(value)){
+            value = null;
+        }
+        if (value != null) {
+            Method writeMethod = targetPd.getWriteMethod();
+            if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
+                writeMethod.setAccessible(true);
+            }
+            writeMethod.invoke(target, value);
+        }
+    }
+
+}

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

@@ -73,6 +73,8 @@ public class DateUtils {
 
     public final static String patternMM = "MM";
 
+    public final static String patternWx  = "yyyy-MM-dd'T'HH:mm:ssXXX";
+
     public static String paresTime(Long time, String pattern) {
         if (time == null || time <= 0) {
             return "";
@@ -716,6 +718,7 @@ public class DateUtils {
     }
 
     public static void main(String[] args) {
+        log.info("失效时间:{}",paresTime(System.currentTimeMillis() + 15*60*1000, DateUtils.patternWx));
         log.info("本年开始时间:{},结束时间:{}", paresTime(getYearStartTime(2023), FORMAT_LONG), paresTime(getYearEndTime(2023), FORMAT_LONG));
         log.info("本月开始时间:{},结束时间:{}", paresTime(getMonthStartTime(2023, 9), FORMAT_LONG), paresTime(getMonthEndTime(2023, 9), FORMAT_LONG));