wujiefeng 10 månader sedan
förälder
incheckning
4885f73997
56 ändrade filer med 2332 tillägg och 5 borttagningar
  1. 35 0
      RewardClient/src/main/java/com/zhongshu/reward/client/model/InviteReceiptsRoleModel.java
  2. 16 0
      RewardClient/src/main/java/com/zhongshu/reward/client/model/TotalStatisticsModel.java
  3. 21 0
      RewardClient/src/main/java/com/zhongshu/reward/client/model/param/QueryTransferParam.java
  4. 40 0
      RewardClient/src/main/java/com/zhongshu/reward/client/model/param/WalletReceiptsParam.java
  5. 25 0
      RewardClient/src/main/java/com/zhongshu/reward/client/model/param/WalletTransferParam.java
  6. 43 0
      RewardClient/src/main/java/com/zhongshu/reward/client/model/wallet/TransferModel.java
  7. 42 0
      RewardClient/src/main/java/com/zhongshu/reward/client/model/wallet/TransferStatusModel.java
  8. 51 0
      RewardClient/src/main/java/com/zhongshu/reward/client/model/wallet/WalletModel.java
  9. 55 0
      RewardClient/src/main/java/com/zhongshu/reward/client/model/wallet/WalletReceiptsModel.java
  10. 89 0
      RewardClient/src/main/java/com/zhongshu/reward/client/model/wallet/WxTransferBatchModel.java
  11. 41 0
      RewardClient/src/main/java/com/zhongshu/reward/client/ret/CommentException.java
  12. 92 0
      RewardClient/src/main/java/com/zhongshu/reward/client/ret/ResultContent.java
  13. 33 0
      RewardClient/src/main/java/com/zhongshu/reward/client/ret/ResultException.java
  14. 11 0
      RewardClient/src/main/java/com/zhongshu/reward/client/ret/ResultMessage.java
  15. 39 0
      RewardClient/src/main/java/com/zhongshu/reward/client/ret/ResultState.java
  16. 19 0
      RewardClient/src/main/java/com/zhongshu/reward/client/type/ComputationType.java
  17. 19 0
      RewardClient/src/main/java/com/zhongshu/reward/client/type/DataState.java
  18. 21 0
      RewardClient/src/main/java/com/zhongshu/reward/client/type/ReceiptsStatus.java
  19. 17 0
      RewardClient/src/main/java/com/zhongshu/reward/client/type/ReceiptsType.java
  20. 11 0
      RewardClient/src/main/java/com/zhongshu/reward/client/type/TimeUnitType.java
  21. 10 0
      RewardClient/src/main/java/com/zhongshu/reward/client/type/TransferChannel.java
  22. 28 0
      RewardClient/src/main/java/com/zhongshu/reward/client/type/TransferStatus.java
  23. 12 0
      RewardClient/src/main/java/com/zhongshu/reward/client/type/WalletType.java
  24. 11 0
      RewardServer/pom.xml
  25. 1 1
      RewardServer/src/main/java/com/zhongshu/reward/server/core/config/MVCConfig.java
  26. 1 1
      RewardServer/src/main/java/com/zhongshu/reward/server/core/config/MongoConfig.java
  27. 1 1
      RewardServer/src/main/java/com/zhongshu/reward/server/core/config/PaymentConfig.java
  28. 1 1
      RewardServer/src/main/java/com/zhongshu/reward/server/core/config/RedisConfig.java
  29. 15 0
      RewardServer/src/main/java/com/zhongshu/reward/server/core/config/VipConfig.java
  30. 15 0
      RewardServer/src/main/java/com/zhongshu/reward/server/core/config/feign/ZswlCloudBdbConfig.java
  31. 54 0
      RewardServer/src/main/java/com/zhongshu/reward/server/core/controller/wallet/WalletController.java
  32. 36 0
      RewardServer/src/main/java/com/zhongshu/reward/server/core/dao/Impl/WalletDaoImpl.java
  33. 106 0
      RewardServer/src/main/java/com/zhongshu/reward/server/core/dao/Impl/WxTransferBatchDaoImpl.java
  34. 14 0
      RewardServer/src/main/java/com/zhongshu/reward/server/core/dao/InviteReceiptsRoleDao.java
  35. 12 0
      RewardServer/src/main/java/com/zhongshu/reward/server/core/dao/TransferRulerDao.java
  36. 17 0
      RewardServer/src/main/java/com/zhongshu/reward/server/core/dao/WalletDao.java
  37. 17 0
      RewardServer/src/main/java/com/zhongshu/reward/server/core/dao/WalletReceiptsDao.java
  38. 20 0
      RewardServer/src/main/java/com/zhongshu/reward/server/core/dao/WxTransferBatchDao.java
  39. 10 0
      RewardServer/src/main/java/com/zhongshu/reward/server/core/dao/extend/WalletDaoExtend.java
  40. 22 0
      RewardServer/src/main/java/com/zhongshu/reward/server/core/dao/extend/WxTransferBatchDaoExtend.java
  41. 43 0
      RewardServer/src/main/java/com/zhongshu/reward/server/core/domain/InviteReceiptsRole.java
  42. 86 0
      RewardServer/src/main/java/com/zhongshu/reward/server/core/domain/TransferRuler.java
  43. 59 0
      RewardServer/src/main/java/com/zhongshu/reward/server/core/domain/Wallet.java
  44. 62 0
      RewardServer/src/main/java/com/zhongshu/reward/server/core/domain/WalletReceipts.java
  45. 109 0
      RewardServer/src/main/java/com/zhongshu/reward/server/core/domain/WxTransferBatch.java
  46. 42 0
      RewardServer/src/main/java/com/zhongshu/reward/server/core/domain/WxTransferScene.java
  47. 23 0
      RewardServer/src/main/java/com/zhongshu/reward/server/core/listener/VipEventListener.java
  48. 117 0
      RewardServer/src/main/java/com/zhongshu/reward/server/core/service/ChatTransferBatchService.java
  49. 8 0
      RewardServer/src/main/java/com/zhongshu/reward/server/core/service/Impl/WalletFeignServiceImpl.java
  50. 65 0
      RewardServer/src/main/java/com/zhongshu/reward/server/core/service/InviteReceiptsRoleService.java
  51. 98 0
      RewardServer/src/main/java/com/zhongshu/reward/server/core/service/WalletReceiptsService.java
  52. 58 0
      RewardServer/src/main/java/com/zhongshu/reward/server/core/service/WalletService.java
  53. 226 0
      RewardServer/src/main/java/com/zhongshu/reward/server/core/service/WxTransferService.java
  54. 56 0
      RewardServer/src/main/java/com/zhongshu/reward/server/core/timer/WalletTimer.java
  55. 156 0
      RewardServer/src/main/java/com/zhongshu/reward/server/core/util/DateUtils.java
  56. 1 1
      RewardServer/src/main/resources/application-dev.yml

+ 35 - 0
RewardClient/src/main/java/com/zhongshu/reward/client/model/InviteReceiptsRoleModel.java

@@ -0,0 +1,35 @@
+package com.zhongshu.reward.client.model;
+
+import com.zhongshu.reward.client.type.ComputationType;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * @author wjf
+ * @date 2024/8/7
+ */
+@Data
+public class InviteReceiptsRoleModel {
+
+    private String id;
+
+    @ApiModelProperty("规则名称")
+    private String roleName;
+
+    @ApiModelProperty("套餐id")
+    private String setMealId;
+
+    @ApiModelProperty("计算规则:固定、百分比")
+    private ComputationType computation;
+
+    @ApiModelProperty("金额额度")
+    private BigDecimal baseTotal;
+
+    @ApiModelProperty("生效状态")
+    private boolean disable;
+
+    @ApiModelProperty("生效范围是否所有")
+    private boolean isALL = true;
+}

+ 16 - 0
RewardClient/src/main/java/com/zhongshu/reward/client/model/TotalStatisticsModel.java

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

+ 21 - 0
RewardClient/src/main/java/com/zhongshu/reward/client/model/param/QueryTransferParam.java

@@ -0,0 +1,21 @@
+package com.zhongshu.reward.client.model.param;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+/**
+ * @author wjf
+ * @date 2024/7/29
+ */
+@Data
+public class QueryTransferParam {
+
+    @Schema(name = "walletId", description = "钱包id")
+    private String walletId;
+
+    @Schema(name = "year", description = "年")
+    private Integer year;
+
+    @Schema(name = "month", description = "月")
+    private Integer month;
+}

+ 40 - 0
RewardClient/src/main/java/com/zhongshu/reward/client/model/param/WalletReceiptsParam.java

@@ -0,0 +1,40 @@
+package com.zhongshu.reward.client.model.param;
+
+
+import com.zhongshu.reward.client.type.ReceiptsType;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * @author wjf
+ * @date 2024/8/6
+ */
+@Data
+public class WalletReceiptsParam {
+
+    /**
+     * 钱包
+     */
+    private String userId;
+
+    /**
+     * 预计到账时间
+     */
+    private Long estimatedTime;
+
+    /**
+     * 到账类型
+     */
+    private ReceiptsType receiptsType;
+
+    /**
+     * 到账金额
+     */
+    private BigDecimal total = BigDecimal.ZERO;
+
+    /**
+     * 外部订单号
+     */
+    private String outTradeNo;
+}

+ 25 - 0
RewardClient/src/main/java/com/zhongshu/reward/client/model/param/WalletTransferParam.java

@@ -0,0 +1,25 @@
+package com.zhongshu.reward.client.model.param;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 钱包提现参数
+ * @author wjf
+ * @date 2024/8/5
+ */
+@Data
+public class WalletTransferParam {
+
+    @Schema(name = "walletId", description = "钱包id")
+    private String walletId;
+
+    @Schema(name = "total", description = "提现金额")
+    private BigDecimal total = BigDecimal.ZERO;
+
+    @Schema(name = "openid", description = "微信openid")
+    private String openid;
+
+}

+ 43 - 0
RewardClient/src/main/java/com/zhongshu/reward/client/model/wallet/TransferModel.java

@@ -0,0 +1,43 @@
+package com.zhongshu.reward.client.model.wallet;
+
+import com.google.gson.annotations.SerializedName;
+import com.wechat.pay.java.core.cipher.Encryption;
+import com.wechat.pay.java.service.transferbatch.model.TransferDetailInput;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class TransferModel {
+
+
+//    @SerializedName("appid")
+//    private String appid;
+//    /** 商家批次单号 说明:商户系统内部的商家批次单号,要求此参数只能由数字、大小写字母组成,在商户系统内部唯一 */
+    @SerializedName("out_batch_no")
+    private String outBatchNo;
+    /** 批次名称 说明:该笔批量转账的名称 */
+    @SerializedName("batch_name")
+    private String batchName;
+    /** 批次备注 说明:转账说明,UTF8编码,最多允许32个字符 */
+    @SerializedName("batch_remark")
+    private String batchRemark;
+    /** 转账总金额 说明:转账金额单位为“分”。转账总金额必须与批次内所有明细转账金额之和保持一致,否则无法发起转账操作 */
+    @SerializedName("total_amount")
+    private Long totalAmount;
+    /** 转账总笔数 说明:一个转账批次单最多发起一千笔转账。转账总笔数必须与批次内所有明细之和保持一致,否则无法发起转账操作 */
+    @SerializedName("total_num")
+    private Integer totalNum;
+    /** 转账明细列表 说明:发起批量转账的明细列表,最多一千笔 */
+    @Encryption
+    @SerializedName("transfer_detail_list")
+    private List<TransferDetailInput> transferDetailList = new ArrayList<TransferDetailInput>();
+    /** 转账场景ID 说明:该批次转账使用的转账场景,如不填写则使用商家的默认场景,如无默认场景可为空,可前往“商家转账到零钱-前往功能”中申请。 如:1001-现金营销 */
+    @SerializedName("transfer_scene_id")
+    private String transferSceneId;
+}

+ 42 - 0
RewardClient/src/main/java/com/zhongshu/reward/client/model/wallet/TransferStatusModel.java

@@ -0,0 +1,42 @@
+package com.zhongshu.reward.client.model.wallet;
+
+import com.google.gson.annotations.Expose;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author wjf
+ * @date 2024/8/5
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class TransferStatusModel {
+    @SerializedName("batch_id")
+    @Expose(
+            serialize = false
+    )
+    private String batchId;
+    @SerializedName("need_query_detail")
+    @Expose(
+            serialize = false
+    )
+    private Boolean needQueryDetail;
+    @SerializedName("offset")
+    @Expose(
+            serialize = false
+    )
+    private Integer offset;
+    @SerializedName("limit")
+    @Expose(
+            serialize = false
+    )
+    private Integer limit;
+    @SerializedName("detail_status")
+    @Expose(
+            serialize = false
+    )
+    private String detailStatus;
+}

+ 51 - 0
RewardClient/src/main/java/com/zhongshu/reward/client/model/wallet/WalletModel.java

@@ -0,0 +1,51 @@
+package com.zhongshu.reward.client.model.wallet;
+
+import com.zhongshu.reward.client.type.DataState;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * @author wjf
+ * @date 2024/8/5
+ */
+@Data
+public class WalletModel {
+
+    private String id;
+
+    private Long createTime;
+
+    private Long updateTime;;
+
+    /**
+     * 用户id
+     */
+    private String userId;
+
+    /**
+     * 商铺id
+     */
+    private String shopId;
+
+
+    /**
+     * 账户余额(可提现金额)
+     */
+    private BigDecimal amount;
+
+    /**
+     * 未结算金额
+     */
+    private BigDecimal waitAmount;
+
+    /**
+     * 今日已提现金额
+     */
+    private BigDecimal todayTransferAmount;
+
+    /**
+     * 钱包状态
+     */
+    private DataState dataState;
+}

+ 55 - 0
RewardClient/src/main/java/com/zhongshu/reward/client/model/wallet/WalletReceiptsModel.java

@@ -0,0 +1,55 @@
+package com.zhongshu.reward.client.model.wallet;
+
+import com.zhongshu.reward.client.type.ReceiptsStatus;
+import com.zhongshu.reward.client.type.ReceiptsType;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * @author wjf
+ * @date 2024/8/6
+ */
+@Data
+public class WalletReceiptsModel {
+
+    private String id;
+
+    private Long createTime;
+
+    private Long updateTime;;
+    /**
+     * 钱包
+     */
+    private String walletId;
+
+    /**
+     * 预计到账时间
+     */
+    private Long estimatedTime;
+
+    /**
+     * 实际到账时间
+     */
+    private Long receiptsTime;
+
+    /**
+     * 到账类型
+     */
+    private ReceiptsType receiptsType;
+
+    /**
+     * 到账金额
+     */
+    private BigDecimal total = BigDecimal.ZERO;
+
+    /**
+     * 状态
+     */
+    private ReceiptsStatus status;
+
+    /**
+     * 外部订单号
+     */
+    private String outTradeNo;
+}

+ 89 - 0
RewardClient/src/main/java/com/zhongshu/reward/client/model/wallet/WxTransferBatchModel.java

@@ -0,0 +1,89 @@
+package com.zhongshu.reward.client.model.wallet;
+
+import com.zhongshu.reward.client.type.TransferChannel;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.math.BigDecimal;
+
+/**
+ * @author wjf
+ * @date 2024/8/5
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxTransferBatchModel {
+
+    private String id;
+
+    private Long createTime;
+
+    private Long updateTime;
+
+    /**
+     * 内部批次单号
+     */
+    private String batchNo;
+
+    /**
+     * (内部)提现明细单号
+     */
+    private String detailNo;
+
+    /**
+     * 提现钱包
+     */
+    private String walletId;
+
+    /**
+     * 提现金额
+     */
+    private BigDecimal total;
+
+    /**
+     * 提现渠道
+     */
+    private TransferChannel channel;
+
+//    /**
+//     * 提现前账户信息
+//     */
+//    private Wallet beforeWalletInfo;
+
+//    /**
+//     * 到账时间
+//     */
+//    private Long tradeTime;
+
+    /**
+     * 批次状态
+     */
+    private String batchStatus;
+
+    /**
+     * 明细状态
+     */
+    private String detailStatus;
+
+    /**
+     * wx批次单号
+     */
+    private String wxBatchId;
+
+    /**
+     * wx批次单号
+     */
+    private String wxDetailId;
+
+    /**
+     * openid
+     */
+    private String openid;
+
+    /**
+     * 异常原因
+     */
+    private String exceptionReason;
+}

+ 41 - 0
RewardClient/src/main/java/com/zhongshu/reward/client/ret/CommentException.java

@@ -0,0 +1,41 @@
+package com.zhongshu.reward.client.ret;
+
+/**
+ * @Author: wy
+ * @Date: 2023/6/6 16:43
+ */
+public class CommentException extends RuntimeException {
+
+    private ResultState resultState;
+
+    private String message;
+
+    /**
+     * 参数校验异常构造方法
+     */
+    public CommentException(String message) {
+        this.message = message;
+    }
+
+    public CommentException(ResultState resultState, String message) {
+        this.resultState = resultState;
+        this.message = message;
+    }
+
+    @Override
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    public ResultState getResultState() {
+        return resultState;
+    }
+
+    public void setResultState(ResultState resultState) {
+        this.resultState = resultState;
+    }
+}

+ 92 - 0
RewardClient/src/main/java/com/zhongshu/reward/client/ret/ResultContent.java

@@ -0,0 +1,92 @@
+package com.zhongshu.reward.client.ret;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.*;
+
+import java.util.Optional;
+
+/**
+ * 结果
+ *
+ * @param <T>
+ */
+@Builder
+@ToString(callSuper = true)
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@AllArgsConstructor
+@NoArgsConstructor
+public class ResultContent<T> {
+
+    //内容
+    @Getter
+    @Setter
+    private T content;
+
+    //状态
+    @Getter
+    @Setter
+    private ResultState state;
+
+    //文本
+    @Getter
+    @Setter
+    private String msg;
+
+
+    //异常
+    @Getter
+    @Setter
+    private ResultException exception;
+
+
+    /**
+     * 获取内容
+     *
+     * @return
+     */
+    public Optional<T> optionalContent() {
+        return Optional.ofNullable(this.content);
+    }
+
+    public static <T> ResultContent build(ResultState state, T content) {
+        return ResultContent.builder().state(state).content(content).msg(state.getRemark()).build();
+    }
+
+    public static <T> ResultContent build(boolean bool) {
+        return build(bool ? ResultState.Success : ResultState.Fail, null);
+    }
+
+    public static <T> ResultContent build(ResultState state) {
+        return build(state, null);
+    }
+
+    public static <T> ResultContent buildContent(T content) {
+        return build(content == null ? ResultState.Fail : ResultState.Success, content);
+    }
+
+    public static <T> ResultContent buildFail(String msg) {
+        return ResultContent.builder().state(ResultState.Fail).msg(msg).build();
+    }
+
+    public static <T> ResultContent buildSuccess(String msg) {
+        return build(ResultState.Success, msg);
+    }
+
+    public static <T> ResultContent buildSuccess(T content) {
+        return build(ResultState.Success, content);
+    }
+
+    public static <T> ResultContent buildSuccess() {
+        return build(ResultState.Success, ResultState.Success.getRemark());
+    }
+
+    public boolean isSuccess()
+    {
+        return ResultState.Success.equals(this.state);
+    }
+
+    public boolean isFailed()
+    {
+        return !ResultState.Success.equals(this.state);
+    }
+}

+ 33 - 0
RewardClient/src/main/java/com/zhongshu/reward/client/ret/ResultException.java

@@ -0,0 +1,33 @@
+package com.zhongshu.reward.client.ret;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 结果集异常
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class ResultException {
+
+    private String type;
+    private String cls;
+    private String message;
+
+
+    /**
+     * 创建异常对象
+     *
+     * @param e
+     * @return
+     */
+    public static ResultException build(Exception e) {
+        ResultException exception = new ResultException();
+        exception.type = e.getClass().getSimpleName();
+        exception.cls = e.getClass().getName();
+        exception.message = e.getMessage();
+        return exception;
+    }
+}

+ 11 - 0
RewardClient/src/main/java/com/zhongshu/reward/client/ret/ResultMessage.java

@@ -0,0 +1,11 @@
+package com.zhongshu.reward.client.ret;
+
+/**
+ * @author TRX
+ * @date 2024/5/31
+ */
+public class ResultMessage {
+    public static final String DATA_NOT_EXIST = "数据不存在:%s";
+
+    public static final String NAME_EXIST = "名称已存在:%s";
+}

+ 39 - 0
RewardClient/src/main/java/com/zhongshu/reward/client/ret/ResultState.java

@@ -0,0 +1,39 @@
+package com.zhongshu.reward.client.ret;
+
+import lombok.Getter;
+
+/**
+ * 结果状态模板
+ */
+public enum ResultState {
+
+    Success("成功"),
+    Fail("失败"),
+    Error("错误"),
+    Exception("异常"),
+    Robot("机器验证"),
+
+    UserExit("用户存在"),
+    UserNotExit("用户不存在"),
+    UserOrPassWordError("用户名或密码错误"),
+
+    NOT_TOKEN_ERROR("token获取失败"),
+    NOT_AUTH_ERROR("需要授权"),
+    EXPIRE_ERROR( "token已过期"),
+    INVALID_TOKEN("无效token"),
+    LOGIN_REQUIRED("需要登录"),
+    CODE_ERROR("验证码错误"),
+
+    AccountNotNull("账户不能为空"),
+    AccountExists("用户存在"),
+    AccountNotExists("账户不存在"),
+    NOT_WECHAT_AUTH("用户微信未授权"),
+    ;
+
+    @Getter
+    private String remark;
+
+    ResultState(String remark) {
+        this.remark = remark;
+    }
+}

+ 19 - 0
RewardClient/src/main/java/com/zhongshu/reward/client/type/ComputationType.java

@@ -0,0 +1,19 @@
+package com.zhongshu.reward.client.type;
+
+/**
+ * 返利计算方式
+ * @author wjf
+ * @date 2024/8/7
+ */
+public enum ComputationType {
+
+    /**
+     * 固定金额
+     */
+    FIXED,
+
+    /**
+     * 百分比
+     */
+    RATIO;
+}

+ 19 - 0
RewardClient/src/main/java/com/zhongshu/reward/client/type/DataState.java

@@ -0,0 +1,19 @@
+package com.zhongshu.reward.client.type;
+
+import lombok.Getter;
+
+/**
+ * 数据状态
+ */
+public enum DataState {
+    Enable("启用"),
+    Disable("已停用"),
+    ;
+
+    @Getter
+    private String remark;
+
+    DataState(String remark) {
+        this.remark = remark;
+    }
+}

+ 21 - 0
RewardClient/src/main/java/com/zhongshu/reward/client/type/ReceiptsStatus.java

@@ -0,0 +1,21 @@
+package com.zhongshu.reward.client.type;
+
+/**
+ * @author wjf
+ * @date 2024/8/6
+ */
+public enum ReceiptsStatus {
+
+    /**
+     * 未结算
+     */
+    WAIT,
+    /**
+     * 已结算
+     */
+    RECEIPTS,
+    /**
+     * 无返利
+     */
+    CANCEL
+}

+ 17 - 0
RewardClient/src/main/java/com/zhongshu/reward/client/type/ReceiptsType.java

@@ -0,0 +1,17 @@
+package com.zhongshu.reward.client.type;
+
+/**
+ * @author wjf
+ * @date 2024/8/5
+ */
+public enum ReceiptsType {
+
+    /**
+     * 返利
+     */
+    REBATE,
+    /**
+     * 佣金
+     */
+    COMMISSION,
+}

+ 11 - 0
RewardClient/src/main/java/com/zhongshu/reward/client/type/TimeUnitType.java

@@ -0,0 +1,11 @@
+package com.zhongshu.reward.client.type;
+
+/**
+ * @author wjf
+ * @date 2024/8/7
+ */
+public enum TimeUnitType {
+
+    MONTH,
+    DAY
+}

+ 10 - 0
RewardClient/src/main/java/com/zhongshu/reward/client/type/TransferChannel.java

@@ -0,0 +1,10 @@
+package com.zhongshu.reward.client.type;
+
+/**
+ * @author wjf
+ * @date 2024/8/5
+ */
+public enum TransferChannel {
+
+    WeChat
+}

+ 28 - 0
RewardClient/src/main/java/com/zhongshu/reward/client/type/TransferStatus.java

@@ -0,0 +1,28 @@
+package com.zhongshu.reward.client.type;
+
+import lombok.Getter;
+
+/**
+ * @author wjf
+ * @date 2024/8/5
+ */
+public enum TransferStatus {
+
+    PROCESSING("提现处理中"),
+
+    SUCCESS("已成功"),
+
+    FAIL("失败"),
+
+    CLOSE("已关闭")
+    ;
+
+
+
+    @Getter
+    private String remark;
+
+    TransferStatus(String remark){
+        this.remark =remark;
+    }
+}

+ 12 - 0
RewardClient/src/main/java/com/zhongshu/reward/client/type/WalletType.java

@@ -0,0 +1,12 @@
+package com.zhongshu.reward.client.type;
+
+/**
+ * @author wjf
+ * @date 2024/8/5
+ */
+public enum WalletType {
+
+    USER,
+
+    SHOP
+}

+ 11 - 0
RewardServer/pom.xml

@@ -34,6 +34,11 @@
 		</dependency>
 
 
+		<dependency>
+			<groupId>com.zswl.cloud.bdb</groupId>
+			<artifactId>zswl-cloud-bdb-client</artifactId>
+			<version>${project.version}</version>
+		</dependency>
 
 		<dependency>
 			<groupId>com.zswl.cloud.shop</groupId>
@@ -41,6 +46,12 @@
 			<version>${project.version}</version>
 		</dependency>
 
+		<dependency>
+			<groupId>com.zhongshu</groupId>
+			<artifactId>VipClient</artifactId>
+			<version>${project.version}</version>
+		</dependency>
+
 
 		<dependency>
 			<groupId>com.github.microservice.components</groupId>

+ 1 - 1
RewardServer/src/main/java/com/zhongshu/reward/server/core/config/MVCConfig.java

@@ -1,4 +1,4 @@
-package com.zhongshu.payment.server.core.config;
+package com.zhongshu.reward.server.core.config;
 
 import com.github.microservice.core.mvc.MVCConfiguration;
 import com.github.microservice.core.mvc.MVCResponseConfiguration;

+ 1 - 1
RewardServer/src/main/java/com/zhongshu/reward/server/core/config/MongoConfig.java

@@ -8,6 +8,6 @@ import org.springframework.data.mongodb.repository.config.EnableMongoRepositorie
 
 @Configuration
 @Import(MongoConfiguration.class)
-@EnableMongoRepositories("com.zhongshu.payment.server.core.dao")
+@EnableMongoRepositories("com.zhongshu.reward.server.core.dao")
 public class MongoConfig {
 }

+ 1 - 1
RewardServer/src/main/java/com/zhongshu/reward/server/core/config/PaymentConfig.java

@@ -1,4 +1,4 @@
-package com.zhongshu.payment.server.core.config;
+package com.zhongshu.reward.server.core.config;
 
 import lombok.Data;
 import org.springframework.boot.context.properties.ConfigurationProperties;

+ 1 - 1
RewardServer/src/main/java/com/zhongshu/reward/server/core/config/RedisConfig.java

@@ -1,4 +1,4 @@
-package com.zhongshu.payment.server.core.config;
+package com.zhongshu.reward.server.core.config;
 
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;

+ 15 - 0
RewardServer/src/main/java/com/zhongshu/reward/server/core/config/VipConfig.java

@@ -0,0 +1,15 @@
+package com.zhongshu.reward.server.core.config;
+
+import com.github.microservice.auth.config.AuthClientConfiguration;
+import com.zhongshu.vip.client.config.VipCenterClientConfiguration;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+
+/**
+ * @author wjf
+ * @date 2024/8/8
+ */
+@Configuration
+@Import(VipCenterClientConfiguration.class)
+public class VipConfig {
+}

+ 15 - 0
RewardServer/src/main/java/com/zhongshu/reward/server/core/config/feign/ZswlCloudBdbConfig.java

@@ -0,0 +1,15 @@
+package com.zhongshu.reward.server.core.config.feign;
+
+import org.springframework.cloud.openfeign.EnableFeignClients;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author wjf
+ * @date 2024/8/7
+ */
+@EnableFeignClients("com.zswl.cloud.bdb.client.service")
+@ComponentScan("com.zswl.cloud.bdb.client")
+@Configuration
+public class ZswlCloudBdbConfig {
+}

+ 54 - 0
RewardServer/src/main/java/com/zhongshu/reward/server/core/controller/wallet/WalletController.java

@@ -0,0 +1,54 @@
+package com.zhongshu.reward.server.core.controller.wallet;
+
+import com.github.microservice.auth.security.annotations.ResourceAuth;
+import com.github.microservice.auth.security.type.AuthType;
+import com.zhongshu.reward.client.model.param.QueryTransferParam;
+import com.zhongshu.reward.client.model.param.WalletTransferParam;
+import com.zhongshu.reward.server.core.service.WalletService;
+import com.zhongshu.reward.server.core.service.WxTransferService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * @author wjf
+ * @date 2024/8/5
+ */
+@Slf4j
+@RestController
+@RequestMapping("/wallet")
+@Tag(name = "钱包")
+public class WalletController {
+
+    @Autowired
+    WalletService walletService;
+
+    @Autowired
+    WxTransferService wxTransferService;
+
+    @Operation(summary = "获取(开通)当前用户钱包信息", description = "获取(开通)当前用户钱包信息")
+    @ResourceAuth(value = "user", type = AuthType.User)
+    @GetMapping ("getWallet")
+    public Object getWalletByUser(@RequestParam(name = "userId") String userId){
+        return walletService.getWallet(userId);
+    }
+
+    @Operation(summary = "发起提现", description = "发起提现")
+    @ResourceAuth(value = "user", type = AuthType.User)
+    @PostMapping (value = "transfer", consumes = MediaType.APPLICATION_JSON_VALUE)
+    public Object transfer(@RequestBody WalletTransferParam param){
+        return wxTransferService.transfer(param);
+    }
+
+
+    @Operation(summary = "查询提现列表", description = "查询提现列表")
+    @ResourceAuth(value = "user", type = AuthType.User)
+    @PostMapping (value = "queryTransfer", consumes = MediaType.APPLICATION_JSON_VALUE)
+    public Object queryTransfer(@RequestBody QueryTransferParam param){
+        return wxTransferService.queryTransfer(param.getWalletId(), param.getYear(), param.getMonth());
+    }
+
+}

+ 36 - 0
RewardServer/src/main/java/com/zhongshu/reward/server/core/dao/Impl/WalletDaoImpl.java

@@ -0,0 +1,36 @@
+package com.zhongshu.reward.server.core.dao.Impl;
+
+import com.github.microservice.components.data.mongo.mongo.helper.DBHelper;
+import com.zhongshu.reward.server.core.dao.extend.WalletDaoExtend;
+import com.zhongshu.reward.server.core.domain.Wallet;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.data.mongodb.core.query.Update;
+
+import java.math.BigDecimal;
+
+/**
+ * @author wjf
+ * @date 2024/8/5
+ */
+public class WalletDaoImpl implements WalletDaoExtend {
+
+    @Autowired
+    DBHelper dbHelper;
+
+    @Autowired
+    MongoTemplate mongoTemplate;
+
+    @Override
+    public boolean resetTodayAmount() {
+        Query query = Query.query(Criteria.where("todayTransferAmount").ne(BigDecimal.ZERO));
+        Update update = new Update();
+        update.set("todayTransferAmount", BigDecimal.ZERO);
+        this.dbHelper.updateTime(update);
+        return this.mongoTemplate.updateMulti(
+                query, update, Wallet.class
+        ).getModifiedCount() > 0;
+    }
+}

+ 106 - 0
RewardServer/src/main/java/com/zhongshu/reward/server/core/dao/Impl/WxTransferBatchDaoImpl.java

@@ -0,0 +1,106 @@
+package com.zhongshu.reward.server.core.dao.Impl;
+
+import com.github.microservice.components.data.mongo.mongo.helper.DBHelper;
+import com.zhongshu.reward.client.model.TotalStatisticsModel;
+import com.zhongshu.reward.client.type.TransferStatus;
+import com.zhongshu.reward.server.core.dao.extend.WxTransferBatchDaoExtend;
+import com.zhongshu.reward.server.core.domain.WxTransferBatch;
+import org.apache.commons.lang3.ObjectUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+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 org.springframework.data.mongodb.core.query.Update;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author wjf
+ * @date 2024/8/5
+ */
+public class WxTransferBatchDaoImpl implements WxTransferBatchDaoExtend {
+
+    @Autowired
+    MongoTemplate mongoTemplate;
+
+    @Autowired
+    DBHelper dbHelper;
+
+
+    @Override
+    public List<WxTransferBatch> list(String walletId, Long startTime, Long endTime) {
+        Criteria criteria = new Criteria();
+
+        if (ObjectUtils.isNotEmpty(walletId)){
+            criteria.and("wallet._id").is(walletId);
+        }
+
+        if (null != startTime){
+            criteria.and("createTime").gte(startTime);
+        }
+
+        if (null != endTime){
+            criteria.and("createTime").lte(endTime);
+        }
+
+        Query query = Query.query(criteria);
+        query.with(Sort.by(Sort.Order.desc("createTime")));
+
+        return mongoTemplate.find(query, WxTransferBatch.class);
+    }
+
+    @Override
+    public boolean updateStatus(String id, String batchStatus, String detailStatus, TransferStatus transferStatus) {
+        Query query = Query.query(Criteria.where("_id").is(id));
+        Update update = new Update();
+        update.set("batchStatus", batchStatus);
+        update.set("detailStatus", detailStatus);
+        update.set("transferStatus", transferStatus);
+        this.dbHelper.updateTime(update);
+        return this.mongoTemplate.updateFirst(
+                query, update, WxTransferBatch.class
+        ).getModifiedCount() > 0;
+    }
+
+    public Long countByTime(String walletId, Long startTime, Long endTime) {
+        Criteria criteria = new Criteria();
+        criteria.and("wallet._id").is(walletId);
+        criteria.and("createTime").gte(startTime);
+        criteria.and("createTime").lte(endTime);
+        criteria.and("transferStatus").in(List.of(TransferStatus.PROCESSING, TransferStatus.SUCCESS));
+
+        Query query = Query.query(criteria);
+        query.with(Sort.by(Sort.Order.desc("createTime")));
+
+        return mongoTemplate.count(query, WxTransferBatch.class);
+    }
+
+    public Integer sumDayTotal(String walletId, Long startTime, Long endTime){
+
+        Criteria criteria = new Criteria();
+        criteria.and("wallet._id").is(walletId);
+        criteria.and("createTime").gte(startTime);
+        criteria.and("createTime").lte(endTime);
+        criteria.and("transferStatus").in(List.of(TransferStatus.PROCESSING, TransferStatus.SUCCESS));
+
+        Aggregation aggregation = Aggregation.newAggregation(
+                Aggregation.match(criteria),
+//                Aggregation.project("_id","amountTotal"),
+                Aggregation.group("wallet._id").sum("total").as("totalAmount")
+//                Aggregation.group("tradeType").last("tradeType").as("_id")
+        );
+
+
+        AggregationResults<TotalStatisticsModel> groupList = mongoTemplate.aggregate(aggregation, WxTransferBatch.class, TotalStatisticsModel.class);
+
+        if (groupList.getMappedResults().size()==0){
+            return 0;
+        }
+        return groupList.getMappedResults().get(0).getTotalAmount();
+    }
+
+}

+ 14 - 0
RewardServer/src/main/java/com/zhongshu/reward/server/core/dao/InviteReceiptsRoleDao.java

@@ -0,0 +1,14 @@
+package com.zhongshu.reward.server.core.dao;
+
+import com.github.microservice.components.data.mongo.mongo.dao.MongoDao;
+import com.zhongshu.reward.server.core.domain.InviteReceiptsRole;
+
+/**
+ * @author wjf
+ * @date 2024/8/7
+ */
+public interface InviteReceiptsRoleDao extends MongoDao<InviteReceiptsRole> {
+
+    boolean existsBySetMealIdAndDisable(String setMealId, boolean disable);
+
+}

+ 12 - 0
RewardServer/src/main/java/com/zhongshu/reward/server/core/dao/TransferRulerDao.java

@@ -0,0 +1,12 @@
+package com.zhongshu.reward.server.core.dao;
+
+import com.github.microservice.components.data.mongo.mongo.dao.MongoDao;
+import com.zhongshu.reward.server.core.domain.TransferRuler;
+
+/**
+ * @author wjf
+ * @date 2024/8/7
+ */
+public interface TransferRulerDao extends MongoDao<TransferRuler> {
+
+}

+ 17 - 0
RewardServer/src/main/java/com/zhongshu/reward/server/core/dao/WalletDao.java

@@ -0,0 +1,17 @@
+package com.zhongshu.reward.server.core.dao;
+
+
+import com.github.microservice.components.data.mongo.mongo.dao.MongoDao;
+import com.zhongshu.reward.server.core.dao.extend.WalletDaoExtend;
+import com.zhongshu.reward.server.core.domain.Wallet;
+
+/**
+ * @author wjf
+ * @date 2024/8/5
+ */
+public interface WalletDao extends MongoDao<Wallet>, WalletDaoExtend {
+
+    Wallet findByUserId(String userId);
+
+    Wallet findTop1ById(String id);
+}

+ 17 - 0
RewardServer/src/main/java/com/zhongshu/reward/server/core/dao/WalletReceiptsDao.java

@@ -0,0 +1,17 @@
+package com.zhongshu.reward.server.core.dao;
+
+import com.github.microservice.components.data.mongo.mongo.dao.MongoDao;
+import com.zhongshu.reward.server.core.domain.WalletReceipts;
+
+import java.util.List;
+
+/**
+ * @author wjf
+ * @date 2024/8/6
+ */
+public interface WalletReceiptsDao extends MongoDao<WalletReceipts> {
+
+    List<WalletReceipts> findByWallet_IdOrderByCreateTimeDesc(String walletId);
+
+    WalletReceipts findTopByOutTradeNo(String outTradeNo);
+}

+ 20 - 0
RewardServer/src/main/java/com/zhongshu/reward/server/core/dao/WxTransferBatchDao.java

@@ -0,0 +1,20 @@
+package com.zhongshu.reward.server.core.dao;
+
+
+import com.github.microservice.components.data.mongo.mongo.dao.MongoDao;
+import com.zhongshu.reward.client.type.TransferStatus;
+import com.zhongshu.reward.server.core.dao.extend.WxTransferBatchDaoExtend;
+import com.zhongshu.reward.server.core.domain.WxTransferBatch;
+
+import java.util.List;
+
+/**
+ * @author wjf
+ * @date 2024/8/5
+ */
+public interface WxTransferBatchDao extends MongoDao<WxTransferBatch>, WxTransferBatchDaoExtend {
+
+    WxTransferBatch findTop1ById(String id);
+
+    List<WxTransferBatch> findByTransferStatus(TransferStatus transferStatus);
+}

+ 10 - 0
RewardServer/src/main/java/com/zhongshu/reward/server/core/dao/extend/WalletDaoExtend.java

@@ -0,0 +1,10 @@
+package com.zhongshu.reward.server.core.dao.extend;
+
+/**
+ * @author wjf
+ * @date 2024/8/5
+ */
+public interface WalletDaoExtend {
+
+    boolean resetTodayAmount();
+}

+ 22 - 0
RewardServer/src/main/java/com/zhongshu/reward/server/core/dao/extend/WxTransferBatchDaoExtend.java

@@ -0,0 +1,22 @@
+package com.zhongshu.reward.server.core.dao.extend;
+
+
+import com.zhongshu.reward.client.type.TransferStatus;
+import com.zhongshu.reward.server.core.domain.WxTransferBatch;
+
+import java.util.List;
+
+/**
+ * @author wjf
+ * @date 2024/8/5
+ */
+public interface WxTransferBatchDaoExtend {
+
+    List<WxTransferBatch> list(String walletId, Long startTime, Long endTime);
+
+    boolean updateStatus(String id, String batchStatus, String detailStatus, TransferStatus transferStatus);
+
+    Long countByTime(String walletId, Long startTime, Long endTime);
+
+    Integer sumDayTotal(String walletId, Long startTime, Long endTime);
+}

+ 43 - 0
RewardServer/src/main/java/com/zhongshu/reward/server/core/domain/InviteReceiptsRole.java

@@ -0,0 +1,43 @@
+package com.zhongshu.reward.server.core.domain;
+
+import com.github.microservice.components.data.mongo.mongo.domain.SuperEntity;
+import com.zhongshu.reward.client.type.ComputationType;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import java.math.BigDecimal;
+
+/**
+ * @author wjf
+ * @date 2024/8/7
+ */
+@Data
+@Builder
+@Document
+@AllArgsConstructor
+@NoArgsConstructor
+public class InviteReceiptsRole extends SuperEntity {
+
+    @ApiModelProperty("规则名称")
+    private String roleName;
+
+    @ApiModelProperty("套餐id")
+    private String setMealId;
+
+    @ApiModelProperty("计算规则:固定、百分比")
+    private ComputationType computation;
+
+    @ApiModelProperty("金额额度")
+    private BigDecimal baseTotal;
+
+    @ApiModelProperty("生效状态")
+    private boolean disable;
+
+    @ApiModelProperty("生效范围是否所有")
+    private boolean isALL = true;
+
+}

+ 86 - 0
RewardServer/src/main/java/com/zhongshu/reward/server/core/domain/TransferRuler.java

@@ -0,0 +1,86 @@
+package com.zhongshu.reward.server.core.domain;
+
+import com.github.microservice.components.data.mongo.mongo.domain.SuperEntity;
+import com.zhongshu.reward.client.type.TimeUnitType;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import java.math.BigDecimal;
+
+/**
+ * 提现规则设置
+ * @author wjf
+ * @date 2024/8/7
+ */
+@Data
+@Builder
+@Document
+@AllArgsConstructor
+@NoArgsConstructor
+public class TransferRuler extends SuperEntity {
+
+    /**
+     * 单笔最小提现金额
+     */
+    private BigDecimal minTotal = BigDecimal.ZERO;
+
+    /**
+     * 单笔最大提现金额
+     */
+    private BigDecimal maxTotal = BigDecimal.ZERO;
+
+    /**
+     * 单日最大转账金额
+     */
+    private BigDecimal dayMaxTotal = BigDecimal.ZERO;
+
+    /**
+     * 提现手续费
+     */
+    private BigDecimal commission = BigDecimal.ZERO;
+
+    /**
+     * 提现次数
+     */
+    private Integer size;
+
+    /**
+     * 时间单位
+     */
+    private TimeUnitType timeUnit;
+
+    /**
+     * 每月开始号数
+     */
+    private Integer startDay;
+
+    /**
+     * 每月结束号数
+     */
+    private Integer endDay;
+
+    /**
+     * 每日开始时
+     */
+    private Integer startHour;
+
+    /**
+     * 每日开始分
+     */
+    private Integer startMinute;
+
+    /**
+     * 每日结束时
+     */
+    private Integer endHour;
+
+    /**
+     * 每日结束时
+     */
+    private Integer endMinute;
+
+}

+ 59 - 0
RewardServer/src/main/java/com/zhongshu/reward/server/core/domain/Wallet.java

@@ -0,0 +1,59 @@
+package com.zhongshu.reward.server.core.domain;
+
+import com.github.microservice.components.data.mongo.mongo.domain.SuperEntity;
+import com.zhongshu.reward.client.type.DataState;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.data.mongodb.core.index.Indexed;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import java.math.BigDecimal;
+
+/**
+ * 钱包
+ * @author wjf
+ * @date 2024/8/5
+ */
+@Data
+@Builder
+@Document
+@AllArgsConstructor
+@NoArgsConstructor
+public class Wallet extends SuperEntity {
+
+    /**
+     * 用户id
+     */
+    @Indexed
+    private String userId;
+
+    /**
+     * 商铺id
+     */
+    @Indexed
+    private String shopId;
+
+
+    /**
+     * 账户余额(可提现金额)
+     */
+    private BigDecimal amount = BigDecimal.ZERO;
+
+    /**
+     * 未结算金额
+     */
+    private BigDecimal waitAmount = BigDecimal.ZERO;
+
+    /**
+     * 当日已提现金额
+     */
+    private BigDecimal todayTransferAmount = BigDecimal.ZERO;
+
+    /**
+     * 钱包状态
+     */
+    private DataState dataState;
+
+}

+ 62 - 0
RewardServer/src/main/java/com/zhongshu/reward/server/core/domain/WalletReceipts.java

@@ -0,0 +1,62 @@
+package com.zhongshu.reward.server.core.domain;
+
+import com.github.microservice.components.data.mongo.mongo.domain.SuperEntity;
+import com.zhongshu.reward.client.type.ReceiptsStatus;
+import com.zhongshu.reward.client.type.ReceiptsType;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.data.mongodb.core.mapping.DBRef;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import java.math.BigDecimal;
+
+/**
+ * 到账记录
+ * @author wjf
+ * @date 2024/8/5
+ */
+@Data
+@Builder
+@Document
+@AllArgsConstructor
+@NoArgsConstructor
+public class WalletReceipts extends SuperEntity {
+
+    /**
+     * 钱包
+     */
+    @DBRef(lazy = true)
+    private Wallet wallet;
+
+    /**
+     * 预计到账时间
+     */
+    private Long estimatedTime;
+
+    /**
+     * 实际到账时间
+     */
+    private Long receiptsTime;
+
+    /**
+     * 到账类型
+     */
+    private ReceiptsType receiptsType;
+
+    /**
+     * 到账金额
+     */
+    private BigDecimal total = BigDecimal.ZERO;
+
+    /**
+     * 状态
+     */
+    private ReceiptsStatus status;
+
+    /**
+     * 外部订单号
+     */
+    private String outTradeNo;
+}

+ 109 - 0
RewardServer/src/main/java/com/zhongshu/reward/server/core/domain/WxTransferBatch.java

@@ -0,0 +1,109 @@
+package com.zhongshu.reward.server.core.domain;
+
+import com.github.microservice.components.data.mongo.mongo.domain.SuperEntity;
+import com.zhongshu.reward.client.type.TransferChannel;
+import com.zhongshu.reward.client.type.TransferStatus;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.data.mongodb.core.index.Indexed;
+import org.springframework.data.mongodb.core.mapping.DBRef;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import java.math.BigDecimal;
+
+/**
+ * 提现记录
+ * @author wjf
+ * @date 2024/8/5
+ */
+@Data
+@Builder
+@Document
+@AllArgsConstructor
+@NoArgsConstructor
+public class WxTransferBatch extends SuperEntity {
+
+    /**
+     * 内部批次单号
+     */
+    @Indexed(unique = true)
+    private String batchNo;
+
+    /**
+     * (内部)提现明细单号
+     */
+    @Indexed
+    private String detailNo;
+
+    /**
+     * 提现钱包
+     */
+    @DBRef(lazy = true)
+    private Wallet wallet;
+
+    /**
+     * 提现金额
+     */
+    private BigDecimal total;
+
+    /**
+     * 提现渠道
+     */
+    @Indexed
+    private TransferChannel channel;
+
+    /**
+     * 提现前账户信息
+     */
+    private Wallet beforeWalletInfo;
+
+//    /**
+//     * 到账时间
+//     */
+//    private Long tradeTime;
+
+    /**
+     * 订单状态
+     */
+    @Indexed
+    private TransferStatus transferStatus;
+
+    /**
+     * 批次状态
+     */
+    @Indexed
+    private String batchStatus;
+
+    /**
+     * 明细状态
+     */
+    @Indexed
+    private String detailStatus;
+
+
+    private String closeReason;
+
+    /**
+     * wx批次单号
+     */
+    @Indexed
+    private String wxBatchId;
+
+    /**
+     * wx批次单号
+     */
+    @Indexed
+    private String wxDetailId;
+
+    /**
+     * openid
+     */
+    private String openid;
+
+    /**
+     * 异常原因
+     */
+    private String failReason;
+}

+ 42 - 0
RewardServer/src/main/java/com/zhongshu/reward/server/core/domain/WxTransferScene.java

@@ -0,0 +1,42 @@
+package com.zhongshu.reward.server.core.domain;
+
+import com.github.microservice.components.data.mongo.mongo.domain.SuperEntity;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.data.mongodb.core.index.Indexed;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import java.math.BigDecimal;
+
+/**
+ * 微信转账场景
+ * @author wjf
+ * @date 2024/8/5
+ */
+@Data
+@Builder
+@Document
+@AllArgsConstructor
+@NoArgsConstructor
+public class WxTransferScene extends SuperEntity {
+
+    /**
+     * 转账场景id
+     */
+    @Indexed
+    private String sceneId;
+
+    /**
+     * 单次转账额度
+     */
+    private BigDecimal onceTotal;
+
+    /**
+     * 单日转账额度
+     */
+    private BigDecimal dayTotal;
+
+
+}

+ 23 - 0
RewardServer/src/main/java/com/zhongshu/reward/server/core/listener/VipEventListener.java

@@ -0,0 +1,23 @@
+package com.zhongshu.reward.server.core.listener;
+
+import com.github.microservice.auth.client.event.auth.EnterpriseApplicationEvent;
+import com.zhongshu.vip.client.event.VipUserEvent;
+import lombok.extern.slf4j.Slf4j;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.context.ApplicationListener;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author wjf
+ * @date 2024/8/7
+ */
+@Slf4j
+@Order(100)
+@Component
+public class VipEventListener implements ApplicationListener<VipUserEvent> {
+    @Override
+    public void onApplicationEvent(VipUserEvent event) {
+        log.info("收到用户会员订阅消息:{}", event.getStreamModel());
+    }
+}

+ 117 - 0
RewardServer/src/main/java/com/zhongshu/reward/server/core/service/ChatTransferBatchService.java

@@ -0,0 +1,117 @@
+package com.zhongshu.reward.server.core.service;
+
+import cn.hutool.core.lang.Snowflake;
+import com.wechat.pay.java.core.Config;
+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.service.transferbatch.TransferBatchService;
+import com.wechat.pay.java.service.transferbatch.model.*;
+import com.zhongshu.reward.client.model.wallet.TransferModel;
+import com.zhongshu.reward.client.model.wallet.TransferStatusModel;
+import com.zhongshu.reward.server.core.config.WeChatConfig;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+
+@Service
+@Slf4j
+public class ChatTransferBatchService {
+
+    @Autowired
+    WeChatConfig weChatConfig;
+
+
+//    @Autowired
+//    TransferBatchService service;
+
+    public static TransferBatchService service;
+
+    @Autowired
+    Snowflake snowflake;
+
+
+
+    public  Config RSAAutoCertificateConfig(){
+        // 初始化商户配置
+        return new  RSAAutoCertificateConfig.Builder()
+                        .merchantId(weChatConfig.getMerchantId())
+                        // 使用 com.wechat.pay.java.core.util
+                        // 中的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名
+                        .privateKey(weChatConfig.getPrivateKey())
+                        .merchantSerialNumber(weChatConfig.getMerchantSerialNumber())
+                        .apiV3Key(weChatConfig.getApiV3Key())
+                        .build();
+
+    }
+
+
+    /**
+     * 通过微信批次单号查询批次单
+     */
+    public  TransferBatchEntity getTransferBatchByNo(TransferStatusModel transferStatusModel) {
+        Config config = RSAAutoCertificateConfig();
+        // 初始化服务
+        service = new TransferBatchService.Builder().config(config).build();
+
+        GetTransferBatchByNoRequest request = new GetTransferBatchByNoRequest();
+        BeanUtils.copyProperties(transferStatusModel, request);
+        return service.getTransferBatchByNo(request);
+    }
+
+//    /**
+//     * 通过商家批次单号查询批次单
+//     */
+//    public  TransferBatchEntity getTransferBatchByOutNo() {
+//
+//        GetTransferBatchByOutNoRequest request = new GetTransferBatchByOutNoRequest();
+//        return service.getTransferBatchByOutNo(request);
+//    }
+
+    /**
+     * 发起商家转账
+     */
+    public InitiateBatchTransferResponse initiateBatchTransfer(TransferModel transferModel) {
+        Config config = RSAAutoCertificateConfig();
+        // 初始化服务
+        service = new TransferBatchService.Builder().config(config).build();
+        try {
+            InitiateBatchTransferRequest request = new InitiateBatchTransferRequest();
+            BeanUtils.copyProperties(transferModel,request);
+            request.setAppid(weChatConfig.getAppid());
+            request.setTransferSceneId(transferModel.getTransferSceneId());
+            return service.initiateBatchTransfer(request);
+        } catch (HttpException e) { // 发送HTTP请求失败
+            // 调用e.getHttpRequest()获取请求打印日志或上报监控,更多方法见HttpException定义
+            log.info("发送HTTP请求失败:{}", e.getHttpRequest());
+        } catch (ServiceException e) { // 服务返回状态小于200或大于等于300,例如500
+            // 调用e.getResponseBody()获取返回体打印日志或上报监控,更多方法见ServiceException定义
+            log.info("请求失败2:{}", e.getResponseBody());
+        } catch (MalformedMessageException e) { // 服务返回成功,返回体类型不合法,或者解析返回体失败
+            // 调用e.getMessage()获取信息打印日志或上报监控,更多方法见MalformedMessageException定义
+            log.info("请求失败3:{}", e.getMessage());
+        }
+        return null;
+    }
+
+//    /**
+//     * 通过微信明细单号查询明细单
+//     */
+//    public  TransferDetailEntity getTransferDetailByNo() {
+//
+//        GetTransferDetailByNoRequest request = new GetTransferDetailByNoRequest();
+//        return service.getTransferDetailByNo(request);
+//    }
+//
+//    /**
+//     * 通过商家明细单号查询明细单
+//     */
+//    public  TransferDetailEntity getTransferDetailByOutNo() {
+//
+//        GetTransferDetailByOutNoRequest request = new GetTransferDetailByOutNoRequest();
+//        return service.getTransferDetailByOutNo(request);
+//    }
+}

+ 8 - 0
RewardServer/src/main/java/com/zhongshu/reward/server/core/service/Impl/WalletFeignServiceImpl.java

@@ -0,0 +1,8 @@
+package com.zhongshu.reward.server.core.service.Impl;
+
+/**
+ * @author wjf
+ * @date 2024/8/5
+ */
+public class WalletFeignServiceImpl {
+}

+ 65 - 0
RewardServer/src/main/java/com/zhongshu/reward/server/core/service/InviteReceiptsRoleService.java

@@ -0,0 +1,65 @@
+package com.zhongshu.reward.server.core.service;
+
+import com.zhongshu.reward.client.model.InviteReceiptsRoleModel;
+import com.zhongshu.reward.client.ret.ResultContent;
+import com.zhongshu.reward.server.core.dao.InviteReceiptsRoleDao;
+import com.zhongshu.reward.server.core.domain.InviteReceiptsRole;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.awt.print.Pageable;
+
+/**
+ * @author wjf
+ * @date 2024/8/7
+ */
+@Service
+public class InviteReceiptsRoleService {
+
+    @Autowired
+    InviteReceiptsRoleDao inviteReceiptsRoleDao;
+
+    /**
+     * 添加推广规则
+     * @param inviteReceiptsRoleModel
+     * @return
+     */
+//    public Object add(InviteReceiptsRoleModel inviteReceiptsRoleModel){
+//        boolean existsBySetMeal= inviteReceiptsRoleDao.existsBySetMealIdAndDisable(inviteReceiptsRoleModel.getSetMealId(), false);
+//        if (existsBySetMeal){
+//            return ResultContent.buildFail("该套餐存在推广规则");
+//        }
+//        InviteReceiptsRole inviteReceiptsRole = new InviteReceiptsRole();
+//        BeanUtils.copyProperties(inviteReceiptsRoleModel, inviteReceiptsRole);
+//        return ResultContent.buildContent(toModel(inviteReceiptsRoleDao.save(inviteReceiptsRole)));
+//    }
+
+    public Object update(InviteReceiptsRoleModel inviteReceiptsRoleModel){
+        if (StringUtils.isEmpty(inviteReceiptsRoleModel.getId())) {//添加
+            boolean existsBySetMeal= inviteReceiptsRoleDao.existsBySetMealIdAndDisable(inviteReceiptsRoleModel.getSetMealId(), false);
+            if (existsBySetMeal){
+                return ResultContent.buildFail("该套餐存在推广规则");
+            }
+        }else if (!inviteReceiptsRoleDao.existsById(inviteReceiptsRoleModel.getId())){
+            return ResultContent.buildContent("找不到要修改的推广规则");
+        }
+
+        InviteReceiptsRole inviteReceiptsRole = new InviteReceiptsRole();
+        BeanUtils.copyProperties(inviteReceiptsRoleModel, inviteReceiptsRole);
+        return ResultContent.buildContent(toModel(inviteReceiptsRoleDao.save(inviteReceiptsRole)));
+    }
+
+
+
+
+    InviteReceiptsRoleModel toModel(InviteReceiptsRole inviteReceiptsRole){
+        InviteReceiptsRoleModel model = new InviteReceiptsRoleModel();
+        if (ObjectUtils.isNotEmpty(inviteReceiptsRole)){
+            BeanUtils.copyProperties(inviteReceiptsRole, model);
+        }
+        return model;
+    }
+}

+ 98 - 0
RewardServer/src/main/java/com/zhongshu/reward/server/core/service/WalletReceiptsService.java

@@ -0,0 +1,98 @@
+package com.zhongshu.reward.server.core.service;
+
+import com.github.microservice.core.util.result.content.ResultContent;
+import com.github.microservice.core.util.result.content.ResultState;
+import com.zhongshu.reward.client.model.param.WalletReceiptsParam;
+import com.zhongshu.reward.client.model.wallet.WalletReceiptsModel;
+import com.zhongshu.reward.client.type.ReceiptsStatus;
+import com.zhongshu.reward.server.core.dao.WalletDao;
+import com.zhongshu.reward.server.core.dao.WalletReceiptsDao;
+import com.zhongshu.reward.server.core.domain.Wallet;
+import com.zhongshu.reward.server.core.domain.WalletReceipts;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.ObjectUtils;
+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.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * @author wjf
+ * @date 2024/8/6
+ */
+@Service
+@Slf4j
+public class WalletReceiptsService {
+
+    @Autowired
+    WalletDao walletDao;
+
+    @Autowired
+    WalletService walletService;
+
+    @Autowired
+    WalletReceiptsDao walletReceiptsDao;
+
+    /**
+     * 邀请返利入账
+     * @param param
+     * @return
+     */
+    @Transactional
+    public Object receipts(WalletReceiptsParam param){
+
+        Wallet wallet = walletService.getWalletByUserId(param.getUserId());
+
+        WalletReceipts walletReceipts = new WalletReceipts();
+        BeanUtils.copyProperties(param, walletReceipts);
+        walletReceipts.setWallet(wallet);
+        if (walletReceipts.getReceiptsType()==null){
+            walletReceipts.setStatus(ReceiptsStatus.WAIT);
+        }
+        wallet.setWaitAmount(wallet.getWaitAmount().add(param.getTotal()));
+        walletDao.save(wallet);
+        return ResultContent.buildContent(toModel(walletReceiptsDao.save(walletReceipts)));
+    }
+
+    /**
+     * 取消返利入账
+     * @param
+     * @return
+     */
+    @Transactional
+    public Object cancelReceipts(String outTradeNo){
+
+        WalletReceipts walletReceipts = walletReceiptsDao.findTopByOutTradeNo(outTradeNo);
+        if (ObjectUtils.isEmpty(walletReceipts)){
+            return ResultContent.build(ResultState.Fail,"返利订单不存在或未入账");
+        }
+        if (!walletReceipts.getStatus().equals(ReceiptsStatus.WAIT)){
+            return ResultContent.build(ResultState.Fail,"订单不处于未结算状态");
+        }
+
+        walletReceipts.setStatus(ReceiptsStatus.CANCEL);
+        walletReceiptsDao.save(walletReceipts);
+        Wallet wallet = walletDao.findTop1ById(walletReceipts.getWallet().getId());
+        wallet.setWaitAmount(wallet.getWaitAmount().subtract(walletReceipts.getTotal()));
+        walletDao.save(wallet);
+        return ResultContent.build(ResultState.Success);
+    }
+
+    public Object listByWallet(String walletId){
+        List<WalletReceipts> list = walletReceiptsDao.findByWallet_IdOrderByCreateTimeDesc(walletId);
+        return ResultContent.buildContent(list.stream().map(this::toModel).collect(Collectors.toList()));
+    }
+
+    WalletReceiptsModel toModel(WalletReceipts walletReceipts){
+        WalletReceiptsModel model = new WalletReceiptsModel();
+        if (null != walletReceipts){
+            BeanUtils.copyProperties(walletReceipts, model, "wallet");
+            model.setWalletId(walletReceipts.getWallet().getId());
+        }
+        return model;
+    }
+}

+ 58 - 0
RewardServer/src/main/java/com/zhongshu/reward/server/core/service/WalletService.java

@@ -0,0 +1,58 @@
+package com.zhongshu.reward.server.core.service;
+
+import com.github.microservice.auth.security.helper.AuthHelper;
+import com.github.microservice.core.util.result.content.ResultContent;
+import com.zhongshu.reward.client.model.wallet.WalletModel;
+import com.zhongshu.reward.client.type.DataState;
+import com.zhongshu.reward.server.core.dao.WalletDao;
+import com.zhongshu.reward.server.core.domain.Wallet;
+import org.apache.commons.lang3.ObjectUtils;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author wjf
+ * @date 2024/8/5
+ */
+@Service
+public class WalletService {
+
+    @Autowired
+    AuthHelper authHelper;
+
+    @Autowired
+    WalletDao walletDao;
+
+    /**
+     * 获取当前登录用户(开通)钱包
+     */
+    public ResultContent getWallet(String userId){
+        Wallet wallet = getWalletByUserId(userId);
+        return ResultContent.buildContent(toModel(wallet));
+    }
+
+    @NotNull
+    public Wallet getWalletByUserId(String userId) {
+        if (ObjectUtils.isEmpty(userId)){
+            userId = authHelper.getCurrentUser().getUserId();
+        }
+        Wallet wallet = walletDao.findByUserId(userId);
+        if (wallet==null){
+            wallet = new Wallet();
+            wallet.setUserId(userId);
+            wallet.setDataState(DataState.Enable);
+            wallet = walletDao.save(wallet);
+        }
+        return wallet;
+    }
+
+    private WalletModel toModel(Wallet wallet){
+        WalletModel walletModel = new WalletModel();
+        if (wallet!=null){
+            BeanUtils.copyProperties(wallet, walletModel);
+        }
+        return walletModel;
+    }
+}

+ 226 - 0
RewardServer/src/main/java/com/zhongshu/reward/server/core/service/WxTransferService.java

@@ -0,0 +1,226 @@
+package com.zhongshu.reward.server.core.service;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.lang.Snowflake;
+import com.github.microservice.auth.client.content.ResultContent;
+import com.github.microservice.auth.client.content.ResultState;
+import com.wechat.pay.java.service.transferbatch.model.InitiateBatchTransferResponse;
+import com.wechat.pay.java.service.transferbatch.model.TransferBatchEntity;
+import com.wechat.pay.java.service.transferbatch.model.TransferDetailInput;
+import com.zhongshu.reward.client.model.param.WalletTransferParam;
+import com.zhongshu.reward.client.model.wallet.TransferModel;
+import com.zhongshu.reward.client.model.wallet.TransferStatusModel;
+import com.zhongshu.reward.client.model.wallet.WxTransferBatchModel;
+import com.zhongshu.reward.client.ret.CommentException;
+import com.zhongshu.reward.client.type.TimeUnitType;
+import com.zhongshu.reward.client.type.TransferChannel;
+import com.zhongshu.reward.client.type.TransferStatus;
+import com.zhongshu.reward.server.core.dao.TransferRulerDao;
+import com.zhongshu.reward.server.core.dao.WalletDao;
+import com.zhongshu.reward.server.core.dao.WxTransferBatchDao;
+import com.zhongshu.reward.server.core.domain.TransferRuler;
+import com.zhongshu.reward.server.core.domain.Wallet;
+import com.zhongshu.reward.server.core.domain.WxTransferBatch;
+import com.zhongshu.reward.server.core.util.DateUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.ObjectUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.aggregation.DateOperators;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalAdjusters;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author wjf
+ * @date 2024/8/5
+ */
+@Service
+@Slf4j
+public class WxTransferService {
+
+    @Autowired
+    WalletDao walletDao;
+
+    @Autowired
+    ChatTransferBatchService wechatService;
+
+    @Autowired
+    Snowflake snowflake;
+
+    @Autowired
+    WxTransferBatchDao wxTransferBatchDao;
+
+    @Autowired
+    TransferRulerDao transferRulerDao;
+
+
+    /**
+     * 发起提现
+     * @param param
+     * @return
+     */
+    @Transactional
+    public Object transfer(WalletTransferParam param){
+        Wallet wallet = walletDao.findTop1ById(param.getWalletId());
+        //校验提现规则
+        validTransfer(param.getTotal(), wallet);
+
+        String outBatchNo = snowflake.nextIdStr();
+        String outDetailNo = snowflake.nextIdStr();
+
+        TransferModel transferModel = new TransferModel();
+        transferModel.setBatchName("佣金/返利发放");
+        transferModel.setBatchRemark("佣金/返利发放");
+        transferModel.setTotalAmount(param.getTotal().longValue());
+        transferModel.setOutBatchNo(outBatchNo);
+
+        List<TransferDetailInput> detailList = new ArrayList<>();
+        TransferDetailInput detail = new TransferDetailInput();
+        detail.setTransferAmount(param.getTotal().longValue());
+        detail.setTransferRemark("佣金/返利发放");
+        detail.setOpenid(param.getOpenid());
+        detail.setOutDetailNo(outDetailNo);
+        detailList.add(detail);
+        transferModel.setTotalNum(detailList.size());
+        transferModel.setTransferDetailList(detailList);
+
+        InitiateBatchTransferResponse response = wechatService.initiateBatchTransfer(transferModel);
+        if (response==null){
+            return ResultContent.build(ResultState.Fail);
+        }
+
+        WxTransferBatch wxTransferBatch = new WxTransferBatch();
+        wxTransferBatch.setBatchNo(outBatchNo);
+        wxTransferBatch.setDetailNo(outDetailNo);
+        wxTransferBatch.setWallet(wallet);
+        wxTransferBatch.setTotal(param.getTotal());
+        wxTransferBatch.setChannel(TransferChannel.WeChat);
+        wxTransferBatch.setBeforeWalletInfo(wallet);
+        wxTransferBatch.setBatchStatus(response.getBatchStatus());
+        wxTransferBatch.setWxBatchId(response.getBatchId());
+        wxTransferBatch.setTransferStatus(TransferStatus.PROCESSING);
+
+        wxTransferBatchDao.save(wxTransferBatch);
+        wallet.setAmount(wallet.getAmount().subtract(param.getTotal()));
+        wallet.setTodayTransferAmount(wallet.getTodayTransferAmount().add(param.getTotal()));
+        walletDao.save(wallet);
+        return ResultContent.build(ResultState.Success);
+    }
+
+
+
+    public Object queryTransfer(String walletId, Integer year, Integer month){
+        Long monthStartTime = DateUtils.getMonthStartTime(year, month);
+        Long monthEndTime = DateUtils.getMonthEndTime(year, month);
+        List<WxTransferBatch> list = wxTransferBatchDao.list(walletId, monthStartTime, monthEndTime);
+        return ResultContent.buildContent(list.stream().map(this::toModel).collect(Collectors.toList()));
+    }
+
+    @Transactional
+    public Object updateTransferStatus(String transferId){
+        WxTransferBatch wxTransferBatch = wxTransferBatchDao.findTop1ById(transferId);
+        if (ObjectUtils.isEmpty(wxTransferBatch)){
+            return ResultContent.build(ResultState.Fail, "提现订单不存在");
+        }
+
+        TransferStatus transferStatus = wxTransferBatch.getTransferStatus();
+        if (!transferStatus.equals(TransferStatus.PROCESSING)){
+            return ResultContent.build(ResultState.Success);
+        }
+
+        TransferStatusModel transferStatusModel = new TransferStatusModel();
+        transferStatusModel.setBatchId(wxTransferBatch.getWxBatchId());
+        transferStatusModel.setNeedQueryDetail(true);
+        transferStatusModel.setDetailStatus("ALL");
+        TransferBatchEntity transferBatchByNo = wechatService.getTransferBatchByNo(transferStatusModel);
+
+        String batchStatus = transferBatchByNo.getTransferBatch().getBatchStatus();
+        String detailStatus = transferBatchByNo.getTransferDetailList().get(0).getDetailStatus();
+
+        if(batchStatus.equals("FINISHED") && detailStatus.equals("SUCCESS")){
+            transferStatus = TransferStatus.SUCCESS;
+        }else if(batchStatus.equals("CLOSED")){
+            transferStatus = TransferStatus.CLOSE;
+            Wallet wallet = walletDao.findTop1ById(wxTransferBatch.getWallet().getId());
+            wallet.setAmount(wallet.getAmount().add(wxTransferBatch.getTotal()));
+            wallet.setTodayTransferAmount(wallet.getTodayTransferAmount().subtract(wxTransferBatch.getTotal()));
+            walletDao.save(wallet);
+        }else if (detailStatus.equals("FAIL")){
+            transferStatus = TransferStatus.FAIL;
+            Wallet wallet = walletDao.findTop1ById(wxTransferBatch.getWallet().getId());
+            wallet.setAmount(wallet.getAmount().add(wxTransferBatch.getTotal()));
+            wallet.setTodayTransferAmount(wallet.getTodayTransferAmount().subtract(wxTransferBatch.getTotal()));
+            walletDao.save(wallet);
+        }
+        boolean update = wxTransferBatchDao.updateStatus(transferId, batchStatus, detailStatus, transferStatus);
+        log.info("更新微信转账批次状态:结果:{}, id:{}, batchStatus:{}, detailStatus: {}, transferStatus: {}",update, transferId, batchStatus, detailStatus, transferStatus);
+        return ResultContent.build(update);
+    }
+
+    WxTransferBatchModel toModel(WxTransferBatch wxTransferBatch){
+        WxTransferBatchModel model = new WxTransferBatchModel();
+        if (null != wxTransferBatch){
+            BeanUtil.copyProperties(wxTransferBatch, model, "beforeWalletInfo", "wallet");
+            model.setWalletId(wxTransferBatch.getWallet().getId());
+        }
+        return model;
+    }
+
+    void validTransfer(BigDecimal total, Wallet wallet){
+        long currentTime = System.currentTimeMillis();
+        Integer size = 0;
+        List<TransferRuler> list = transferRulerDao.findAll();
+        if (list.isEmpty()){
+            throw new CommentException(com.zhongshu.reward.client.ret.ResultState.Exception, "管理员未设置提现规则");
+        }
+        TransferRuler transferRuler = list.get(0);
+        //提现时间
+        if (transferRuler.getTimeUnit().equals(TimeUnitType.MONTH)){//每月
+            Long dayOfMonthStartTime = DateUtils.getDayOfMonthStartTime(transferRuler.getStartDay());
+            Long dayOfMonthEndTime = DateUtils.getDayOfMonthEndTime(transferRuler.getEndDay());
+            if (currentTime < dayOfMonthStartTime || currentTime > dayOfMonthEndTime){
+                throw new CommentException(com.zhongshu.reward.client.ret.ResultState.Exception, "当前不处于提现时间段");
+            }
+            size = wxTransferBatchDao.countByTime(wallet.getId(), dayOfMonthStartTime, dayOfMonthEndTime).intValue();
+        }else if (transferRuler.getTimeUnit().equals(TimeUnitType.DAY)){
+            Long hourMinuteStartTime = DateUtils.getHourMinuteStartTime(transferRuler.getStartHour(), transferRuler.getStartMinute());
+            Long hourMinuteEndTime = DateUtils.getHourMinuteEndTime(transferRuler.getEndHour(), transferRuler.getEndMinute());
+            if (currentTime < hourMinuteStartTime || currentTime > hourMinuteEndTime){
+                throw new CommentException(com.zhongshu.reward.client.ret.ResultState.Exception, "当前不处于提现时间段");
+            }
+            size = wxTransferBatchDao.countByTime(wallet.getId(), hourMinuteStartTime, hourMinuteEndTime).intValue();
+        }
+        //单笔金额
+        if (total.compareTo(transferRuler.getMinTotal()) < 0){
+            throw new CommentException(com.zhongshu.reward.client.ret.ResultState.Exception, "单笔提现金额低于最小值");
+        }else if (total.compareTo(transferRuler.getMaxTotal()) > 0){
+            throw new CommentException(com.zhongshu.reward.client.ret.ResultState.Exception, "单笔提现金额超出最大值");
+        }
+
+        //判断提现额度是否超出每日上限
+        Integer sumDayTotal = wxTransferBatchDao.sumDayTotal(wallet.getId(), DateUtils.getCurrentDayStartTime().getTime(), DateUtils.getCurrentDayEndTime().getTime());
+        if (total.add(BigDecimal.valueOf(sumDayTotal)).compareTo(transferRuler.getDayMaxTotal()) > 0){
+            throw new CommentException(com.zhongshu.reward.client.ret.ResultState.Exception, "超出每日提现金额上限");
+//            return ResultContent.build(ResultState.Fail, "超出每日提现金额上限");
+        }
+        //判断可提现金额是否足够
+        if (total.compareTo(wallet.getAmount()) < 0){
+            throw new CommentException(com.zhongshu.reward.client.ret.ResultState.Exception, "可提现余额不足");
+//            return ResultContent.build(ResultState.Fail, "可提现余额不足");
+        }
+        //提现次数
+        if (transferRuler.getSize() >= size){
+            throw new CommentException(com.zhongshu.reward.client.ret.ResultState.Exception, "超过可提现次数");
+        }
+    }
+
+
+}

+ 56 - 0
RewardServer/src/main/java/com/zhongshu/reward/server/core/timer/WalletTimer.java

@@ -0,0 +1,56 @@
+package com.zhongshu.reward.server.core.timer;
+
+
+import com.zhongshu.reward.client.type.TransferStatus;
+import com.zhongshu.reward.server.core.dao.WalletDao;
+import com.zhongshu.reward.server.core.dao.WxTransferBatchDao;
+import com.zhongshu.reward.server.core.domain.WxTransferBatch;
+import com.zhongshu.reward.server.core.service.WxTransferService;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * @author wjf
+ * @date 2024/8/5
+ */
+@Component
+@Log4j2
+public class WalletTimer {
+
+    @Autowired
+    WalletDao walletDao;
+
+    @Autowired
+    WxTransferBatchDao wxTransferBatchDao;
+
+    @Autowired
+    WxTransferService wxTransferService;
+
+    /**
+     * 重置每日提现额度
+     */
+    @Scheduled(cron = "0 0 0 * * ?")
+    public void resetTodayAmount(){
+        try {
+            walletDao.resetTodayAmount();
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+    }
+
+    @Scheduled(fixedRate = 5000)
+    public void updateTransferStatus(){
+        try {
+            List<WxTransferBatch> byTransferStatus = wxTransferBatchDao.findByTransferStatus(TransferStatus.PROCESSING);
+            for (WxTransferBatch wxTransferBatch : byTransferStatus){
+                wxTransferService.updateTransferStatus(wxTransferBatch.getId());
+            }
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+    }
+}

+ 156 - 0
RewardServer/src/main/java/com/zhongshu/reward/server/core/util/DateUtils.java

@@ -0,0 +1,156 @@
+package com.zhongshu.reward.server.core.util;
+
+import cn.hutool.log.Log;
+import lombok.extern.slf4j.Slf4j;
+
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.util.Calendar;
+import java.util.Date;
+
+/**
+ * @author wjf
+ * @date 2024/8/8
+ */
+@Slf4j
+public class DateUtils {
+
+
+    /**
+     * 获得本天的开始时间
+     *
+     * @return
+     */
+    public static Date getCurrentDayStartTime() {
+        ZoneId zoneId = ZoneId.systemDefault();
+        LocalDateTime date = LocalDateTime.now();
+        LocalDateTime startOfTheDay = LocalDateTime.of(date.toLocalDate(), LocalTime.MIN);
+        Date beginTime = Date.from(startOfTheDay.atZone(zoneId).toInstant());
+        return beginTime;
+    }
+
+    /**
+     * 获得本天的结束时间
+     *
+     * @return
+     */
+    public static Date getCurrentDayEndTime() {
+        ZoneId zoneId = ZoneId.systemDefault();
+        LocalDateTime date = LocalDateTime.now();
+        LocalDateTime startOfTheDay = LocalDateTime.of(date.toLocalDate(), LocalTime.MAX);
+        Date beginTime = Date.from(startOfTheDay.atZone(zoneId).toInstant());
+        return beginTime;
+    }
+
+    /**
+     * 本月指定日的开始时间
+     *
+     * @return
+     */
+    public static Long getDayOfMonthStartTime(Integer day) {
+        Calendar c = Calendar.getInstance();
+
+        c.set(Calendar.DATE, 1);
+        c.add(Calendar.DATE, day-1);
+
+        c.set(Calendar.HOUR_OF_DAY, 23);
+        c.set(Calendar.MINUTE, 59);
+        c.set(Calendar.SECOND, 59);
+
+        return c.getTimeInMillis();
+    }
+
+    /**
+     * 本月指定日的结束时间
+     *
+     * @return
+     */
+    public static Long getDayOfMonthEndTime(Integer day) {
+        Calendar c = Calendar.getInstance();
+
+        c.set(Calendar.DATE, 1);
+        c.add(Calendar.DATE, day-1);
+
+        c.set(Calendar.HOUR_OF_DAY, 0);
+        c.set(Calendar.MINUTE, 0);
+        c.set(Calendar.SECOND, 0);
+
+        return c.getTimeInMillis();
+    }
+
+    /**
+     * 指定年月开始时间
+     *
+     * @return
+     */
+    public static Long getMonthStartTime(Integer year, Integer month) {
+        Calendar c = Calendar.getInstance();
+
+        c.set(Calendar.YEAR, year);
+        c.set(Calendar.MONTH, month - 1);
+        c.set(Calendar.DATE, 1);
+
+        c.set(Calendar.HOUR_OF_DAY, 0);
+        c.set(Calendar.MINUTE, 0);
+        c.set(Calendar.SECOND, 0);
+
+        return c.getTimeInMillis();
+
+    }
+
+    /**
+     * 指定年月结束时间
+     *
+     * @return
+     */
+    public static Long getMonthEndTime(Integer year, Integer month) {
+        Calendar c = Calendar.getInstance();
+
+        c.set(Calendar.YEAR, year);
+        c.set(Calendar.MONTH, month - 1);
+        c.add(Calendar.MONTH, 1);
+        c.set(Calendar.DAY_OF_MONTH, 0);
+
+        c.set(Calendar.HOUR_OF_DAY, 23);
+        c.set(Calendar.MINUTE, 59);
+        c.set(Calendar.SECOND, 59);
+        return c.getTimeInMillis();
+    }
+
+    /**
+     * 当天指定时分开始时间 time: HH:mm
+     *
+     * @return
+     */
+    public static Long getHourMinuteStartTime(Integer hour, Integer minute) {
+        Calendar c = Calendar.getInstance();
+
+        c.set(Calendar.HOUR_OF_DAY, hour);
+        c.set(Calendar.MINUTE, minute);
+        c.set(Calendar.SECOND, 59);
+        return c.getTimeInMillis();
+    }
+
+    /**
+     * 当天指定时分结束时间 time: HH:mm
+     *
+     * @return
+     */
+    public static Long getHourMinuteEndTime(Integer hour, Integer minute) {
+        Calendar c = Calendar.getInstance();
+
+        c.set(Calendar.HOUR_OF_DAY, 21);
+        c.set(Calendar.MINUTE, hour);
+        c.set(Calendar.SECOND, minute);
+        return c.getTimeInMillis();
+    }
+
+    public static void main(String[] args) {
+        Calendar c = Calendar.getInstance();
+
+        c.set(Calendar.HOUR_OF_DAY, 21);
+        c.set(Calendar.MINUTE, 50);
+        c.set(Calendar.SECOND, 59);
+    }
+}

+ 1 - 1
RewardServer/src/main/resources/application-dev.yml

@@ -10,7 +10,7 @@ spring:
     database: 6
 
 swagger:
-  packageName: "com.zhongshu.payment.core.controller"
+  packageName: "com.zhongshu.reward.core.controller"
   title: ${project.artifactId}
   description: ${project.description}
   version: "1.0"