浏览代码

充值流程

wujiefeng 1 年之前
父节点
当前提交
5201065bb3
共有 29 个文件被更改,包括 749 次插入69 次删除
  1. 23 0
      PaymentClient/src/main/java/com/zhongshu/payment/client/model/RechargeRecordModel.java
  2. 16 0
      PaymentClient/src/main/java/com/zhongshu/payment/client/model/TotalStatisticsModel.java
  3. 20 0
      PaymentClient/src/main/java/com/zhongshu/payment/client/model/TransferModel.java
  4. 6 0
      PaymentClient/src/main/java/com/zhongshu/payment/client/model/WalletModel.java
  5. 15 0
      PaymentClient/src/main/java/com/zhongshu/payment/client/model/param/ExamineParam.java
  6. 3 3
      PaymentClient/src/main/java/com/zhongshu/payment/client/model/param/GetWalletParam.java
  7. 3 0
      PaymentClient/src/main/java/com/zhongshu/payment/client/model/param/OrderParam.java
  8. 5 2
      PaymentClient/src/main/java/com/zhongshu/payment/client/model/param/RechargeParam.java
  9. 36 0
      PaymentClient/src/main/java/com/zhongshu/payment/client/model/param/TransferSearchParam.java
  10. 1 1
      PaymentClient/src/main/java/com/zhongshu/payment/client/types/PaymentType.java
  11. 12 1
      PaymentClient/src/main/java/com/zhongshu/payment/client/types/RechargeState.java
  12. 2 0
      PaymentClient/src/main/java/com/zhongshu/payment/client/types/TradeType.java
  13. 2 2
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/controller/RechargeController.java
  14. 63 0
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/controller/TransferController.java
  15. 1 1
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/controller/WalletController.java
  16. 13 17
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/controller/test/TestController.java
  17. 4 0
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/dao/RechargeRecordDao.java
  18. 4 0
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/dao/WalletDao.java
  19. 8 0
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/dao/extend/RechargeRecordDaoExtend.java
  20. 83 2
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/dao/impl/RechargeRecordDaoImpl.java
  21. 21 3
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/domain/wallet/RechargeRecord.java
  22. 40 14
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/service/RechargeService.java
  23. 255 0
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/service/TransferService.java
  24. 35 1
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/service/impl/WalletFeignServiceImpl.java
  25. 41 4
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/service/wallet/WalletService.java
  26. 16 1
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/service/wxPaymentV3/WxPayNotifyService.java
  27. 4 1
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/service/wxPaymentV3/WxPaymentService.java
  28. 16 16
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/service/wxPaymentV3/WxTransferBatchService.java
  29. 1 0
      PaymentServer/src/main/java/com/zhongshu/payment/server/core/utils/DateUtils.java

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

@@ -1,7 +1,9 @@
 package com.zhongshu.payment.client.model;
 
+
 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;
 
@@ -12,6 +14,12 @@ import lombok.Data;
 @Data
 public class RechargeRecordModel {
 
+    private String id;
+
+    private Long createTime;
+
+    private Long updateTime;
+
     @Schema(name = "oid", description = "项目id")
     private String oid;
 
@@ -35,4 +43,19 @@ public class RechargeRecordModel {
 
     @Schema(name = "tradeTime", description = "交易时间")
     private Long tradeTime;
+
+    @Schema(name = "prePayModel", description = "调用微信支付参数")
+    private PrePayModel prePayModel;
+
+    @Schema(name = "tradeType", description = "交易类型")
+    private TradeType tradeType;
+
+    @Schema(name = "failReason", description = "失败原因")
+    private String failReason;
+
+    private Object userInfo;
+
+    private TransferModel transferModel;
+
+    private String remark;
 }

+ 16 - 0
PaymentClient/src/main/java/com/zhongshu/payment/client/model/TotalStatisticsModel.java

@@ -0,0 +1,16 @@
+package com.zhongshu.payment.client.model;
+
+import lombok.Data;
+
+/**
+ * @author wjf
+ * @date 2024/7/31
+ */
+
+@Data
+public class TotalStatisticsModel {
+
+    private String tradeType;
+
+    private Integer totalAmount;
+}

+ 20 - 0
PaymentClient/src/main/java/com/zhongshu/payment/client/model/TransferModel.java

@@ -0,0 +1,20 @@
+package com.zhongshu.payment.client.model;
+
+import lombok.Data;
+
+/**
+ * @author wjf
+ * @date 2024/7/30
+ */
+@Data
+public class TransferModel {
+
+
+    private String outBatchNo;
+
+    private String batchId;
+
+    private String createTime;
+
+    private String batchStatus;
+}

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

@@ -14,6 +14,12 @@ import java.math.BigDecimal;
 @Data
 public class WalletModel {
 
+    private String id;
+
+    private Long createTime;
+
+    private Long updateTime;
+
     @Schema(description = "项目id")
     private String oid;
 

+ 15 - 0
PaymentClient/src/main/java/com/zhongshu/payment/client/model/param/ExamineParam.java

@@ -0,0 +1,15 @@
+package com.zhongshu.payment.client.model.param;
+
+import lombok.Data;
+
+/**
+ * @author wjf
+ * @date 2024/7/31
+ */
+@Data
+public class ExamineParam {
+
+    private String outTradeNo;
+
+    private String remark;
+}

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

@@ -11,9 +11,9 @@ import lombok.Data;
 @Data
 public class GetWalletParam {
 
-    @Schema(name = "oid", description = "机构id")
-    private String oid;
+    @Schema(name = "appid", description = "小程序appid")
+    private String appid;
 
-    @Schema(name = "walletType", description = "钱包类型:Shop, User")
+    @Schema(name = "walletType", description = "钱包类型:Shop, User", example = "User")
     private WalletType walletType;
 }

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

@@ -16,4 +16,7 @@ public class OrderParam {
 
     @Schema(name = "jscode", description = "微信用户授权码", example = "123456")
     private String jscode;
+
+    @Schema(name = "appid", description = "appid", example = "123456")
+    private String appid;
 }

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

@@ -14,9 +14,12 @@ public class RechargeParam {
     @Schema(name = "oid", description = "项目id",required = true, example = "")
     private String oid;
 
-    @Schema(name = "oid", description = "学校id",required = true, example = "")
+    @Schema(name = "schoolId", description = "学校id",required = true, example = "")
     private String schoolId;
 
+    @Schema(name = "appid", description = "appid")
+    private String appid;
+
     @Schema(name = "walletId", description = "钱包id",required = true, example = "")
     private String walletId;
 
@@ -28,7 +31,7 @@ public class RechargeParam {
     private String description;
 
     // 订单金额(必填)
-    @Schema(name = "amount", description = "订单金额",required = true, example = "{\"total\":1,\"currency\":\"CNY\"}")
+    @Schema(name = "total", description = "订单金额",required = true, example = "")
     private Integer total;
 
 //    @Schema(name = "jscode", description = "微信用户授权码", example = "123456")

+ 36 - 0
PaymentClient/src/main/java/com/zhongshu/payment/client/model/param/TransferSearchParam.java

@@ -0,0 +1,36 @@
+package com.zhongshu.payment.client.model.param;
+
+import com.zhongshu.payment.client.types.RechargeState;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+/**
+ * @author wjf
+ * @date 2024/7/31
+ */
+@Data
+public class TransferSearchParam {
+
+    @Schema(description = "项目id")
+    private String oid;
+
+    @Schema(description = "部门id")
+    private String departmentId;
+
+    @Schema(description = "用户id")
+    private String userId;
+
+    @Schema(description = "商户id")
+    private String shopId;
+
+    @Schema(description = "支付状态")
+    private RechargeState rechargeState;
+
+    @Schema(description = "订单号")
+    private String outTradeNo;
+
+    @Schema(description = "人员编号")
+    private String userCode;
+
+    private String schoolId;
+}

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

@@ -3,7 +3,7 @@ package com.zhongshu.payment.client.types;
 import lombok.Getter;
 
 public enum PaymentType {
-    Wechat("微信"),
+    WeChat("微信"),
     UnionPay("银联"),
 
     ;

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

@@ -13,9 +13,20 @@ public enum RechargeState {
     NOTPAY("未支付"),
     RECHARGING("充值中"),
     CLOSED("已关闭"),
+
     REVOKED(":已撤销(付款码支付)"),
     USERPAYING("用户支付中(付款码支付)"),
-    PAYERROR("支付失败(其他原因,如银行返回失败)")
+    PAYERROR("支付失败(其他原因,如银行返回失败)"),
+
+    TakeReview("提现审核中"),
+    Taking("提现处理中"),
+    TakeSuccess("提现成功"),
+
+    TakeRefuse("提现审批不通过"),
+
+    TakeFail("提现失败"),
+
+
     ;
 
     @Getter

+ 2 - 0
PaymentClient/src/main/java/com/zhongshu/payment/client/types/TradeType.java

@@ -15,6 +15,8 @@ public enum TradeType {
     Frozen("冻结"),
     CancelFrozen("取消冻结"),
     Take("提现"),
+
+    TakeReturn("提现退还"),
     Charge("充值")
     ;
 

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

@@ -62,7 +62,7 @@ public class RechargeController {
     /** 查询充值订单详情 */
     @Operation(summary = "查询充值订单详情", description = "查询充值订单详情")
     @GetMapping(value = "queryInfoById")
-    public Object queryInfoById(@RequestParam("outTradeNo") String id){
-        return rechargeService.queryInfoById(id);
+    public Object queryInfoById(@RequestParam("outTradeNo") String outTradeNo){
+        return rechargeService.queryInfoById(outTradeNo);
     }
 }

+ 63 - 0
PaymentServer/src/main/java/com/zhongshu/payment/server/core/controller/TransferController.java

@@ -0,0 +1,63 @@
+package com.zhongshu.payment.server.core.controller;
+
+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.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.*;
+
+/**
+ * 提现
+ * @author wjf
+ * @date 2024/7/30
+ */
+@Slf4j
+@RestController
+@RequestMapping("/transfer")
+@Tag(name = "用户提现")
+public class TransferController {
+
+    @Autowired
+    TransferService transferService;
+
+
+    @Operation(summary = "创建提现订单", description = "创建提现订单")
+    @PostMapping(value = "create", consumes = MediaType.APPLICATION_JSON_VALUE)
+    public Object create(@RequestBody RechargeParam param){
+        return transferService.create(param);
+    }
+
+
+    @Operation(summary = "通过提现审批", description = "创建提现订单")
+    @PostMapping(value = "passTransfer", consumes = MediaType.APPLICATION_JSON_VALUE)
+    public Object passTransfer(@RequestBody ExamineParam param){
+        return transferService.passTransfer(param);
+    }
+
+    @Operation(summary = "拒绝提现审批", description = "创建提现订单")
+    @PostMapping(value = "refuseTransfer", consumes = MediaType.APPLICATION_JSON_VALUE)
+    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 = "获取提现转账状态")
+    @GetMapping(value = "getTransferState")
+    public Object getTransferState(String outTradeNo){
+        return transferService.getTransferState(outTradeNo);
+    }
+}

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

@@ -32,6 +32,6 @@ public class WalletController {
     @Operation(summary = "获取(开通)当前用户钱包信息", description = "获取(开通)当前用户钱包信息")
     @PostMapping("getWallet")
     public Object getWalletByUser(@RequestBody GetWalletParam param){
-        return walletService.getWalletByUser(param.getOid(), param.getWalletType(), null);
+        return walletService.getWalletByUser(param.getAppid(), param.getWalletType(), null);
     }
 }

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

@@ -1,11 +1,8 @@
 package com.zhongshu.payment.server.core.controller.test;
 
-import com.zhongshu.card.client.model.feign.ProjectWxPayModel;
-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.card.client.service.ProjectPaySettingService;
+import com.zhongshu.payment.server.core.dao.RechargeRecordDao;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import org.slf4j.Logger;
@@ -15,9 +12,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RestController;
 
-import java.io.File;
-import java.util.UUID;
-
 @RestController
 @RequestMapping("test")
 @Tag(name = "测试")
@@ -28,19 +22,21 @@ public class TestController {
     @Autowired
     ProjectPaySettingFeignService projectPaySettingService;
 
+    @Autowired
+    RechargeRecordDao rechargeRecordDao;
+
     @Operation(summary = "测试接口", description = "测试接口")
     @RequestMapping(value = "text", method = {RequestMethod.GET})
     public ResultContent text() {
-        ProjectWxPayParam param = new ProjectWxPayParam();
-        param.setAppId("wx92ae04fb0f325887");
-        ResultContent<WxPayConfigModel> content = projectPaySettingService.getProjectWxPayConfig(param);
-        WxPayConfigModel model = content.getContent();
-
-        String path = Thread.currentThread().getContextClassLoader().getResource("").getPath() + "apiclientkey/apiclient_key_1680033836.pem";
-        log.info("path: {}", path);
-        File file = new File(path);
-        log.info("file: {}", file.getAbsolutePath());
-        return ResultContent.buildSuccess(model);
+//        SendMessageModel sendMessageModel = new SendMessageModel();
+//        sendMessageModel.setMessage(JsonUtil.toJson(Map.of("status", 1, "outTradeNo", 1)));
+//
+//        String topic = String.format("/wechat/pay/%s", "665fc0389083d203896d3541");
+//        sendMessageModel.setTopic(topic);
+//        sendMessageModel.setUserId("665fc0389083d203896d3541");
+
+
+        return ResultContent.buildContent(rechargeRecordDao.getTotalAmountByTradeType("66a749a66f75da30730658c7"));
     }
 
 

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

@@ -4,6 +4,8 @@ import com.github.microservice.components.data.mongo.mongo.dao.MongoDao;
 import com.zhongshu.payment.server.core.dao.extend.RechargeRecordDaoExtend;
 import com.zhongshu.payment.server.core.domain.wallet.RechargeRecord;
 
+import java.util.List;
+
 /**
  * @author wjf
  * @date 2024/7/25
@@ -12,5 +14,7 @@ public interface RechargeRecordDao extends MongoDao<RechargeRecord>, RechargeRec
 
     RechargeRecord findByOutTradeNo(String outTradeNo);
 
+    List<RechargeRecord> findByOutTradeNoIn(List<String> outTradeNo);
+
     RechargeRecord findTop1ById(String id);
 }

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

@@ -3,6 +3,8 @@ 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;
 
+import java.util.List;
+
 /**
  * @author wjf
  * @date 2024/7/25
@@ -15,4 +17,6 @@ public interface WalletDao extends MongoDao<Wallet> {
 
     Wallet findTop1ById(String id);
 
+    List<Wallet> findByIdIn(List<String> idList);
+
 }

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

@@ -1,7 +1,11 @@
 package com.zhongshu.payment.server.core.dao.extend;
 
+import com.zhongshu.payment.client.model.TotalStatisticsModel;
+import com.zhongshu.payment.client.model.param.TransferSearchParam;
 import com.zhongshu.payment.server.core.domain.wallet.RechargeRecord;
 import com.zhongshu.payment.server.core.domain.wallet.Wallet;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
 
 import java.util.List;
 
@@ -12,4 +16,8 @@ import java.util.List;
 public interface RechargeRecordDaoExtend {
 
     List<RechargeRecord> ListByWallet(Wallet wallet, Long startTime, Long endTime);
+
+    Page<RechargeRecord> pageTransfer(Pageable pageable, TransferSearchParam param);
+
+    public List<TotalStatisticsModel> getTotalAmountByTradeType(String walletId);
 }

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

@@ -1,22 +1,35 @@
 package com.zhongshu.payment.server.core.dao.impl;
 
+import ch.qos.logback.core.util.StringUtil;
 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.types.RechargeState;
 import com.zhongshu.payment.server.core.dao.extend.RechargeRecordDaoExtend;
 import com.zhongshu.payment.server.core.domain.wallet.RechargeRecord;
 import com.zhongshu.payment.server.core.domain.wallet.Wallet;
 import com.zhongshu.payment.server.core.utils.CommonUtil;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.ObjectUtils;
+import org.bson.types.ObjectId;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
 import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.aggregation.Aggregation;
+import org.springframework.data.mongodb.core.aggregation.AggregationResults;
 import org.springframework.data.mongodb.core.query.Criteria;
 import org.springframework.data.mongodb.core.query.Query;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
  * @author wjf
  * @date 2024/7/26
  */
+@Slf4j
 public class RechargeRecordDaoImpl implements RechargeRecordDaoExtend {
 
     @Autowired
@@ -30,7 +43,7 @@ public class RechargeRecordDaoImpl implements RechargeRecordDaoExtend {
         Criteria criteria = new Criteria();
 
         if (ObjectUtils.isNotEmpty(wallet)){
-            criteria.and("wallet").is(wallet);
+            criteria.and("wallet._id").is(wallet.getId());
         }
 
         if (!CommonUtil.longIsEmpty(startTime)){
@@ -41,6 +54,74 @@ public class RechargeRecordDaoImpl implements RechargeRecordDaoExtend {
             criteria.and("createTime").lte(endTime);
         }
 
-        return mongoTemplate.find(Query.query(criteria), RechargeRecord.class);
+        Query query = Query.query(criteria);
+        query.with(Sort.by(Sort.Order.desc("createTime")));
+
+        return mongoTemplate.find(query, RechargeRecord.class);
+    }
+
+    @Override
+    public Page<RechargeRecord> pageTransfer(Pageable pageable, TransferSearchParam param) {
+        Criteria criteria = new Criteria();
+        //筛选条件
+        //部门
+        if (StringUtil.notNullNorEmpty(param.getDepartmentId())){
+            criteria.and("userInfo.department.id").is(param.getDepartmentId());
+        }
+        //人员
+        if (StringUtil.notNullNorEmpty(param.getUserId())){
+            criteria.and("userId").is(param.getUserId());
+        }
+        //商户
+
+        //支付状态
+        if (param.getRechargeState()!=null){
+
+        }
+
+        //订单号
+        if (StringUtil.notNullNorEmpty(param.getOutTradeNo())){
+            criteria.and("outTradeNo").is(param.getOutTradeNo());
+        }
+        //人员编号
+        if (StringUtil.notNullNorEmpty(param.getOutTradeNo())){
+            criteria.and("userInfo.code").is(param.getUserCode());
+        }
+        if (StringUtil.notNullNorEmpty(param.getOid())){
+            criteria.and("oid").is(param.getOid());
+        }
+
+        if (StringUtil.notNullNorEmpty(param.getOid())){
+            criteria.and("schoolId").is(param.getSchoolId());
+        }
+        Query query = Query.query(criteria);
+        query.with(Sort.by(Sort.Order.desc("createTime")));
+        return dbHelper.pages(query, pageable, RechargeRecord.class);
+    }
+
+    public List<TotalStatisticsModel> getTotalAmountByTradeType(String walletId){
+        Criteria criteria = new  Criteria();
+
+        if (StringUtil.notNullNorEmpty(walletId)){
+            criteria.and("wallet._id").is(new ObjectId(walletId));
+        }
+        criteria.and("rechargeState").in(List.of(RechargeState.SUCCESS, RechargeState.TakeSuccess));
+        Aggregation aggregation = Aggregation.newAggregation(
+                Aggregation.match(criteria),
+                Aggregation.project("tradeType","amountTotal"),
+                Aggregation.group("tradeType").sum("total").as("amountTotal")
+                );
+
+
+        log.info("聚合查询{}\n{}",aggregation.getOptions(), aggregation.getPipeline());
+        Query query =Query.query(criteria);
+
+        AggregationResults<TotalStatisticsModel> groupList = mongoTemplate.aggregate(aggregation, TotalStatisticsModel.class, TotalStatisticsModel.class);
+        List<TotalStatisticsModel> list = new ArrayList<>();
+
+        for (TotalStatisticsModel object : groupList){
+            list.add(object);
+        }
+        return list;
     }
 }

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

@@ -1,9 +1,12 @@
 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.model.PrePayModel;
+import com.zhongshu.payment.client.model.TransferModel;
 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;
 import org.springframework.data.mongodb.core.mapping.Document;
@@ -28,6 +31,9 @@ public class RechargeRecord extends SuperEntity {
     @Schema(name = "schoolId", description = "学校id")
     private String schoolId;
 
+    @Schema(name = "appid", description = "appid")
+    private String appid;
+
     @Schema(name = "钱包信息", description = "钱包信息")
     private Wallet wallet;
 
@@ -46,13 +52,25 @@ public class RechargeRecord extends SuperEntity {
     @Schema(name = "rechargeState", description = "订单状态")
     private RechargeState rechargeState;
 
+    @Schema(name = "rechargeStateDesc", description = "订单状态描述")
+    private String rechargeStateDesc;
+
     @Schema(name = "tradeTime", description = "交易时间")
     private Long tradeTime;
 
-    @Schema(name = "prePayModel", description = "交易时间")
+    @Schema(name = "prePayModel", description = "调用微信支付参数")
     private PrePayModel prePayModel;
 
-    private Integer createMonth;
+    @Schema(name = "tradeType", description = "交易类型")
+    private TradeType tradeType;
+
+    @Schema(name = "failReason", description = "失败原因")
+    private String failReason;
+
+    private TransferModel transferModel;
+
+    private OrganizationUserModel userInfo;
+
+    private String remark;
 
-    private Integer createYear;
 }

+ 40 - 14
PaymentServer/src/main/java/com/zhongshu/payment/server/core/service/RechargeService.java

@@ -7,8 +7,11 @@ 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.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.model.wechat.MiniAppUserInfoVo;
+import com.zhongshu.card.client.service.OrganizationFeignService;
 import com.zhongshu.card.client.service.ProjectPaySettingFeignService;
 import com.zhongshu.payment.client.model.PrePayModel;
 import com.zhongshu.payment.client.model.RechargeRecordModel;
@@ -16,23 +19,24 @@ 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.client.types.TradeType;
 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.domain.wechatPay.WxPayConfig;
 import com.zhongshu.payment.server.core.service.impl.WalletFeignServiceImpl;
 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.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
 import java.math.BigDecimal;
 import java.util.List;
@@ -70,8 +74,12 @@ public class RechargeService {
     @Autowired
     ProjectPaySettingFeignService paySettingFeignService;
 
+    @Autowired
+    OrganizationFeignService organizationFeignService;
+
     /** 创建充值订单 */
     public Object create(RechargeParam param){
+        String userId = authHelper.getCurrentUser().getUserId();
         Wallet userWallet = walletDao.findTop1ById(param.getWalletId());
         //判断钱包是否初始化
         if (userWallet==null){
@@ -79,11 +87,22 @@ public class RechargeService {
         }
 
         RechargeRecord rechargeRecord = new RechargeRecord();
-        BeanUtils.copyPropertiesWithoutNull(param, rechargeRecord);
+        org.springframework.beans.BeanUtils.copyProperties(param, rechargeRecord, "total");
         String outTradeNo = CommonUtil.UUID();
         rechargeRecord.setOutTradeNo(outTradeNo);
         rechargeRecord.setTotal(BigDecimal.valueOf(param.getTotal()));
+        rechargeRecord.setOid(userWallet.getOid());
+        rechargeRecord.setTradeType(TradeType.Charge);
+        rechargeRecord.setUserId(userId);
 
+        OrgUserDetailParam orgUserDetailParam = new OrgUserDetailParam();
+        orgUserDetailParam.setOid(userWallet.getOid());
+        orgUserDetailParam.setUserId(userWallet.getUserId());
+        com.zhongshu.card.client.ret.ResultContent<OrganizationUserModel> orgUserDetail = organizationFeignService.getOrgUserDetail(orgUserDetailParam);
+        if (orgUserDetail.isFailed()){
+            return ResultContent.buildFail("获取用户信息失败");
+        }
+        rechargeRecord.setUserInfo(orgUserDetail.getContent());
         rechargeRecord.setRechargeState(RechargeState.NOTPAY);
         rechargeRecord.setWallet(userWallet);
         RechargeRecord record = rechargeRecordDao.save(rechargeRecord);
@@ -94,13 +113,16 @@ public class RechargeService {
     private RechargeRecordModel toModel(RechargeRecord record) {
         RechargeRecordModel model = new RechargeRecordModel();
         if (record!=null){
-            BeanUtils.copyPropertiesWithoutNull(record, model);
+            BeanUtils.copyProperties(record, model, "total");
             model.setTotal(record.getTotal().intValue());
+            model.setPrePayModel(record.getPrePayModel());
+            model.setUserInfo(record.getUserInfo());
         }
         return model;
     }
 
     /** 下单 */
+    @Transactional
     public Object order(OrderParam param){
         RechargeRecord record = rechargeRecordDao.findByOutTradeNo(param.getOutTradeNo());
         if (record==null){
@@ -121,19 +143,17 @@ public class RechargeService {
         walletDao.save(userWallet);
 
         //判断微信支付配置
-        WxPayConfig config = wxPayConfigDao.findByOid(record.getOid());
+//        WxPayConfig config = wxPayConfigDao.findByOid(record.getOid());
         //调用微信支付--下单接口
         PrepayRequest request = new PrepayRequest();
-        request.setMchid(config.getMchId());
-        request.setAppid(config.getAppid());
-        request.setNotifyUrl(config.getNotifyUrl());
+//        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);
+        request.setOutTradeNo(param.getOutTradeNo());
         //设置交易失效时间,15分钟
         request.setTimeExpire(DateUtils.paresTime(System.currentTimeMillis() + 15*60*1000, DateUtils.patternWx));
         Payer payer = new Payer();
@@ -141,7 +161,7 @@ public class RechargeService {
         request.setPayer(payer);
 
         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("获取微信支付配置失败");
@@ -151,6 +171,7 @@ public class RechargeService {
             return prepayResult;
         }
         record.setPrePayModel(prepayResult.getContent());
+        record.setRechargeState(RechargeState.RECHARGING);
         rechargeRecordDao.save(record);
         return prepayResult;
     }
@@ -201,6 +222,11 @@ public class RechargeService {
         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));
+        }
         record.setRechargeState(RechargeState.CLOSED);
         rechargeRecordDao.save(record);
         return wxPaymentService.closeOrder(outTradeNo, paySetResult.getContent());
@@ -223,8 +249,8 @@ public class RechargeService {
     }
 
     /** 查询充值订单详情 */
-    public Object queryInfoById(String id){
-        RechargeRecord record = rechargeRecordDao.findByOutTradeNo(id);
+    public Object queryInfoById(String outTradeNo){
+        RechargeRecord record = rechargeRecordDao.findByOutTradeNo(outTradeNo);
         return ResultContent.buildSuccess(toModel(record));
     }
 

+ 255 - 0
PaymentServer/src/main/java/com/zhongshu/payment/server/core/service/TransferService.java

@@ -0,0 +1,255 @@
+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;
+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.RechargeRecordModel;
+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.RechargeState;
+import com.zhongshu.payment.client.types.TradeType;
+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;
+import com.zhongshu.payment.server.core.domain.wallet.Wallet;
+import com.zhongshu.payment.server.core.service.impl.WalletFeignServiceImpl;
+import com.zhongshu.payment.server.core.service.wxPaymentV3.WxTransferBatchService;
+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;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * 提现
+ * @author wjf
+ * @date 2024/7/29
+ */
+@Service
+public class TransferService {
+
+    @Autowired
+    WalletDao walletDao;
+
+    @Autowired
+    RechargeRecordDao rechargeRecordDao;
+
+    @Autowired
+    WxTransferBatchService wxTransferBatchService;
+
+    @Autowired
+    ProjectPaySettingFeignService paySettingFeignService;
+
+    @Autowired
+    WalletFeignServiceImpl walletFeignService;
+
+    @Autowired
+    AuthHelper authHelper;
+
+    @Autowired
+    OrganizationFeignService organizationFeignService;
+
+    /** 发起提现 */
+    @Transactional
+    public Object create(RechargeParam param){
+        String userId = authHelper.getCurrentUser().getUserId();
+        Wallet userWallet = walletDao.findTop1ById(param.getWalletId());
+        //判断钱包是否初始化
+        if (userWallet==null){
+            return ResultContent.buildFail("用户钱包未开通");
+        }
+
+        RechargeRecord rechargeRecord = new RechargeRecord();
+        org.springframework.beans.BeanUtils.copyProperties(param, rechargeRecord, "total");
+        String outTradeNo = CommonUtil.UUID();
+        rechargeRecord.setOutTradeNo(outTradeNo);
+        rechargeRecord.setTotal(BigDecimal.valueOf(param.getTotal()));
+        rechargeRecord.setOid(userWallet.getOid());
+        rechargeRecord.setTradeType(TradeType.Take);
+        rechargeRecord.setRechargeState(RechargeState.TakeReview);
+        rechargeRecord.setWallet(userWallet);
+        rechargeRecord.setUserId(userId);
+        //设置人员信息
+        OrgUserDetailParam orgUserDetailParam = new OrgUserDetailParam();
+        orgUserDetailParam.setOid(userWallet.getOid());
+        orgUserDetailParam.setUserId(userWallet.getUserId());
+        com.zhongshu.card.client.ret.ResultContent<OrganizationUserModel> orgUserDetail = organizationFeignService.getOrgUserDetail(orgUserDetailParam);
+        if (orgUserDetail.isFailed()){
+            return ResultContent.buildFail("获取用户信息失败");
+        }
+        rechargeRecord.setUserInfo(orgUserDetail.getContent());
+
+        AmountUpdateParam amountUpdateParam = new AmountUpdateParam();
+        amountUpdateParam.setOutTradeNo(rechargeRecord.getOutTradeNo());
+        amountUpdateParam.setOid(rechargeRecord.getOid());
+        amountUpdateParam.setUserId(userId);
+        amountUpdateParam.setTotal(rechargeRecord.getTotal());
+        amountUpdateParam.setSchoolId(rechargeRecord.getSchoolId());
+        walletFeignService.commitTake(amountUpdateParam);
+
+        RechargeRecord record = rechargeRecordDao.save(rechargeRecord);
+        return ResultContent.buildSuccess(toModel(record));
+    }
+
+    @Transactional
+    public Object passTransfer(ExamineParam param){
+        RechargeRecord record = rechargeRecordDao.findByOutTradeNo(param.getOutTradeNo());
+        if (record==null){
+            return ResultContent.buildFail("充值订单:"+param.getOutTradeNo()+"不存在");
+        }
+        Wallet userWallet = walletDao.findTop1ById(record.getWallet().getId());
+
+        //判断微信支付配置
+        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("获取微信支付配置失败");
+        }
+
+        if (StringUtil.isNullOrEmpty(param.getRemark())){
+            param.setRemark("余额提现");
+        }
+
+        InitiateBatchTransferRequest request = new InitiateBatchTransferRequest();
+        request.setAppid(record.getAppid());
+
+        request.setOutBatchNo(record.getId());
+        request.setBatchRemark(param.getRemark());
+        request.setTotalAmount(record.getTotal().longValue());
+        request.setTotalNum(1);
+
+        TransferDetailInput transferDetailInput = new TransferDetailInput();
+        transferDetailInput.setOpenid(userWallet.getOpenid());
+        transferDetailInput.setOutDetailNo(record.getOutTradeNo());
+        transferDetailInput.setTransferAmount(record.getTotal().longValue());
+        transferDetailInput.setTransferRemark(param.getRemark());
+        if(record.getTotal().compareTo(BigDecimal.valueOf(2000L))>=0){
+            //获取用户信息
+            transferDetailInput.setUserName("用户名");
+        }
+        if (record.getTotal().compareTo(BigDecimal.valueOf(0.3))<0){
+            transferDetailInput.setUserName(null);
+        }
+        request.setTransferDetailList(List.of(transferDetailInput));
+        //设置转账场景id
+        request.setTransferSceneId("");
+
+        InitiateBatchTransferResponse initiateBatchTransferResponse = wxTransferBatchService.InitiateBatchTransferResponse(request, paySetResult.getContent());
+        TransferModel transferModel = new TransferModel();
+        BeanUtils.copyProperties(initiateBatchTransferResponse, transferModel);
+        record.setTransferModel(transferModel);
+        if (initiateBatchTransferResponse.getBatchStatus().equals("ACCEPTED")){
+            record.setRechargeState(RechargeState.RECHARGING);
+        }
+        if (initiateBatchTransferResponse.getBatchStatus().equals("PROCESSING")){
+            record.setRechargeState(RechargeState.Taking);
+        }
+        if (initiateBatchTransferResponse.getBatchStatus().equals("FINISHED")){
+            record.setRechargeState(RechargeState.TakeSuccess);
+        }
+        if (initiateBatchTransferResponse.getBatchStatus().equals("CLOSED")){
+            record.setRechargeState(RechargeState.CLOSED);
+        }
+        rechargeRecordDao.save(record);
+        return ResultContent.buildSuccess(record);
+    }
+
+    @Transactional
+    public Object refuseTransfer(ExamineParam param){
+        RechargeRecord record = rechargeRecordDao.findByOutTradeNo(param.getOutTradeNo());
+        if (record==null){
+            return ResultContent.buildFail("充值订单:"+param.getOutTradeNo()+"不存在");
+        }
+        record.setRechargeState(RechargeState.TakeRefuse);
+        record.setRemark(param.getRemark());
+        rechargeRecordDao.save(record);
+
+        AmountUpdateParam amountUpdateParam = new AmountUpdateParam();
+        amountUpdateParam.setOutTradeNo(record.getOutTradeNo());
+        amountUpdateParam.setOid(record.getOid());
+        amountUpdateParam.setUserId(record.getUserId());
+        amountUpdateParam.setTotal(record.getTotal());
+        amountUpdateParam.setSchoolId(record.getSchoolId());
+        walletFeignService.failTake(amountUpdateParam);
+        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){
+        RechargeRecord record = rechargeRecordDao.findByOutTradeNo(outTradeNo);
+
+        ProjectWxPayParam param = new ProjectWxPayParam();
+        param.setAppId(record.getAppid());
+        com.zhongshu.card.client.ret.ResultContent<WxPayConfigModel> configResult = paySettingFeignService.getProjectWxPayConfig(param);
+        if (configResult.isFailed()){
+            return ResultContent.buildFail("获取微信支付配置失败");
+        }
+        GetTransferDetailByOutNoRequest request = new GetTransferDetailByOutNoRequest();
+        request.setOutBatchNo(record.getId());
+        request.setOutDetailNo(record.getOutTradeNo());
+        TransferDetailEntity transferDetailByOutNo = wxTransferBatchService.getTransferDetailByOutNo(request, configResult.getContent());
+        if (transferDetailByOutNo.getDetailStatus().equals("INIT")){
+            record.setRechargeState(RechargeState.Taking);
+            record.setRechargeStateDesc("系统转账校验中");
+        }
+        if (transferDetailByOutNo.getDetailStatus().equals("WAIT_PAY")){
+            record.setRechargeState(RechargeState.Taking);
+            record.setRechargeStateDesc("待商户确认");
+        }
+
+        if (transferDetailByOutNo.getDetailStatus().equals("PROCESSING")){
+            record.setRechargeState(RechargeState.Taking);
+            record.setRechargeStateDesc("正在处理中");
+        }
+        if (transferDetailByOutNo.getDetailStatus().equals("SUCCESS")){
+            record.setRechargeState(RechargeState.TakeSuccess);
+            record.setRechargeStateDesc("提现成功");
+        }
+        if (transferDetailByOutNo.getDetailStatus().equals("FAIL")){
+            record.setRechargeState(RechargeState.TakeFail);
+            record.setRechargeStateDesc(transferDetailByOutNo.getFailReason().name());
+            AmountUpdateParam amountUpdateParam = new AmountUpdateParam();
+            amountUpdateParam.setOutTradeNo(record.getOutTradeNo());
+            amountUpdateParam.setOid(record.getOid());
+            amountUpdateParam.setUserId(record.getUserId());
+            amountUpdateParam.setTotal(record.getTotal());
+            amountUpdateParam.setSchoolId(record.getSchoolId());
+            walletFeignService.failTake(amountUpdateParam);
+        }
+        rechargeRecordDao.save(record);
+        return ResultContent.buildSuccess(toModel(record));
+    }
+
+    private RechargeRecordModel toModel(RechargeRecord record) {
+        RechargeRecordModel model = new RechargeRecordModel();
+        if (record!=null){
+            org.springframework.beans.BeanUtils.copyProperties(record, model, "total");
+            model.setTotal(record.getTotal().intValue());
+            model.setUserInfo(record.getUserInfo());
+        }
+        return model;
+    }
+}

+ 35 - 1
PaymentServer/src/main/java/com/zhongshu/payment/server/core/service/impl/WalletFeignServiceImpl.java

@@ -16,6 +16,7 @@ import com.zhongshu.payment.server.core.utils.BeanUtils;
 import org.jetbrains.annotations.NotNull;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
 import java.math.BigDecimal;
 import java.util.List;
@@ -41,6 +42,7 @@ public class WalletFeignServiceImpl implements WalletFeignService {
     }
 
     @NotNull
+    @Transactional
     private Wallet findWallet(String oid, @NotNull WalletType walletType, String shopId, String userId){
         Wallet wallet = null;
         if (walletType.equals(WalletType.User)){
@@ -67,6 +69,7 @@ public class WalletFeignServiceImpl implements WalletFeignService {
 
     /** 充值 */
     @Override
+    @Transactional
     public ResultContent recharge(AmountUpdateParam param){
         Wallet wallet = findWallet(param.getOid(), WalletType.User, param.getShopId(), param.getUserId());
         wallet.setAmount(wallet.getAmount().add(param.getTotal()));
@@ -78,6 +81,7 @@ public class WalletFeignServiceImpl implements WalletFeignService {
 
     /** 消费 */
     @Override
+    @Transactional
     public ResultContent consume(AmountUpdateParam param){
         Wallet userWallet = findWallet(param.getOid(), WalletType.User, param.getShopId(), param.getUserId());
 
@@ -101,6 +105,7 @@ public class WalletFeignServiceImpl implements WalletFeignService {
     }
 
     /** 发起退款 */
+    @Transactional
     public ResultContent frozen(AmountUpdateParam param){
         Wallet shopWallet = findWallet(param.getOid(), WalletType.Shop, param.getShopId(), param.getUserId());
 
@@ -119,6 +124,7 @@ public class WalletFeignServiceImpl implements WalletFeignService {
     }
 
     /** 退款(审批失败) */
+    @Transactional
     public ResultContent cancelFrozen(AmountUpdateParam param){
         Wallet shopWallet = findWallet(param.getOid(), WalletType.Shop, param.getShopId(), param.getUserId());
         shopWallet.setAmount(shopWallet.getAmount().add(param.getTotal()));
@@ -128,6 +134,7 @@ public class WalletFeignServiceImpl implements WalletFeignService {
     }
 
     /** 退款(审批通过) */
+    @Transactional
     public ResultContent refund(AmountUpdateParam param){
         Wallet shopWallet = findWallet(param.getOid(), WalletType.Shop, param.getShopId(), param.getUserId());
 
@@ -151,10 +158,37 @@ public class WalletFeignServiceImpl implements WalletFeignService {
     }
 
     /** 用户发起提现 */
+    @Transactional
+    public ResultContent commitTake(AmountUpdateParam param){
+        Wallet userWallet = findWallet(param.getOid(), WalletType.User, param.getShopId(), param.getUserId());
+        if (userWallet.getAmount().compareTo(param.getTotal()) < 0 ){
+            return ResultContent.buildFail("可用余额不足");
+        }
+        if (userWallet.getTotalAmount().compareTo(param.getTotal()) < 0 ){
+            return ResultContent.buildFail("总额不足");
+        }
+        userWallet.setAmount(userWallet.getAmount().subtract(param.getTotal()));
+        userWallet.setTotalAmount(userWallet.getTotalAmount().subtract(param.getTotal()));
+        walletDao.save(userWallet);
+        createWalletFlow(userWallet.getId(), param.getTotal(), param.getOutTradeNo(), TradeType.Take, param.getAttach(), param.getSchoolId());
+        return ResultContent.buildSuccess();
+    }
 
     /** 用户提现(审批失败) */
-
+    @Transactional
+    public ResultContent failTake(AmountUpdateParam param){
+        Wallet userWallet = findWallet(param.getOid(), WalletType.User, param.getShopId(), param.getUserId());
+        userWallet.setAmount(userWallet.getAmount().add(param.getTotal()));
+        userWallet.setTotalAmount(userWallet.getTotalAmount().add(param.getTotal()));
+        walletDao.save(userWallet);
+        createWalletFlow(userWallet.getId(), param.getTotal(), param.getOutTradeNo(), TradeType.TakeReturn, param.getAttach(), param.getSchoolId());
+        return ResultContent.buildSuccess();
+    }
     /** 用户提现(审批通过) */
+//    public ResultContent takePass(AmountUpdateParam param){
+//        Wallet userWallet = findWallet(param.getOid(), WalletType.User, param.getShopId(), param.getUserId());
+//        return ResultContent.buildSuccess();
+//    }
 
 //    @Override
 //    public ResultContent addAmount(String walletId, BigDecimal total, String outTradeNo, TradeType type, String attach) {

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

@@ -2,11 +2,19 @@ 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.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;
 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;
@@ -31,6 +39,16 @@ public class WalletService {
     @Autowired
     AuthHelper authHelper;
 
+    @Autowired
+    ProjectPaySettingFeignService paySettingFeignService;
+
+    @Autowired
+    OrganizationFeignService organizationFeignService;
+
+    @Autowired
+    RechargeRecordDao rechargeRecordDao;
+
+
     /** 获取钱包微信授权状态 */
     public Object getWeChatAuthState(String walletId){
         Wallet wallet = walletDao.findTop1ById(walletId);
@@ -38,15 +56,24 @@ public class WalletService {
             return ResultContent.buildFail("钱包未开通");
         }
         if (StringUtil.isNullOrEmpty(wallet.getOpenid())){
-            return ResultContent.build(ResultState.NOT_WECHAT_AUTH);
+            return ResultContent.buildContent(ResultState.NOT_WECHAT_AUTH);
         }
         return ResultContent.buildSuccess();
     }
 
     /** 查询用户钱包 */
-    public Object getWalletByUser(String oid, WalletType walletType, String userId){
+    public Object getWalletByUser(String appid, WalletType walletType, String userId){
+
+        ProjectWxPayParam param = new ProjectWxPayParam();
+        param.setAppId(appid);
+        com.zhongshu.card.client.ret.ResultContent<WxPayConfigModel> payConfigResult = paySettingFeignService.getProjectWxPayConfig(param);
+        if (payConfigResult.isFailed()){
+            return ResultContent.buildFail("获取支付配置信息失败");
+        }
+        String oid = payConfigResult.getContent().getProjectOid();
+
         if (StringUtil.isNullOrEmpty(userId)){
-            userId = authHelper.getCurrentUser().getUser();
+            userId = authHelper.getCurrentUser().getUserId();
         }
 
         Wallet wallet = walletDao.findByUserIdAndOid(userId, oid);
@@ -59,7 +86,17 @@ public class WalletService {
         wallet.setAmount(BigDecimal.ZERO);
         wallet.setAmount(BigDecimal.ZERO);
         wallet.setDataState(DataState.Enable);
-        wallet.setWalletType(walletType);
+
+        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);
+        }
         walletDao.save(wallet);
         return ResultContent.buildSuccess(toModel(wallet));
     }

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

@@ -6,6 +6,8 @@ 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.mqtt.SendMessageModel;
+import com.zhongshu.card.client.service.MqttFeignService;
 import com.zhongshu.payment.client.model.param.AmountUpdateParam;
 import com.zhongshu.payment.client.ret.ResultContent;
 import com.zhongshu.payment.client.types.RechargeState;
@@ -23,6 +25,7 @@ import org.springframework.stereotype.Service;
 
 import java.io.BufferedReader;
 import java.io.InputStreamReader;
+import java.util.Map;
 
 import static com.wechat.pay.contrib.apache.httpclient.constant.WechatPayHttpHeaders.*;
 
@@ -40,6 +43,9 @@ public class WxPayNotifyService {
     @Autowired
     WalletFeignServiceImpl walletService;
 
+    @Autowired
+    MqttFeignService mqttFeignService;
+
     public void payNotify(HttpServletRequest request) {
         try {
             //读取请求体的信息
@@ -92,6 +98,7 @@ public class WxPayNotifyService {
                 record.setRechargeState(RechargeState.SUCCESS);
                 record.setTradeTime(DateUtils.timeToLong(transaction.getSuccessTime(), DateUtils.patternWx));
                 rechargeRecordDao.save(record);
+                //增加余额
                 AmountUpdateParam amountUpdateParam = new AmountUpdateParam();
                 amountUpdateParam.setOid(record.getOid());
                 amountUpdateParam.setUserId(record.getUserId());
@@ -102,15 +109,23 @@ public class WxPayNotifyService {
                 if (recharge.isFailed()){
                     log.error("充值失败:钱包余额增加失败");
                 }
-                //todo 账户可用余额 增加
             }else {
                 log.info("微信支付异常:{}", transaction.getTradeState());
                 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();
+            String topic = String.format("/wechat/pay/%s", userId);
+            sendMessageModel.setTopic(topic);
+            sendMessageModel.setUserId(userId);
+            mqttFeignService.sendMessage(sendMessageModel);
         } catch (Exception e) {
             Log.info("微信支付回调验签错误:{}", e.getMessage());
+        }finally {
+
         }
     }
 

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

@@ -149,7 +149,8 @@ public class WxPaymentService extends SuperService {
             // 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
             request.setAppid(configModel.getAppId());
             request.setMchid(configModel.getMchId());
-            request.setNotifyUrl(configModel.getNotifyUrl());
+            request.setNotifyUrl("https://api.dev.qk.zonelife.cn/paymentserver/wechat/v3/notify/payNotify");
+//            request.setNotifyUrl(configModel.getNotifyUrl());
             // 调用接口
             PrepayResponse response = service.prepay(request);
 
@@ -289,6 +290,8 @@ public class WxPaymentService extends SuperService {
 
 
 
+
+
     @SneakyThrows
     public String sign(String privateKeyPath, byte[] message){
         Signature sign = Signature.getInstance("SHA256withRSA");

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

@@ -4,7 +4,7 @@ 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 com.zhongshu.card.client.model.payment.paySetting.WxPayConfigModel;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 
@@ -20,19 +20,19 @@ public class WxTransferBatchService {
     public static TransferBatchService service;
 
     // 初始化商户配置
-    public  Config RSAAutoCertificateConfig(){
+    public  Config RSAAutoCertificateConfig(String mchId, String privateKeyPath, String mchSerialNo, String apiV3Key){
         return new RSAAutoCertificateConfig.Builder()
-                .merchantId(WxV3PayConfig.Mch_ID)
+                .merchantId(mchId)
                 // 使用 com.wechat.pay.java.core.util 中的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名
-                .privateKeyFromPath(WxV3PayConfig.privateKeyPath)
-                .merchantSerialNumber(WxV3PayConfig.mchSerialNo)
-                .apiV3Key(WxV3PayConfig.apiV3Key)
+                .privateKeyFromPath(privateKeyPath)
+                .merchantSerialNumber(mchSerialNo)
+                .apiV3Key(apiV3Key)
                 .build();
     }
 
     /** 发起商家转账 */
-    public InitiateBatchTransferResponse InitiateBatchTransferResponse(InitiateBatchTransferRequest request){
-        Config config = RSAAutoCertificateConfig();
+    public InitiateBatchTransferResponse InitiateBatchTransferResponse(InitiateBatchTransferRequest request, WxPayConfigModel wxPayConfigModel){
+        Config config = RSAAutoCertificateConfig(wxPayConfigModel.getMchId(), wxPayConfigModel.getPrivateKeyPath(), wxPayConfigModel.getMchSerialNo(), wxPayConfigModel.getApiV3Key());
         // 初始化服务
         service = new TransferBatchService.Builder().config(config).build();
         // ... 调用接口
@@ -40,32 +40,32 @@ public class WxTransferBatchService {
     }
 
     /** 通过微信批次单号查询批次单 */
-    public TransferBatchEntity getTransferBatchByNo(GetTransferBatchByNoRequest request) {
-        Config config = RSAAutoCertificateConfig();
+    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) {
-        Config config = RSAAutoCertificateConfig();
+    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) {
-        Config config = RSAAutoCertificateConfig();
+    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) {
-        Config config = RSAAutoCertificateConfig();
+    public TransferDetailEntity getTransferDetailByOutNo(GetTransferDetailByOutNoRequest request, WxPayConfigModel wxPayConfigModel) {
+        Config config = RSAAutoCertificateConfig(wxPayConfigModel.getMchId(), wxPayConfigModel.getPrivateKeyPath(), wxPayConfigModel.getMchSerialNo(), wxPayConfigModel.getApiV3Key());
         // 初始化服务
         service = new TransferBatchService.Builder().config(config).build();
         return service.getTransferDetailByOutNo(request);

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

@@ -725,5 +725,6 @@ 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(Thread.currentThread().getContextClassLoader().getResource("").getPath());
     }
 }