Explorar o código

Merge remote-tracking branch 'origin/feature/mall_product' into brokerate

# Conflicts:
#	yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/record/BrokerageRecordConvert.java
#	yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/user/BrokerageUserConvert.java
#	yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/record/BrokerageRecordServiceImpl.java
#	yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/user/BrokerageUserServiceImpl.java
owen hai 1 ano
pai
achega
cddeb37289
Modificáronse 84 ficheiros con 1006 adicións e 580 borrados
  1. 2 2
      sql/mysql/pay_wallet.sql
  2. 1 1
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/CommonResult.java
  3. 18 0
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainActivityApi.java
  4. 2 23
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/dto/BargainRecordCreateReqDTO.java
  5. 21 5
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApi.java
  6. 0 39
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/dto/CombinationRecordUpdateStatusReqDTO.java
  7. 19 0
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApi.java
  8. 50 0
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/dto/SeckillActivityUpdateStockReqDTO.java
  9. 2 1
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
  10. 41 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainActivityApiImpl.java
  11. 14 7
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApiImpl.java
  12. 84 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApiImpl.java
  13. 45 33
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/CombinationRecordDO.java
  14. 10 5
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordService.java
  15. 10 11
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java
  16. 14 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityService.java
  17. 17 13
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java
  18. 0 26
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/util/PromotionUtils.java
  19. 5 0
      yudao-module-mall/yudao-module-trade-biz/pom.xml
  20. 2 1
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/brokerage/BrokerageApiImpl.java
  21. 10 1
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java
  22. 1 1
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleDetailRespVO.java
  23. 3 3
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/BrokerageUserController.java
  24. 0 3
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/vo/BrokerageUserRespVO.java
  25. 5 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/TradeOrderController.java
  26. 8 9
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderDetailRespVO.java
  27. 12 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/AppBrokerageRecordController.java
  28. 16 14
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/AppBrokerageUserController.java
  29. 19 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/record/AppBrokerageProductPriceRespVO.java
  30. 1 1
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserChildSummaryRespVO.java
  31. 1 1
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserMySummaryRespVO.java
  32. 1 1
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserRankByPriceRespVO.java
  33. 3 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserRespVO.java
  34. 0 3
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/withdraw/AppBrokerageWithdrawCreateReqVO.java
  35. 4 4
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java
  36. 6 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementReqVO.java
  37. 1 1
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/aftersale/TradeAfterSaleConvert.java
  38. 8 13
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/record/BrokerageRecordConvert.java
  39. 7 13
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/user/BrokerageUserConvert.java
  40. 3 1
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
  41. 2 2
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/brokerage/user/BrokerageUserDO.java
  42. 1 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/record/BrokerageRecordMapper.java
  43. 1 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/user/BrokerageUserMapper.java
  44. 36 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/redis/no/TradeOrderNoRedisDAO.java
  45. 1 6
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java
  46. 2 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/bo/BrokerageAddReqBO.java
  47. 2 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/bo/UserBrokerageSummaryBO.java
  48. 1 1
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/record/BrokerageRecordService.java
  49. 3 2
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/record/BrokerageRecordServiceImpl.java
  50. 6 4
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/user/BrokerageUserService.java
  51. 26 22
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/user/BrokerageUserServiceImpl.java
  52. 81 47
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java
  53. 0 5
      yudao-module-member/yudao-module-member-biz/pom.xml
  54. 11 1
      yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.http
  55. 8 0
      yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthLoginRespVO.java
  56. 1 11
      yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/AppMemberUserController.java
  57. 1 1
      yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/auth/AuthConvert.java
  58. 17 13
      yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java
  59. 9 0
      yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApi.java
  60. 1 0
      yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java
  61. 5 0
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApiImpl.java
  62. 15 6
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/PayOrderController.java
  63. 1 1
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/AppPayWalletController.java
  64. 2 2
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/vo/wallet/AppPayWalletRespVO.java
  65. 4 0
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/wallet/PayWalletTransactionConvert.java
  66. 2 2
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/wallet/PayWalletDO.java
  67. 18 39
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/wallet/PayWalletMapper.java
  68. 17 17
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/wallet/WalletPayClient.java
  69. 11 3
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderService.java
  70. 12 0
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java
  71. 12 12
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletService.java
  72. 83 109
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletServiceImpl.java
  73. 7 3
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletTransactionService.java
  74. 17 4
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletTransactionServiceImpl.java
  75. 50 0
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/bo/CreateWalletTransactionBO.java
  76. 8 5
      yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialUserApi.java
  77. 27 0
      yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialUserRespDTO.java
  78. 5 4
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialUserApiImpl.java
  79. 4 3
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java
  80. 8 5
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialUserService.java
  81. 5 3
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialUserServiceImpl.java
  82. 3 2
      yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImplTest.java
  83. 10 7
      yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/social/SocialUserServiceImplTest.java
  84. 4 2
      yudao-server/src/main/resources/application-local.yaml

+ 2 - 2
sql/mysql/pay_wallet.sql

@@ -8,8 +8,8 @@ CREATE TABLE `pay_wallet`
     `user_id`        bigint   NOT NULL COMMENT '用户编号',
     `user_type`      tinyint  NOT NULL DEFAULT 0 COMMENT '用户类型',
     `balance`        int      NOT NULL DEFAULT 0 COMMENT '余额,单位分',
-    `total_expense`  bigint      NOT NULL DEFAULT 0 COMMENT '累计支出,单位分',
-    `total_recharge` bigint      NOT NULL DEFAULT 0 COMMENT '累计充值,单位分',
+    `total_expense`  int      NOT NULL DEFAULT 0 COMMENT '累计支出,单位分',
+    `total_recharge` int      NOT NULL DEFAULT 0 COMMENT '累计充值,单位分',
     `creator`        varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
     `create_time`    datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
     `updater`        varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',

+ 1 - 1
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/CommonResult.java

@@ -41,7 +41,7 @@ public class CommonResult<T> implements Serializable {
      * 因为 A 方法返回的 CommonResult 对象,不满足调用其的 B 方法的返回,所以需要进行转换。
      *
      * @param result 传入的 result 对象
-     * @param <T> 返回的泛型
+     * @param <T>    返回的泛型
      * @return 新的 CommonResult 对象
      */
     public static <T> CommonResult<T> error(CommonResult<?> result) {

+ 18 - 0
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainActivityApi.java

@@ -0,0 +1,18 @@
+package cn.iocoder.yudao.module.promotion.api.bargain;
+
+/**
+ * 砍价活动 Api 接口
+ *
+ * @author HUIHUI
+ */
+public interface BargainActivityApi {
+
+    /**
+     * 更新砍价活动库存
+     *
+     * @param activityId 砍价活动编号
+     * @param count      购买数量
+     */
+    void updateBargainActivityStock(Long activityId, Integer count);
+
+}

+ 2 - 23
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/dto/BargainRecordCreateReqDTO.java

@@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.promotion.api.bargain.dto;
 
 import lombok.Data;
 
-import javax.validation.constraints.NotEmpty;
 import javax.validation.constraints.NotNull;
 
 // TODO @芋艿:这块要在看看
@@ -40,17 +39,7 @@ public class BargainRecordCreateReqDTO {
      */
     @NotNull(message = "订单编号不能为空")
     private Long orderId;
-    // TODO @puhui999:spuName、picUrl、 之类字段不用传递;
-    /**
-     * 商品名字
-     */
-    @NotEmpty(message = "商品名字不能为空")
-    private String spuName;
-    /**
-     * 商品图片
-     */
-    @NotEmpty(message = "商品图片不能为空")
-    private String picUrl;
+
     /**
      * 砍价商品单价
      */
@@ -61,17 +50,7 @@ public class BargainRecordCreateReqDTO {
      */
     @NotNull(message = "商品原价不能为空")
     private Integer price;
-    // TODO @puhui999:nickname、avatar 不用传递,去查询;
-    /**
-     * 用户昵称
-     */
-    @NotEmpty(message = "用户昵称不能为空")
-    private String nickname;
-    /**
-     * 用户头像
-     */
-    @NotEmpty(message = "用户头像不能为空")
-    private String avatar;
+
     /**
      * 开团状态:进行中 砍价成功 砍价失败
      */

+ 21 - 5
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApi.java

@@ -2,9 +2,9 @@ package cn.iocoder.yudao.module.promotion.api.combination;
 
 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO;
-import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordUpdateStatusReqDTO;
 
 import javax.validation.Valid;
+import java.time.LocalDateTime;
 import java.util.List;
 
 // TODO @芋艿:后面也再撸撸这几个接口
@@ -51,13 +51,29 @@ public interface CombinationRecordApi {
      */
     void validateCombinationLimitCount(Long activityId, Integer count, Integer sumCount);
 
-    // TODO @puhui999:是不是搞成具体的方法,拼团成功,拼团失败,这种方法;
+    /**
+     * 更新拼团状态为成功
+     *
+     * @param userId  用户编号
+     * @param orderId 订单编号
+     */
+    void updateRecordStatusToSuccess(Long userId, Long orderId);
 
     /**
-     * 更新开团记录状态
+     * 更新拼团状态为失败
      *
-     * @param reqDTO 请求 DTO
+     * @param userId  用户编号
+     * @param orderId 订单编号
+     */
+    void updateRecordStatusToFailed(Long userId, Long orderId);
+
+    /**
+     * 更新拼团状态为 进行中
+     *
+     * @param userId    用户编号
+     * @param orderId   订单编号
+     * @param startTime 开始时间
      */
-    void updateCombinationRecordStatus(CombinationRecordUpdateStatusReqDTO reqDTO);
+    void updateRecordStatusToInProgress(Long userId, Long orderId, LocalDateTime startTime);
 
 }

+ 0 - 39
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/dto/CombinationRecordUpdateStatusReqDTO.java

@@ -1,39 +0,0 @@
-package cn.iocoder.yudao.module.promotion.api.combination.dto;
-
-import lombok.Data;
-
-import javax.validation.constraints.NotNull;
-import java.time.LocalDateTime;
-
-/**
- * 拼团记录的更新状态 Request DTO
- *
- * @author HUIHUI
- */
-@Data
-public class CombinationRecordUpdateStatusReqDTO {
-
-    /**
-     * 用户编号
-     */
-    @NotNull(message = "用户编号不能为空")
-    private Long userId;
-
-    /**
-     * 订单编号
-     */
-    @NotNull(message = "订单编号不能为空")
-    private Long orderId;
-
-    /**
-     * 开团状态:正在开团 拼团成功 拼团失败
-     */
-    @NotNull(message = "开团状态不能为空")
-    private Integer status;
-
-    /**
-     * 团开始时间
-     */
-    private LocalDateTime startTime;
-
-}

+ 19 - 0
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApi.java

@@ -0,0 +1,19 @@
+package cn.iocoder.yudao.module.promotion.api.seckill;
+
+import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
+
+/**
+ * 秒杀活动 API 接口
+ *
+ * @author HUIHUI
+ */
+public interface SeckillActivityApi {
+
+    /**
+     * 更新秒杀库存
+     *
+     * @param updateStockReqDTO 请求
+     */
+    void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO);
+
+}

+ 50 - 0
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/dto/SeckillActivityUpdateStockReqDTO.java

@@ -0,0 +1,50 @@
+package cn.iocoder.yudao.module.promotion.api.seckill.dto;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 更新秒杀库存 request DTO
+ *
+ * @author HUIHUI
+ */
+@Data
+public class SeckillActivityUpdateStockReqDTO {
+
+    // TODO @puhui999:参数校验
+
+    // TODO @puhui999:秒杀的话,一次只能购买一种商品哈;不能多个哈;
+
+    /**
+     * 活动编号
+     */
+    private Long activityId;
+    /**
+     * 总购买数量
+     */
+    private Integer count;
+    /**
+     * 活动商品
+     */
+    private List<Item> items;
+
+    @Data
+    public static class Item {
+
+        /**
+         * SPU 编号
+         */
+        private Long spuId;
+        /**
+         * SKU 编号
+         */
+        private Long skuId;
+        /**
+         * 购买数量
+         */
+        private Integer count;
+
+    }
+
+}

+ 2 - 1
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java

@@ -51,10 +51,11 @@ public interface ErrorCodeConstants {
 
     // ========== 秒杀活动 1013008000 ==========
     ErrorCode SECKILL_ACTIVITY_NOT_EXISTS = new ErrorCode(1013008000, "秒杀活动不存在");
-    ErrorCode SECKILL_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1013008002, "存在商品参加了其它秒杀活动");
+    ErrorCode SECKILL_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1013008002, "存在商品参加了其它秒杀活动,秒杀时段冲突");
     ErrorCode SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1013008003, "秒杀活动已关闭,不能修改");
     ErrorCode SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013008004, "秒杀活动未关闭或未结束,不能删除");
     ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1013008005, "秒杀活动已关闭,不能重复关闭");
+    ErrorCode SECKILL_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1013008006, "更新秒杀活动库存失败,原因秒杀库存不足");
 
     // ========== 秒杀时段 1013009000 ==========
     ErrorCode SECKILL_CONFIG_NOT_EXISTS = new ErrorCode(1013009000, "秒杀时段不存在");

+ 41 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainActivityApiImpl.java

@@ -0,0 +1,41 @@
+package cn.iocoder.yudao.module.promotion.api.bargain;
+
+import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityUpdateReqVO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
+import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.BARGAIN_ACTIVITY_NOT_EXISTS;
+
+/**
+ * 砍价活动 Api 接口实现类
+ *
+ * @author HUIHUI
+ */
+@Service
+public class BargainActivityApiImpl implements BargainActivityApi {
+
+    @Resource
+    private BargainActivityService bargainActivityService;
+
+    @Override
+    public void updateBargainActivityStock(Long activityId, Integer count) {
+        // TODO @puhui999:可以整个实现到 bargainActivityService 中
+        // 查询砍价活动
+        BargainActivityDO activity = bargainActivityService.getBargainActivity(activityId);
+        if (activity == null) {
+            throw exception(BARGAIN_ACTIVITY_NOT_EXISTS);
+        }
+
+        // 更新砍价库存
+        // TODO @puhui999:考虑下并发更新问题
+        BargainActivityUpdateReqVO reqVO = new BargainActivityUpdateReqVO();
+        reqVO.setId(activityId);
+        reqVO.setStock(activity.getStock() - count);
+        bargainActivityService.updateBargainActivity(reqVO);
+    }
+
+}

+ 14 - 7
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApiImpl.java

@@ -2,13 +2,13 @@ package cn.iocoder.yudao.module.promotion.api.combination;
 
 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO;
-import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordUpdateStatusReqDTO;
 import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
 import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
 import cn.iocoder.yudao.module.promotion.service.combination.CombinationRecordService;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
+import java.time.LocalDateTime;
 import java.util.List;
 
 /**
@@ -43,12 +43,19 @@ public class CombinationRecordApiImpl implements CombinationRecordApi {
     }
 
     @Override
-    public void updateCombinationRecordStatus(CombinationRecordUpdateStatusReqDTO reqDTO) {
-        if (null == reqDTO.getStartTime()) {
-            recordService.updateCombinationRecordStatusByUserIdAndOrderId(reqDTO);
-        } else {
-            recordService.updateCombinationRecordStatusAndStartTimeByUserIdAndOrderId(reqDTO);
-        }
+    public void updateRecordStatusToSuccess(Long userId, Long orderId) {
+        recordService.updateCombinationRecordStatusByUserIdAndOrderId(CombinationRecordStatusEnum.SUCCESS.getStatus(), userId, orderId);
+    }
+
+    @Override
+    public void updateRecordStatusToFailed(Long userId, Long orderId) {
+        recordService.updateCombinationRecordStatusByUserIdAndOrderId(CombinationRecordStatusEnum.FAILED.getStatus(), userId, orderId);
+    }
+
+    @Override
+    public void updateRecordStatusToInProgress(Long userId, Long orderId, LocalDateTime startTime) {
+        recordService.updateRecordStatusAndStartTimeByUserIdAndOrderId(CombinationRecordStatusEnum.IN_PROGRESS.getStatus(),
+                userId, orderId, startTime);
     }
 
 }

+ 84 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApiImpl.java

@@ -0,0 +1,84 @@
+package cn.iocoder.yudao.module.promotion.api.seckill;
+
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
+import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
+import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.SECKILL_ACTIVITY_UPDATE_STOCK_FAIL;
+
+/**
+ * 秒杀活动接口 Api 接口实现类
+ *
+ * @author HUIHUI
+ */
+@Service
+public class SeckillActivityApiImpl implements SeckillActivityApi {
+
+    @Resource
+    private SeckillActivityService activityService;
+
+    // TODO @puhui:建议这块弄到 activityService 实现哈;
+    // TODO @puhui:这个方法,要考虑事务性
+    @Override
+    public void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO) {
+        // TODO @puhui999:长方法,最好有 1.1 1.2 2.1 这种步骤哈;
+        SeckillActivityDO seckillActivity = activityService.getSeckillActivity(updateStockReqDTO.getActivityId());
+        if (seckillActivity.getStock() < updateStockReqDTO.getCount()) {
+            throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
+        }
+        // 获取活动商品
+        // TODO @puhui999:在一个方法里,dos 和 dolist 最好保持一致,要么用 s,要么用 list 哈;
+        List<SeckillProductDO> productDOs = activityService.getSeckillProductListByActivityId(updateStockReqDTO.getActivityId());
+        // TODO @puhui999:这个是不是搞成  CollectionUtils.convertMultiMap()
+        List<SeckillActivityUpdateStockReqDTO.Item> items = updateStockReqDTO.getItems();
+        Map<Long, List<Long>> map = new HashMap<>();
+        items.forEach(item -> {
+            if (map.containsKey(item.getSpuId())) {
+                List<Long> skuIds = map.get(item.getSpuId());
+                skuIds.add(item.getSkuId());
+                map.put(item.getSpuId(), skuIds);
+            } else {
+                List<Long> list = new ArrayList<>();
+                list.add(item.getSkuId());
+                map.put(item.getSpuId(), list);
+            }
+        });
+        // 过滤出购买的商品
+        // TODO @puhui999:productDOList 可以简化成 productList;一般来说,do 之类不用带着哈,在变量里;
+        List<SeckillProductDO> productDOList = CollectionUtils.filterList(productDOs, item -> map.get(item.getSpuId()).contains(item.getSkuId()));
+        Map<Long, SeckillActivityUpdateStockReqDTO.Item> productDOMap = CollectionUtils.convertMap(items, SeckillActivityUpdateStockReqDTO.Item::getSkuId, p -> p);
+        // 检查活动商品库存是否充足
+        // TODO @puhui999:避免 b 这种无业务含义的变量;
+        boolean b = CollectionUtils.anyMatch(productDOList, item -> {
+            SeckillActivityUpdateStockReqDTO.Item item1 = productDOMap.get(item.getSkuId());
+            return (item.getStock() < item1.getCount()) || (item.getStock() - item1.getCount()) < 0;
+        });
+        if (b) {
+            throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
+        }
+        // TODO @puhui999:类似 doList,应该和下面的 update 逻辑粘的更紧密一点;so 在空行的时候,应该挪到 74 之后里去;甚至更合理,应该是 79 之后;说白了,逻辑要分块,每个模块涉及的代码要紧密在一起;
+        List<SeckillProductDO> doList = CollectionUtils.convertList(productDOList, item -> {
+            item.setStock(item.getStock() - productDOMap.get(item.getSkuId()).getCount());
+            return item;
+        });
+
+        // 更新活动库存
+        // TODO @puhui999:考虑下并发更新
+        seckillActivity.setStock(seckillActivity.getStock() + updateStockReqDTO.getCount());
+        seckillActivity.setTotalStock(seckillActivity.getTotalStock() - updateStockReqDTO.getCount());
+        activityService.updateSeckillActivity(seckillActivity);
+        // 更新活动商品库存
+        activityService.updateSeckillActivityProductList(doList);
+    }
+
+}

+ 45 - 33
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/CombinationRecordDO.java

@@ -9,6 +9,7 @@ import lombok.*;
 
 import java.time.LocalDateTime;
 
+// TODO 芋艿:把字段的顺序,和 do 顺序对齐下
 /**
  * 拼团记录 DO
  *
@@ -27,34 +28,28 @@ import java.time.LocalDateTime;
 @AllArgsConstructor
 public class CombinationRecordDO extends BaseDO {
 
+    /**
+     * 编号,主键自增
+     */
     @TableId
     private Long id;
+
     /**
      * 拼团活动编号
+     *
+     * 关联 {@link CombinationActivityDO#getId()}
      */
     private Long activityId;
     /**
-     * SPU 编号
-     */
-    private Long spuId;
-    /**
-     * SKU 编号
-     */
-    private Long skuId;
-    /**
-     * 用户编号
-     */
-    private Long userId;
-    /**
-     * 订单编号
+     * 拼团商品单价
+     *
+     * 冗余 {@link CombinationProductDO#getCombinationPrice()}
      */
-    private Long orderId;
+    private Integer combinationPrice;
     /**
-     * 团长编号
-     *
-     * 关联 {@link CombinationRecordDO#getId()}
+     * SPU 编号
      */
-    private Long headId;
+    private Long spuId;
     /**
      * 商品名字
      */
@@ -64,9 +59,14 @@ public class CombinationRecordDO extends BaseDO {
      */
     private String picUrl;
     /**
-     * 拼团商品单价
+     * SKU 编号
      */
-    private Integer combinationPrice;
+    private Long skuId;
+
+    /**
+     * 用户编号
+     */
+    private Long userId;
     /**
      * 用户昵称
      */
@@ -75,22 +75,44 @@ public class CombinationRecordDO extends BaseDO {
      * 用户头像
      */
     private String avatar;
+
+    /**
+     * 团长编号
+     *
+     * 关联 {@link CombinationRecordDO#getId()}
+     */
+    private Long headId;
     /**
      * 开团状态
      *
      * 关联 {@link CombinationRecordStatusEnum}
      */
     private Integer status;
+    /**
+     * 订单编号
+     */
+    private Long orderId;
+    /**
+     * 开团需要人数
+     *
+     * 关联 {@link CombinationActivityDO#getUserSize()}
+     */
+    private Integer userSize;
+    /**
+     * 已加入拼团人数
+     */
+    private Integer userCount;
     /**
      * 是否虚拟成团
      */
     private Boolean virtualGroup;
+
     /**
-     * 过期时间,单位:小时
+     * 过期时间
      *
-     * 关联 {@link CombinationActivityDO#getLimitDuration()}
+     * 基于 {@link CombinationRecordDO#getStartTime()} + {@link CombinationActivityDO#getLimitDuration()} 计算
      */
-    private Integer expireTime;
+    private LocalDateTime expireTime;
     /**
      * 开始时间 (订单付款后开始的时间)
      */
@@ -99,15 +121,5 @@ public class CombinationRecordDO extends BaseDO {
      * 结束时间(成团时间/失败时间)
      */
     private LocalDateTime endTime;
-    /**
-     * 开团需要人数
-     *
-     * 关联 {@link CombinationActivityDO#getUserSize()}
-     */
-    private Integer userSize;
-    /**
-     * 已加入拼团人数
-     */
-    private Integer userCount;
 
 }

+ 10 - 5
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordService.java

@@ -1,9 +1,9 @@
 package cn.iocoder.yudao.module.promotion.service.combination;
 
 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
-import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordUpdateStatusReqDTO;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO;
 
+import java.time.LocalDateTime;
 import java.util.List;
 
 /**
@@ -16,9 +16,11 @@ public interface CombinationRecordService {
     /**
      * 更新拼团状态
      *
-     * @param reqDTO 请求 DTO
+     * @param status 状态
+     * @param userId 用户编号
+     * @param orderId 订单编号
      */
-    void updateCombinationRecordStatusByUserIdAndOrderId(CombinationRecordUpdateStatusReqDTO reqDTO);
+    void updateCombinationRecordStatusByUserIdAndOrderId(Integer status, Long userId, Long orderId);
 
     /**
      * 创建拼团记录
@@ -30,9 +32,12 @@ public interface CombinationRecordService {
     /**
      * 更新拼团状态和开始时间
      *
-     * @param reqDTO 请求 DTO
+     * @param status 状态
+     * @param userId 用户编号
+     * @param orderId 订单编号
+     * @param startTime 开始时间
      */
-    void updateCombinationRecordStatusAndStartTimeByUserIdAndOrderId(CombinationRecordUpdateStatusReqDTO reqDTO);
+    void updateRecordStatusAndStartTimeByUserIdAndOrderId(Integer status, Long userId, Long orderId, LocalDateTime startTime);
 
     /**
      * 获得拼团状态

+ 10 - 11
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java

@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.promotion.service.combination;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
-import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordUpdateStatusReqDTO;
 import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO;
@@ -21,6 +20,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU
 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
 
 // TODO 芋艿:等拼团记录做完,完整 review 下
+
 /**
  * 拼团记录 Service 实现类
  *
@@ -38,27 +38,27 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public void updateCombinationRecordStatusByUserIdAndOrderId(CombinationRecordUpdateStatusReqDTO reqDTO) {
+    public void updateCombinationRecordStatusByUserIdAndOrderId(Integer status, Long userId, Long orderId) {
         // 校验拼团是否存在
-        CombinationRecordDO recordDO = validateCombinationRecord(reqDTO.getUserId(), reqDTO.getOrderId());
+        CombinationRecordDO recordDO = validateCombinationRecord(userId, orderId);
 
         // 更新状态
-        recordDO.setStatus(reqDTO.getStatus());
+        recordDO.setStatus(status);
         recordMapper.updateById(recordDO);
     }
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public void updateCombinationRecordStatusAndStartTimeByUserIdAndOrderId(CombinationRecordUpdateStatusReqDTO reqDTO) {
-        CombinationRecordDO recordDO = validateCombinationRecord(reqDTO.getUserId(), reqDTO.getOrderId());
+    public void updateRecordStatusAndStartTimeByUserIdAndOrderId(Integer status, Long userId, Long orderId, LocalDateTime startTime) {
+        CombinationRecordDO recordDO = validateCombinationRecord(userId, orderId);
         // 更新状态
-        recordDO.setStatus(reqDTO.getStatus());
+        recordDO.setStatus(status);
         // 更新开始时间
-        recordDO.setStartTime(reqDTO.getStartTime());
+        recordDO.setStartTime(startTime);
         recordMapper.updateById(recordDO);
 
         // 更新拼团参入人数
-        List<CombinationRecordDO> recordDOs = recordMapper.selectListByHeadIdAndStatus(recordDO.getHeadId(), reqDTO.getStatus());
+        List<CombinationRecordDO> recordDOs = recordMapper.selectListByHeadIdAndStatus(recordDO.getHeadId(), status);
         if (CollUtil.isNotEmpty(recordDOs)) {
             recordDOs.forEach(item -> {
                 item.setUserCount(recordDOs.size());
@@ -115,8 +115,7 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
         // 2. 创建拼团记录
         CombinationRecordDO record = CombinationActivityConvert.INSTANCE.convert(reqDTO);
         record.setVirtualGroup(false);
-        // TODO @puhui999:过期时间,应该是 Date 哈;
-        record.setExpireTime(activity.getLimitDuration());
+        record.setExpireTime(record.getStartTime().plusHours(activity.getLimitDuration()));
         record.setUserSize(activity.getUserSize());
         recordMapper.insert(record);
     }

+ 14 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityService.java

@@ -33,6 +33,20 @@ public interface SeckillActivityService {
      */
     void updateSeckillActivity(@Valid SeckillActivityUpdateReqVO updateReqVO);
 
+    /**
+     * 更新秒杀活动
+     *
+     * @param activityDO 秒杀活动
+     */
+    void updateSeckillActivity(SeckillActivityDO activityDO);
+
+    /**
+     * 更新秒杀活动商品
+     *
+     * @param productList 活动商品列表
+     */
+    void updateSeckillActivityProductList(List<SeckillProductDO> productList);
+
     /**
      * 关闭秒杀活动
      *

+ 17 - 13
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java

@@ -79,8 +79,8 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
      * 1. 校验秒杀时段是否存在
      * 2. 秒杀商品是否参加其它活动
      *
-     * @param configIds 秒杀时段数组
-     * @param spuId 商品 SPU 编号
+     * @param configIds  秒杀时段数组
+     * @param spuId      商品 SPU 编号
      * @param activityId 秒杀活动编号
      */
     private void validateProductConflict(List<Long> configIds, Long spuId, Long activityId) {
@@ -92,15 +92,9 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
         if (activityId != null) { // 排除自己
             activityList.removeIf(item -> ObjectUtil.equal(item.getId(), activityId));
         }
-        // TODO @puhui999:一个 spu,参与两个活动应该没关系,关键是活动时间不充能重叠;
-        // 2.2 过滤出所有 spuId 有交集的活动,判断是否存在重叠
-        List<SeckillActivityDO> activityDOs1 = filterList(activityList, s -> ObjectUtil.equal(s.getSpuId(), spuId));
-        if (isNotEmpty(activityDOs1)) {
-            throw exception(SECKILL_ACTIVITY_SPU_CONFLICTS);
-        }
-        // 2.3 过滤出所有 configIds 有交集的活动,判断是否存在重叠
-        List<SeckillActivityDO> activityDOs2 = filterList(activityList, s -> containsAny(s.getConfigIds(), configIds));
-        if (isNotEmpty(activityDOs2)) {
+        // 2.2 过滤出所有 configIds 有交集的活动,判断是否存在重叠
+        List<SeckillActivityDO> conflictActivityList = filterList(activityList, s -> containsAny(s.getConfigIds(), configIds));
+        if (isNotEmpty(conflictActivityList)) {
             throw exception(SECKILL_ACTIVITY_SPU_CONFLICTS);
         }
     }
@@ -108,7 +102,7 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
     /**
      * 校验秒杀商品是否都存在
      *
-     * @param spuId 商品 SPU 编号
+     * @param spuId    商品 SPU 编号
      * @param products 秒杀商品
      */
     private void validateProductExists(Long spuId, List<SeckillProductBaseVO> products) {
@@ -150,11 +144,21 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
         updateSeckillProduct(updateObj, updateReqVO.getProducts());
     }
 
+    @Override
+    public void updateSeckillActivity(SeckillActivityDO activityDO) {
+        seckillActivityMapper.updateById(activityDO);
+    }
+
+    @Override
+    public void updateSeckillActivityProductList(List<SeckillProductDO> productList) {
+        seckillProductMapper.updateBatch(productList);
+    }
+
     /**
      * 更新秒杀商品
      *
      * @param activity 秒杀活动
-     * @param products  该活动的最新商品配置
+     * @param products 该活动的最新商品配置
      */
     private void updateSeckillProduct(SeckillActivityDO activity, List<SeckillProductBaseVO> products) {
         // 第一步,对比新老数据,获得添加、修改、删除的列表

+ 0 - 26
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/util/PromotionUtils.java

@@ -1,18 +1,9 @@
 package cn.iocoder.yudao.module.promotion.util;
 
 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
-import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
-import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
 
 import java.time.LocalDateTime;
-import java.util.List;
-import java.util.Set;
-import java.util.function.Function;
-
-import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.anyMatch;
-import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;
 
 /**
  * 活动工具类
@@ -31,21 +22,4 @@ public class PromotionUtils {
         return LocalDateTimeUtils.beforeNow(endTime) ? CommonStatusEnum.DISABLE.getStatus() : CommonStatusEnum.ENABLE.getStatus();
     }
 
-    /**
-     * 校验商品 sku 是否都存在
-     *
-     * @param skus     数据库中的商品 skus
-     * @param products 需要校验的商品
-     * @param func     获取需要校验的商品的 skuId
-     */
-    public static <T> void validateProductSkuAllExists(List<ProductSkuRespDTO> skus, List<T> products, Function<T, Long> func) {
-        // 校验 sku 个数是否一致
-        Set<Long> skuIdsSet = CollectionUtils.convertSet(products, func);
-        Set<Long> skuIdsSet1 = CollectionUtils.convertSet(skus, ProductSkuRespDTO::getId);
-        // 校验 skuId 是否存在
-        if (anyMatch(skuIdsSet, s -> !skuIdsSet1.contains(s))) {
-            throw exception(SKU_NOT_EXISTS);
-        }
-    }
-
 }

+ 5 - 0
yudao-module-mall/yudao-module-trade-biz/pom.xml

@@ -86,6 +86,11 @@
             <artifactId>yudao-spring-boot-starter-mybatis</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-spring-boot-starter-redis</artifactId>
+        </dependency>
+
         <!-- Test 测试相关 -->
         <dependency>
             <groupId>cn.iocoder.boot</groupId>

+ 2 - 1
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/brokerage/BrokerageApiImpl.java

@@ -20,13 +20,14 @@ public class BrokerageApiImpl implements BrokerageApi {
     @Resource
     private BrokerageUserService brokerageUserService;
 
+    @Override
     public BrokerageUserDTO getBrokerageUser(Long userId) {
         return BrokerageUserConvert.INSTANCE.convertDTO(brokerageUserService.getBrokerageUser(userId));
     }
 
     @Override
     public boolean bindUser(Long userId, Long bindUserId, Boolean isNewUser) {
-        return brokerageUserService.bindUser(userId, bindUserId, isNewUser);
+        return brokerageUserService.bindBrokerageUser(userId, bindUserId, isNewUser);
     }
 
 }

+ 10 - 1
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java

@@ -76,6 +76,11 @@ public class TradeAfterSaleController {
     public CommonResult<TradeAfterSaleDetailRespVO> getOrderDetail(@RequestParam("id") Long id) {
         // 查询订单
         TradeAfterSaleDO afterSale = afterSaleService.getAfterSale(id);
+        // TODO @puhui999:这里建议改成,如果为 null,直接返回 success null;主要查询操作,尽量不要有非空的提示哈;交给前端处理;
+//        if (afterSale == null) {
+//            return success(null, AFTER_SALE_NOT_FOUND.getMsg());
+//        }
+
         // 查询订单
         TradeOrderDO order = tradeOrderQueryService.getOrder(afterSale.getOrderId());
         // 查询订单项
@@ -92,7 +97,11 @@ public class TradeAfterSaleController {
             TradeAfterSaleLogRespDTO respVO = new TradeAfterSaleLogRespDTO();
             respVO.setId((long) i);
             respVO.setUserId((long) i);
-            respVO.setUserType(1);
+            respVO.setUserType(i % 2 == 0 ? 2 : 1);
+            // 模拟系统操作
+            if (i == 2) {
+                respVO.setUserType(3);
+            }
             respVO.setAfterSaleId(id);
             respVO.setOrderId((long) i);
             respVO.setOrderItemId((long) i);

+ 1 - 1
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleDetailRespVO.java

@@ -35,7 +35,7 @@ public class TradeAfterSaleDetailRespVO extends TradeAfterSaleBaseVO {
     /**
      * 售后日志
      */
-    private List<TradeAfterSaleLogRespVO> afterSaleLog;
+    private List<TradeAfterSaleLogRespVO> logs;
 
     @Schema(description = "管理后台 - 交易订单的详情的订单项目")
     @Data

+ 3 - 3
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/BrokerageUserController.java

@@ -62,7 +62,7 @@ public class BrokerageUserController {
     @Operation(summary = "修改推广资格")
     @PreAuthorize("@ss.hasPermission('trade:brokerage-user:update-brokerage-enable')")
     public CommonResult<Boolean> updateBrokerageEnabled(@Valid @RequestBody BrokerageUserUpdateBrokerageEnabledReqVO updateReqVO) {
-        brokerageUserService.updateBrokerageEnabled(updateReqVO.getId(), updateReqVO.getEnabled());
+        brokerageUserService.updateBrokerageUserEnabled(updateReqVO.getId(), updateReqVO.getEnabled());
         return success(true);
     }
 
@@ -90,12 +90,12 @@ public class BrokerageUserController {
         // 合计分佣订单
         Map<Long, UserBrokerageSummaryBO> userOrderSummaryMap = convertMap(userIds,
                 userId -> userId,
-                userId -> brokerageRecordService.summaryByUserIdAndBizTypeAndStatus(userId,
+                userId -> brokerageRecordService.getUserBrokerageSummaryByUserId(userId,
                         BrokerageRecordBizTypeEnum.ORDER.getType(), BrokerageRecordStatusEnum.SETTLEMENT.getStatus()));
         // 合计推广用户数量
         Map<Long, Long> brokerageUserCountMap = convertMap(userIds,
                 userId -> userId,
-                userId -> brokerageUserService.getCountByBindUserId(userId));
+                userId -> brokerageUserService.getBrokerageUserCountByBindUserId(userId));
 
         // todo 合计提现
 

+ 0 - 3
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/vo/BrokerageUserRespVO.java

@@ -19,7 +19,6 @@ public class BrokerageUserRespVO extends BrokerageUserBaseVO {
     @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
     private LocalDateTime createTime;
 
-
     // ========== 用户信息 ==========
 
     @Schema(description = "用户头像", example = "https://www.iocoder.cn/xxx.png")
@@ -27,7 +26,6 @@ public class BrokerageUserRespVO extends BrokerageUserBaseVO {
     @Schema(description = "用户昵称", example = "李四")
     private String nickname;
 
-
     // ========== 推广信息 ==========
 
     @Schema(description = "推广用户数量(一级)", example = "20019")
@@ -37,7 +35,6 @@ public class BrokerageUserRespVO extends BrokerageUserBaseVO {
     @Schema(description = "推广订单金额", example = "20019")
     private Integer brokerageOrderPrice;
 
-
     // ========== 提现信息 ==========
 
     @Schema(description = "已提现金额", example = "20019")

+ 5 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/TradeOrderController.java

@@ -67,6 +67,11 @@ public class TradeOrderController {
     public CommonResult<TradeOrderDetailRespVO> getOrderDetail(@RequestParam("id") Long id) {
         // 查询订单
         TradeOrderDO order = tradeOrderQueryService.getOrder(id);
+        // TODO @puhui999:这里建议改成,如果为 null,直接返回 success null;主要查询操作,尽量不要有非空的提示哈;交给前端处理;
+//        if (order == null) {
+//            return success(null, ORDER_NOT_FOUND.getMsg());
+//        }
+
         // 查询订单项
         List<TradeOrderItemDO> orderItems = tradeOrderQueryService.getOrderItemListByOrderId(id);
         // orderLog

+ 8 - 9
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderDetailRespVO.java

@@ -26,24 +26,23 @@ public class TradeOrderDetailRespVO extends TradeOrderBaseVO {
     private MemberUserRespVO user;
 
     /**
-     * TODO 订单操作日志, 先模拟一波;返回 logs,简洁,然后复数哈
+     * TODO 订单操作日志, 先模拟一波
      */
-    private List<OrderLog> orderLog;
+    private List<OrderLog> logs;
 
-    // TODO @puhui999:swagger 注解
+    @Schema(description = "管理后台 - 交易订单的操作日志")
     @Data
     public static class OrderLog {
 
-        /**
-         * 内容
-         */
+        @Schema(description = "操作详情", requiredMode = Schema.RequiredMode.REQUIRED, example = "订单发货")
         private String content;
 
-        /**
-         * 创建时间
-         */
+        @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2023-06-01 10:50:20")
         private LocalDateTime createTime;
 
+        @Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+        private Integer userType;
+
     }
 
     @Schema(description = "管理后台 - 交易订单的详情的订单项目")

+ 12 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/AppBrokerageRecordController.java

@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.trade.controller.app.brokerage;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
+import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record.AppBrokerageProductPriceRespVO;
 import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record.AppBrokerageRecordPageReqVO;
 import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record.AppBrokerageRecordRespVO;
 import io.swagger.v3.oas.annotations.Operation;
@@ -11,6 +12,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
 import javax.validation.Valid;
@@ -40,4 +42,14 @@ public class AppBrokerageRecordController {
         return success(new PageResult<>(asList(vo1, vo2), 10L));
     }
 
+    @GetMapping("/get-product-brokerage-price")
+    @Operation(summary = "获得商品的分销金额")
+    public CommonResult<AppBrokerageProductPriceRespVO> getProductBrokeragePrice(@RequestParam("spuId") Long spuId) {
+        AppBrokerageProductPriceRespVO respVO = new AppBrokerageProductPriceRespVO();
+        respVO.setEnabled(true); // TODO @疯狂:需要开启分销 + 人允许分销
+        respVO.setBrokerageMinPrice(1);
+        respVO.setBrokerageMaxPrice(2);
+        return success(respVO);
+    }
+
 }

+ 16 - 14
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/AppBrokerageUserController.java

@@ -37,11 +37,19 @@ public class AppBrokerageUserController {
     @PreAuthenticated
     public CommonResult<AppBrokerageUserRespVO> getBrokerageUser() {
         AppBrokerageUserRespVO respVO = new AppBrokerageUserRespVO()
+                .setBrokerageEnabled(true)
                 .setPrice(2000)
                 .setFrozenPrice(3000);
         return success(respVO);
     }
 
+    @PutMapping("/bind")
+    @Operation(summary = "绑定推广员")
+    @PreAuthenticated
+    public CommonResult<Boolean> bindBrokerageUser(@Valid @RequestBody AppBrokerageUserBindReqVO reqVO) {
+        return success(brokerageUserService.bindBrokerageUser(getLoginUserId(), reqVO.getBindUserId(), false));
+    }
+
     // TODO 芋艿:临时 mock =>
     @GetMapping("/get-summary")
     @Operation(summary = "获得个人分销统计")
@@ -49,7 +57,7 @@ public class AppBrokerageUserController {
     public CommonResult<AppBrokerageUserMySummaryRespVO> getBrokerageUserSummary() {
         AppBrokerageUserMySummaryRespVO respVO = new AppBrokerageUserMySummaryRespVO()
                 .setYesterdayPrice(1)
-                .setPrice(2)
+                .setBrokeragePrice(2)
                 .setFrozenPrice(3)
                 .setWithdrawPrice(4)
                 .setFirstBrokerageUserCount(166)
@@ -84,16 +92,16 @@ public class AppBrokerageUserController {
     public CommonResult<PageResult<AppBrokerageUserRankByPriceRespVO>> getBrokerageUserChildSummaryPageByPrice(AppBrokerageUserRankPageReqVO pageReqVO) {
         AppBrokerageUserRankByPriceRespVO vo1 = new AppBrokerageUserRankByPriceRespVO()
                 .setId(1L).setNickname("芋1**艿").setAvatar("http://www.iocoder.cn/images/common/wechat_mp_2017_07_31_bak.jpg")
-                .setPrice(10);
+                .setBrokeragePrice(10);
         AppBrokerageUserRankByPriceRespVO vo2 = new AppBrokerageUserRankByPriceRespVO()
                 .setId(2L).setNickname("芋2**艿").setAvatar("http://www.iocoder.cn/images/common/wechat_mp_2017_07_31_bak.jpg")
-                .setPrice(6);
+                .setBrokeragePrice(6);
         AppBrokerageUserRankByPriceRespVO vo3 = new AppBrokerageUserRankByPriceRespVO()
                 .setId(3L).setNickname("芋3**艿").setAvatar("http://www.iocoder.cn/images/common/wechat_mp_2017_07_31_bak.jpg")
-                .setPrice(4);
+                .setBrokeragePrice(4);
         AppBrokerageUserRankByPriceRespVO vo4 = new AppBrokerageUserRankByPriceRespVO()
                 .setId(3L).setNickname("芋3**艿").setAvatar("http://www.iocoder.cn/images/common/wechat_mp_2017_07_31_bak.jpg")
-                .setPrice(4);
+                .setBrokeragePrice(4);
         return success(new PageResult<>(asList(vo1, vo2, vo3, vo4), 10L));
     }
 
@@ -105,11 +113,11 @@ public class AppBrokerageUserController {
             AppBrokerageUserChildSummaryPageReqVO pageReqVO) {
         AppBrokerageUserChildSummaryRespVO vo1 = new AppBrokerageUserChildSummaryRespVO()
                 .setId(1L).setNickname("芋1**艿").setAvatar("http://www.iocoder.cn/images/common/wechat_mp_2017_07_31_bak.jpg")
-                .setPrice(10).setPrice(20).setBrokerageOrderCount(30)
+                .setBrokeragePrice(10).setBrokeragePrice(20).setBrokerageOrderCount(30)
                 .setBrokerageTime(LocalDateTime.now());
         AppBrokerageUserChildSummaryRespVO vo2 = new AppBrokerageUserChildSummaryRespVO()
                 .setId(1L).setNickname("芋2**艿").setAvatar("http://www.iocoder.cn/images/common/wechat_mp_2017_07_31_bak.jpg")
-                .setPrice(20).setPrice(30).setBrokerageOrderCount(40)
+                .setBrokeragePrice(20).setBrokeragePrice(30).setBrokerageOrderCount(40)
                 .setBrokerageTime(LocalDateTime.now());
         return success(new PageResult<>(asList(vo1, vo2), 10L));
     }
@@ -118,15 +126,9 @@ public class AppBrokerageUserController {
     @GetMapping("/get-rank-by-price")
     @Operation(summary = "获得分销用户排行(基于佣金)")
     @Parameter(name = "times", description = "时间段", required = true)
-    public CommonResult<Integer> getBrokerageUserRankByPrice(
+    public CommonResult<Integer> bindBrokerageUser(
             @RequestParam("times") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) LocalDateTime[] times) {
         return success(1);
     }
 
-    @PutMapping("/bind-user")
-    @Operation(summary = "绑定推广员")
-    public CommonResult<Boolean> getBrokerageUserRankByPrice(@Valid AppBrokerageUserBindReqVO reqVO) {
-        return success(brokerageUserService.bindUser(getLoginUserId(), reqVO.getBindUserId(), false));
-    }
-
 }

+ 19 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/record/AppBrokerageProductPriceRespVO.java

@@ -0,0 +1,19 @@
+package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "用户 App - 商品的分销金额 Response VO")
+@Data
+public class AppBrokerageProductPriceRespVO {
+
+    @Schema(description = "是否开启", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    private Boolean enabled;
+
+    @Schema(description = "分销最小金额,单位:分", example = "100")
+    private Integer brokerageMinPrice;
+
+    @Schema(description = "分销最大金额,单位:分", example = "100")
+    private Integer brokerageMaxPrice;
+
+}

+ 1 - 1
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserChildSummaryRespVO.java

@@ -19,7 +19,7 @@ public class AppBrokerageUserChildSummaryRespVO {
     private String avatar;
 
     @Schema(description = "佣金金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
-    private Integer price;
+    private Integer brokeragePrice;
 
     @Schema(description = "分销订单数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
     private Integer brokerageOrderCount;

+ 1 - 1
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserMySummaryRespVO.java

@@ -14,7 +14,7 @@ public class AppBrokerageUserMySummaryRespVO {
     private Integer withdrawPrice;
 
     @Schema(description = "可用的佣金,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "2408")
-    private Integer price;
+    private Integer brokeragePrice;
 
     @Schema(description = "冻结的佣金,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "234")
     private Integer frozenPrice;

+ 1 - 1
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserRankByPriceRespVO.java

@@ -17,6 +17,6 @@ public class AppBrokerageUserRankByPriceRespVO {
     private String avatar;
 
     @Schema(description = "佣金金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
-    private Integer price;
+    private Integer brokeragePrice;
 
 }

+ 3 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserRespVO.java

@@ -7,6 +7,9 @@ import lombok.Data;
 @Data
 public class AppBrokerageUserRespVO {
 
+    @Schema(description = "是否有分销资格", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
+    private Boolean brokerageEnabled;
+
     @Schema(description = "可用的佣金,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "2408")
     private Integer price;
 

+ 0 - 3
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/withdraw/AppBrokerageWithdrawCreateReqVO.java

@@ -23,21 +23,18 @@ public class AppBrokerageWithdrawCreateReqVO {
     @Min(value = 1, message = "提现金额不能小于 1")
     private Integer price;
 
-
     // ========== 银行卡、微信、支付宝 提现相关字段 ==========
 
     @Schema(description = "提现账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456789")
     @NotBlank(message = "提现账号不能为空", groups = {Bank.class, Wechat.class, Alipay.class})
     private String accountNo;
 
-
     // ========== 微信、支付宝 提现相关字段 ==========
 
     @Schema(description = "收款码的图片", example = "https://www.iocoder.cn/1.png")
     @URL(message = "收款码的图片,必须是一个 URL")
     private String accountQrCodeUrl;
 
-
     // ========== 银行卡 提现相关字段 ==========
 
     @Schema(description = "持卡人姓名", example = "张三")

+ 4 - 4
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java

@@ -4,7 +4,6 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
 import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO;
-import cn.iocoder.yudao.module.product.api.property.ProductPropertyValueApi;
 import cn.iocoder.yudao.module.trade.controller.app.order.vo.*;
 import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemCommentCreateReqVO;
 import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemRespVO;
@@ -82,9 +81,10 @@ public class AppTradeOrderController {
     public CommonResult<AppTradeOrderDetailRespVO> getOrder(@RequestParam("id") Long id) {
         // 查询订单
         TradeOrderDO order = tradeOrderQueryService.getOrder(getLoginUserId(), id);
-        if (order == null) {
-            return success(null);
-        }
+        // TODO @puhui999:这里建议改成,如果为 null,直接返回 success null;主要查询操作,尽量不要有非空的提示哈;交给前端处理;
+//        if (order == null) {
+//            return success(null, ORDER_NOT_FOUND.getMsg());
+//        }
 
         // 查询订单项
         List<TradeOrderItemDO> orderItems = tradeOrderQueryService.getOrderItemListByOrderId(order.getId());

+ 6 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementReqVO.java

@@ -50,12 +50,18 @@ public class AppTradeOrderSettlementReqVO {
     private Long seckillActivityId;
 
     // ========== 拼团活动相关字段 ==========
+    // TODO @puhui999:是不是拼团记录的编号哈?
     @Schema(description = "拼团活动编号", example = "1024")
     private Long combinationActivityId;
 
     @Schema(description = "拼团团长编号", example = "2048")
     private Long combinationHeadId;
 
+    // ========== 砍价活动相关字段 ==========
+    // TODO @puhui999:是不是砍价记录的编号哈?
+    @Schema(description = "砍价活动编号", example = "123")
+    private Long bargainActivityId;
+
     @Data
     @Schema(description = "用户 App - 商品项")
     @Valid

+ 1 - 1
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/aftersale/TradeAfterSaleConvert.java

@@ -78,7 +78,7 @@ public interface TradeAfterSaleConvert {
         // 处理订单信息
         respVO.setOrder(convert(order));
         // 处理售后日志
-        respVO.setAfterSaleLog(convertList1(logs));
+        respVO.setLogs(convertList1(logs));
         return respVO;
     }
     List<TradeAfterSaleLogRespVO> convertList1(List<TradeAfterSaleLogRespDTO> list);

+ 8 - 13
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/record/BrokerageRecordConvert.java

@@ -33,27 +33,22 @@ public interface BrokerageRecordConvert {
 
     PageResult<BrokerageRecordRespVO> convertPage(PageResult<BrokerageRecordDO> page);
 
+    // TODO @疯狂:可能 title 不是很固化,会存在类似:沐晴成功购买《XXX JVM 实战》
     default BrokerageRecordDO convert(BrokerageUserDO user, BrokerageRecordBizTypeEnum bizType, String bizId,
-                                      Integer brokerageFrozenDays, int brokerage, LocalDateTime unfreezeTime,
+                                      Integer brokerageFrozenDays, int brokeragePrice, LocalDateTime unfreezeTime,
                                       String title, Long sourceUserId, Integer sourceUserType) {
         brokerageFrozenDays = ObjectUtil.defaultIfNull(brokerageFrozenDays, 0);
         // 不冻结时,佣金直接就是结算状态
         Integer status = brokerageFrozenDays > 0
                 ? BrokerageRecordStatusEnum.WAIT_SETTLEMENT.getStatus()
                 : BrokerageRecordStatusEnum.SETTLEMENT.getStatus();
-        return new BrokerageRecordDO()
-                .setUserId(user.getId())
-                .setBizType(bizType.getType())
-                .setBizId(bizId)
-                .setPrice(brokerage)
-                .setTotalPrice(user.getPrice())
+        return new BrokerageRecordDO().setUserId(user.getId())
+                .setBizType(bizType.getType()).setBizId(bizId)
+                .setPrice(brokeragePrice).setTotalPrice(user.getBrokeragePrice())
                 .setTitle(title)
-                .setDescription(StrUtil.format(bizType.getDescription(), String.format("¥%.2f", brokerage / 100d)))
-                .setStatus(status)
-                .setFrozenDays(brokerageFrozenDays)
-                .setUnfreezeTime(unfreezeTime)
-                .setSourceUserType(sourceUserType)
-                .setSourceUserId(sourceUserId);
+                .setDescription(StrUtil.format(bizType.getDescription(), String.format("¥%.2f", brokeragePrice / 100d)))
+                .setStatus(status).setFrozenDays(brokerageFrozenDays).setUnfreezeTime(unfreezeTime)
+                .setSourceUserType(sourceUserType).setSourceUserId(sourceUserId);
     }
 
     default PageResult<BrokerageRecordRespVO> convertPage(PageResult<BrokerageRecordDO> pageResult, Map<Long, MemberUserRespDTO> userMap) {

+ 7 - 13
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/user/BrokerageUserConvert.java

@@ -41,25 +41,19 @@ public interface BrokerageUserConvert {
 
             // 推广用户数量(一级)
             vo.setBrokerageUserCount(MapUtil.getInt(brokerageUserCountMap, vo.getId(), 0));
-
+            // 推广订单数量、推广订单金额
             Optional<UserBrokerageSummaryBO> orderSummaryOptional = Optional.ofNullable(userOrderSummaryMap.get(vo.getId()));
-            // 推广订单数量
-            vo.setBrokerageOrderCount(orderSummaryOptional.map(UserBrokerageSummaryBO::getCount).orElse(0));
-            // 推广订单金额
-            vo.setBrokerageOrderPrice(orderSummaryOptional.map(UserBrokerageSummaryBO::getPrice).orElse(0));
-
-            // todo 已提现次数
-            vo.setWithdrawCount(0);
-            // todo 已提现金额
-            vo.setWithdrawPrice(0);
+            vo.setBrokerageOrderCount(orderSummaryOptional.map(UserBrokerageSummaryBO::getCount).orElse(0))
+                    .setBrokerageOrderPrice(orderSummaryOptional.map(UserBrokerageSummaryBO::getPrice).orElse(0));
+            // todo 已提现次数、已提现金额
+            vo.setWithdrawCount(0).setWithdrawPrice(0);
         }
         return result;
     }
 
     default BrokerageUserRespVO copyTo(MemberUserRespDTO source, BrokerageUserRespVO target) {
-        Optional.ofNullable(source)
-                .ifPresent(user -> target.setNickname(user.getNickname())
-                        .setAvatar(user.getAvatar()));
+        Optional.ofNullable(source).ifPresent(
+                user -> target.setNickname(user.getNickname()).setAvatar(user.getAvatar()));
         return target;
     }
 

+ 3 - 1
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java

@@ -95,6 +95,7 @@ public interface TradeOrderConvert {
         items.forEach(item -> item.setIncrCount(-item.getIncrCount()));
         return new ProductSkuUpdateStockReqDTO(items);
     }
+
     List<ProductSkuUpdateStockReqDTO.Item> convertList(List<TradeOrderItemDO> list);
 
     @Mappings({
@@ -153,9 +154,10 @@ public interface TradeOrderConvert {
             TradeOrderDetailRespVO.OrderLog orderLog = new TradeOrderDetailRespVO.OrderLog();
             orderLog.setContent("订单操作" + i);
             orderLog.setCreateTime(LocalDateTime.now());
+            orderLog.setUserType(i % 2 == 0 ? 2 : 1);
             orderLogs.add(orderLog);
         }
-        orderVO.setOrderLog(orderLogs);
+        orderVO.setLogs(orderLogs);
         return orderVO;
     }
 

+ 2 - 2
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/brokerage/user/BrokerageUserDO.java

@@ -43,7 +43,7 @@ public class BrokerageUserDO extends BaseDO {
     private LocalDateTime bindUserTime;
 
     /**
-     * 推广资格
+     * 是否有分销资格
      */
     private Boolean brokerageEnabled;
     /**
@@ -54,7 +54,7 @@ public class BrokerageUserDO extends BaseDO {
     /**
      * 可用佣金
      */
-    private Integer price;
+    private Integer brokeragePrice;
     /**
      * 冻结佣金
      */

+ 1 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/record/BrokerageRecordMapper.java

@@ -53,6 +53,7 @@ public interface BrokerageRecordMapper extends BaseMapperX<BrokerageRecordDO> {
                 BrokerageRecordDO::getBizId, bizId);
     }
 
+    // TODO @疯狂:mysql 关键字,大写哈;这样看起来清晰点;例如说 SELECT COUNT(1)
     @Select("select count(1), sum(price) from trade_brokerage_record where user_id = #{userId} and biz_type = #{bizType} and status = #{status}")
     UserBrokerageSummaryBO selectCountAndSumPriceByUserIdAndBizTypeAndStatus(@Param("userId") Long userId,
                                                                              @Param("bizType") Integer bizType,

+ 1 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/user/BrokerageUserMapper.java

@@ -134,4 +134,5 @@ public interface BrokerageUserMapper extends BaseMapperX<BrokerageUserDO> {
                 .eq(BrokerageUserDO::getId, id)
                 .set(BrokerageUserDO::getBrokerageEnabled, false).set(BrokerageUserDO::getBrokerageTime, null));
     }
+
 }

+ 36 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/redis/no/TradeOrderNoRedisDAO.java

@@ -0,0 +1,36 @@
+package cn.iocoder.yudao.module.trade.dal.redis.no;
+
+import cn.hutool.core.date.DatePattern;
+import cn.hutool.core.date.DateUtil;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Repository;
+
+import javax.annotation.Resource;
+import java.time.LocalDateTime;
+
+/**
+ * 订单序号的 Redis DAO
+ *
+ * @author HUIHUI
+ */
+@Repository
+public class TradeOrderNoRedisDAO {
+
+    public static final String TRADE_ORDER_NO_PREFIX = "O";
+
+    @Resource
+    private StringRedisTemplate stringRedisTemplate;
+
+    /**
+     * 生成序号
+     *
+     * @param prefix 前缀
+     * @return 序号
+     */
+    public String generate(String prefix) {
+        String noPrefix = prefix + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATETIME_PATTERN);
+        Long no = stringRedisTemplate.opsForValue().increment(noPrefix);
+        return noPrefix + no;
+    }
+
+}

+ 1 - 6
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java

@@ -90,12 +90,7 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa
 
     @Override
     public TradeAfterSaleDO getAfterSale(Long id) {
-        TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(id);
-        // TODO @puhui999;读不到,不要这里报错哈;交给前端报错;一般是读取信息不到,message 提示,然后 close tab;
-        if (afterSale == null) {
-            throw exception(AFTER_SALE_NOT_FOUND);
-        }
-        return afterSale;
+        return tradeAfterSaleMapper.selectById(id);
     }
 
     // TODO 芋艿:拼团失败,要不要发起售后的方式退款?还是走取消逻辑?

+ 2 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/bo/BrokerageAddReqBO.java

@@ -5,6 +5,7 @@ import lombok.Data;
 import lombok.NoArgsConstructor;
 
 import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
 
 /**
  * 佣金 增加 Request BO
@@ -24,6 +25,7 @@ public class BrokerageAddReqBO {
     /**
      * 佣金基数
      */
+    @NotNull(message = "佣金基数不能为空")
     private Integer basePrice;
     /**
      * 一级佣金(固定)

+ 2 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/bo/UserBrokerageSummaryBO.java

@@ -13,6 +13,7 @@ import lombok.NoArgsConstructor;
 @NoArgsConstructor
 @AllArgsConstructor
 public class UserBrokerageSummaryBO {
+
     /**
      * 佣金数量
      */
@@ -21,4 +22,5 @@ public class UserBrokerageSummaryBO {
      * 佣金总额
      */
     private Integer price;
+
 }

+ 1 - 1
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/record/BrokerageRecordService.java

@@ -66,5 +66,5 @@ public interface BrokerageRecordService {
      * @param status  佣金状态
      * @return 用户佣金汇总
      */
-    UserBrokerageSummaryBO summaryByUserIdAndBizTypeAndStatus(Long userId, Integer bizType, Integer status);
+    UserBrokerageSummaryBO getUserBrokerageSummaryByUserId(Long userId, Integer bizType, Integer status);
 }

+ 3 - 2
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/record/BrokerageRecordServiceImpl.java

@@ -91,6 +91,7 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void cancelBrokerage(Long userId, BrokerageRecordBizTypeEnum bizType, String bizId) {
+        // TODO @疯狂:userId 加进去查询,会不会更好一点?万一穿错参数;
         BrokerageRecordDO record = brokerageRecordMapper.selectByBizTypeAndBizId(bizType.getType(), bizId);
         if (record == null || ObjectUtil.notEqual(record.getUserId(), userId)) {
             log.error("[cancelBrokerage][userId({})][bizId({}) 更新为已失效失败:记录不存在]", userId, bizId);
@@ -209,9 +210,9 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
     }
 
     @Override
-    public UserBrokerageSummaryBO summaryByUserIdAndBizTypeAndStatus(Long userId, Integer bizType, Integer status) {
+    public UserBrokerageSummaryBO getUserBrokerageSummaryByUserId(Long userId, Integer bizType, Integer status) {
         UserBrokerageSummaryBO summaryBO = brokerageRecordMapper.selectCountAndSumPriceByUserIdAndBizTypeAndStatus(userId, bizType, status);
-        return summaryBO == null ? new UserBrokerageSummaryBO(0, 0) : summaryBO;
+        return summaryBO != null ? summaryBO : new UserBrokerageSummaryBO(0, 0);
     }
 
     @Transactional(rollbackFor = Exception.class)

+ 6 - 4
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/user/BrokerageUserService.java

@@ -52,7 +52,7 @@ public interface BrokerageUserService {
      * @param id      用户编号
      * @param enabled 推广资格
      */
-    void updateBrokerageEnabled(Long id, Boolean enabled);
+    void updateBrokerageUserEnabled(Long id, Boolean enabled);
 
     /**
      * 获得用户的推广人
@@ -79,20 +79,21 @@ public interface BrokerageUserService {
     void updateUserFrozenPrice(Long id, Integer frozenPrice);
 
     /**
-     * 更新用户冻结佣金(减少), 更新用户佣金(增加)
+     * 更新用户冻结佣金(减少)更新用户佣金(增加)
      *
      * @param id          用户编号
      * @param frozenPrice 减少冻结佣金(负数)
      */
     void updateFrozenPriceDecrAndPriceIncr(Long id, Integer frozenPrice);
 
+    // TODO @疯狂:这个后面可能要支持下,二级
     /**
      * 获得推广用户数量(一级)
      *
      * @param bindUserId 绑定的推广员编号
      * @return 推广用户数量
      */
-    Long getCountByBindUserId(Long bindUserId);
+    Long getBrokerageUserCountByBindUserId(Long bindUserId);
 
     /**
      * 【会员】绑定推广员
@@ -102,5 +103,6 @@ public interface BrokerageUserService {
      * @param isNewUser  是否为新用户
      * @return 是否绑定
      */
-    boolean bindUser(Long userId, Long bindUserId, Boolean isNewUser);
+    boolean bindBrokerageUser(Long userId, Long bindUserId, Boolean isNewUser);
+
 }

+ 26 - 22
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/user/BrokerageUserServiceImpl.java

@@ -55,23 +55,24 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
 
     @Override
     public void updateBrokerageUserId(Long id, Long bindUserId) {
-        // 0. 校验存在
+        // 校验存在
         BrokerageUserDO brokerageUser = validateBrokerageUserExists(id);
+
+        // 情况一:清除推广员
         if (bindUserId == null) {
-            // 1. 清除推广员
+            // 清除推广员
             brokerageUserMapper.updateBindUserIdAndBindUserTimeToNull(id);
             return;
         }
 
-        // 2.1 校验能否绑定
+        // 情况二:修改推广员
         validateCanBindUser(brokerageUser, bindUserId);
-        // 2.2 修改推广员
         brokerageUserMapper.updateById(new BrokerageUserDO().setId(id)
                 .setBindUserId(bindUserId).setBindUserTime(LocalDateTime.now()));
     }
 
     @Override
-    public void updateBrokerageEnabled(Long id, Boolean enabled) {
+    public void updateBrokerageUserEnabled(Long id, Boolean enabled) {
         // 校验存在
         validateBrokerageUserExists(id);
         if (BooleanUtil.isTrue(enabled)) {
@@ -130,39 +131,42 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
     }
 
     @Override
-    public Long getCountByBindUserId(Long bindUserId) {
+    public Long getBrokerageUserCountByBindUserId(Long bindUserId) {
+        // TODO @疯狂:mapper 封装下哈;不直接在 service 调用这种基础 mapper 的基础方法
         return brokerageUserMapper.selectCount(BrokerageUserDO::getBindUserId, bindUserId);
     }
 
+    // TODO @疯狂:因为现在 user 会存在使用验证码直接注册,所以 isNewUser 不太好传递;我们是不是可以约定绑定的时间,createTime 在 30 秒内,就认为新用户;
     @Override
-    public boolean bindUser(Long userId, Long bindUserId, Boolean isNewUser) {
+    public boolean bindBrokerageUser(Long userId, Long bindUserId, Boolean isNewUser) {
+        // TODO @疯狂:userId 为空,搞到参数校验里哇;
         if (userId == null) {
             throw exception(0);
         }
 
-        boolean isInsert = false;
+        // 1. 获得分销用户
+        boolean isNewBrokerageUser = false;
         BrokerageUserDO brokerageUser = brokerageUserMapper.selectById(userId);
-        // 分销用户不存在的情况:1.新注册 2.旧数据 3.分销功能关闭后又打开
-        if (brokerageUser == null) {
-            isInsert = true;
-            brokerageUser = new BrokerageUserDO().setId(userId).setBrokerageEnabled(false).setPrice(0).setFrozenPrice(0);
+        if (brokerageUser == null) { // 分销用户不存在的情况:1. 新注册;2. 旧数据;3. 分销功能关闭后又打开
+            isNewBrokerageUser = true;
+            brokerageUser = new BrokerageUserDO().setId(userId).setBrokerageEnabled(false).setBrokeragePrice(0).setFrozenPrice(0);
         }
 
-        // 校验分配配置
-        boolean validated = validateTradeConfig(brokerageUser, bindUserId, isNewUser);
+        // 2.1 校验是否能绑定用户
+        boolean validated = isUserCanBind(brokerageUser, bindUserId, isNewUser);
         if (!validated) {
             return false;
         }
-
-        // 校验能否绑定
+        // 2.3 校验能否绑定
         validateCanBindUser(brokerageUser, bindUserId);
-
-        if (isInsert) {
+        // 2.3 绑定用户
+        if (isNewBrokerageUser) {
             Integer enabledCondition = tradeConfigService.getTradeConfig().getBrokerageEnabledCondition();
-            if (BrokerageEnabledConditionEnum.ALL.getCondition().equals(enabledCondition)) {
-                // 人人分销:用户默认就有分销资格
+            if (BrokerageEnabledConditionEnum.ALL.getCondition().equals(enabledCondition)) { // 人人分销:用户默认就有分销资格
+                // TODO @疯狂:应该设置下 brokerageTime,而不是 bindUserTime
                 brokerageUser.setBrokerageEnabled(true).setBindUserTime(LocalDateTime.now());
             }
+            // TODO @疯狂:这里是不是要设置 bindUserId、bindUserTime 字段哈;
             brokerageUserMapper.insert(brokerageUser);
         } else {
             brokerageUserMapper.updateById(new BrokerageUserDO().setId(userId)
@@ -171,7 +175,7 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
         return true;
     }
 
-    private boolean validateTradeConfig(BrokerageUserDO user, Long bindUserId, Boolean isNewUser) {
+    private boolean isUserCanBind(BrokerageUserDO user, Long bindUserId, Boolean isNewUser) {
         // 校验分销功能是否启用
         TradeConfigDO tradeConfig = tradeConfigService.getTradeConfig();
         if (tradeConfig == null || !BooleanUtil.isTrue(tradeConfig.getBrokerageEnabled())) {
@@ -194,7 +198,6 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
             }
         }
 
-        validateCanBindUser(user, bindUserId);
         return true;
     }
 
@@ -210,6 +213,7 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
             throw exception(BROKERAGE_BIND_SELF);
         }
 
+        // TODO @疯狂:这块是不是一直查询到根节点,中间不允许出现自己;就是不能形成环。虽然目前是 2 级,但是未来可能会改多级; = = 环的话,就会存在问题哈
         // A->B->A:下级不能绑定自己的上级,   A->B->C->A可以!!
         if (Objects.equals(user.getId(), bindUser.getBindUserId())) {
             throw exception(BROKERAGE_BIND_LOOP);

+ 81 - 47
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java

@@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.trade.service.order;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.lang.Assert;
-import cn.hutool.core.util.IdUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.extra.spring.SpringUtil;
@@ -25,12 +24,14 @@ import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
 import cn.iocoder.yudao.module.product.api.comment.ProductCommentApi;
 import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO;
 import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
+import cn.iocoder.yudao.module.promotion.api.bargain.BargainActivityApi;
 import cn.iocoder.yudao.module.promotion.api.bargain.BargainRecordApi;
 import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi;
 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO;
-import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordUpdateStatusReqDTO;
 import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi;
 import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO;
+import cn.iocoder.yudao.module.promotion.api.seckill.SeckillActivityApi;
+import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
 import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO;
 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderRemarkReqVO;
@@ -46,6 +47,7 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
 import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper;
 import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper;
+import cn.iocoder.yudao.module.trade.dal.redis.no.TradeOrderNoRedisDAO;
 import cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants;
 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum;
 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
@@ -74,7 +76,7 @@ import java.util.Set;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
-import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_NOT_FOUND;
+import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_UPDATE_PRICE_FAIL_EQUAL;
 import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_UPDATE_PRICE_FAIL_PAID;
 import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
 
@@ -92,6 +94,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
     private TradeOrderMapper tradeOrderMapper;
     @Resource
     private TradeOrderItemMapper tradeOrderItemMapper;
+    @Resource
+    private TradeOrderNoRedisDAO orderNoRedisDAO;
 
     @Resource
     private CartService cartService;
@@ -115,6 +119,10 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
     @Resource
     private BargainRecordApi bargainRecordApi;
     @Resource
+    private SeckillActivityApi seckillActivityApi;
+    @Resource
+    private BargainActivityApi bargainActivityApi;
+    @Resource
     private MemberUserApi memberUserApi;
     @Resource
     private MemberLevelApi memberLevelApi;
@@ -195,22 +203,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
         // TODO @puhui999:这个逻辑,先抽个小方法;未来要通过设计模式,把这些拼团之类的逻辑,抽象出去
         // 拼团
         if (Objects.equals(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
-            MemberUserRespDTO user = memberUserApi.getUser(userId);
-            List<CombinationRecordRespDTO> recordRespDTOS = combinationRecordApi.getRecordListByUserIdAndActivityId(userId, createReqVO.getCombinationActivityId());
-            // TODO 拼团一次应该只能选择一种规格的商品
-            TradeOrderItemDO orderItemDO = orderItems.get(0);
-            if (CollUtil.isNotEmpty(recordRespDTOS)) {
-                List<Long> skuIds = convertList(recordRespDTOS, CombinationRecordRespDTO::getSkuId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus()));
-                List<TradeOrderItemDO> tradeOrderItemDOS = tradeOrderItemMapper.selectListByOrderIdAnSkuId(convertList(recordRespDTOS,
-                        CombinationRecordRespDTO::getOrderId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), skuIds);
-                combinationRecordApi.validateCombinationLimitCount(createReqVO.getCombinationActivityId(),
-                        CollectionUtils.getSumValue(tradeOrderItemDOS, TradeOrderItemDO::getCount, Integer::sum), orderItemDO.getCount());
-            }
-
-            combinationRecordApi.createCombinationRecord(TradeOrderConvert.INSTANCE.convert(order, orderItemDO, createReqVO, user));
+            createCombinationRecord(userId, createReqVO, orderItems, order);
         }
         // 3.2 秒杀的特殊逻辑
-        // TODO 秒杀扣减库存是下单就扣除还是等待订单支付成功再扣除
         if (Objects.equals(TradeOrderTypeEnum.SECKILL.getType(), order.getType())) {
 
         }
@@ -220,6 +215,22 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
         return order;
     }
 
+    private void createCombinationRecord(Long userId, AppTradeOrderCreateReqVO createReqVO, List<TradeOrderItemDO> orderItems, TradeOrderDO order) {
+        MemberUserRespDTO user = memberUserApi.getUser(userId);
+        List<CombinationRecordRespDTO> recordRespDTOS = combinationRecordApi.getRecordListByUserIdAndActivityId(userId, createReqVO.getCombinationActivityId());
+        // TODO 拼团一次应该只能选择一种规格的商品
+        TradeOrderItemDO orderItemDO = orderItems.get(0);
+        if (CollUtil.isNotEmpty(recordRespDTOS)) {
+            List<Long> skuIds = convertList(recordRespDTOS, CombinationRecordRespDTO::getSkuId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus()));
+            List<TradeOrderItemDO> tradeOrderItemDOS = tradeOrderItemMapper.selectListByOrderIdAnSkuId(convertList(recordRespDTOS,
+                    CombinationRecordRespDTO::getOrderId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), skuIds);
+            combinationRecordApi.validateCombinationLimitCount(createReqVO.getCombinationActivityId(),
+                    CollectionUtils.getSumValue(tradeOrderItemDOS, TradeOrderItemDO::getCount, Integer::sum), orderItemDO.getCount());
+        }
+
+        combinationRecordApi.createCombinationRecord(TradeOrderConvert.INSTANCE.convert(order, orderItemDO, createReqVO, user));
+    }
+
     // TODO @puhui999:订单超时,自动取消;
 
     /**
@@ -246,8 +257,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
             address = validateAddress(userId, createReqVO.getAddressId());
         }
         TradeOrderDO order = TradeOrderConvert.INSTANCE.convert(userId, clientIp, createReqVO, calculateRespBO, address);
+        String no = orderNoRedisDAO.generate(TradeOrderNoRedisDAO.TRADE_ORDER_NO_PREFIX);
         order.setType(validateActivity(createReqVO));
-        order.setNo(IdUtil.getSnowflakeNextId() + ""); // TODO @puhui999: 参考支付订单,的 no 生成哈;
+        order.setNo(no);
         order.setStatus(TradeOrderStatusEnum.UNPAID.getStatus());
         order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus());
         order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum));
@@ -299,19 +311,23 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
     private void afterCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO,
                                        TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> orderItems,
                                        TradePriceCalculateRespBO calculateRespBO) {
-        // 下单时扣减商品库存
-        // TODO @puhui999:扣库存,需要前置;
+        Integer count = getSumValue(orderItems, TradeOrderItemDO::getCount, Integer::sum);
         // 1)如果是秒杀商品:额外扣减秒杀的库存;
-        // 2)如果是拼团活动:额外扣减拼团的库存;
-        // 3)如果是砍价活动:额外扣减砍价的库存;
-        productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convertNegative(orderItems));
-
-        // 删除购物车商品
-        Set<Long> cartIds = convertSet(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCartId);
-        if (CollUtil.isNotEmpty(cartIds)) {
-            cartService.deleteCart(userId, cartIds);
-        }
-
+        if (Objects.equals(TradeOrderTypeEnum.SECKILL.getType(), tradeOrderDO.getType())) {
+            SeckillActivityUpdateStockReqDTO updateStockReqDTO = new SeckillActivityUpdateStockReqDTO();
+            updateStockReqDTO.setActivityId(createReqVO.getSeckillActivityId());
+            updateStockReqDTO.setCount(count);
+            updateStockReqDTO.setItems(CollectionUtils.convertList(orderItems, item -> {
+                SeckillActivityUpdateStockReqDTO.Item item1 = new SeckillActivityUpdateStockReqDTO.Item();
+                item1.setSpuId(item.getSpuId());
+                item1.setSkuId(item.getSkuId());
+                item1.setCount(item.getCount());
+                return item1;
+            }));
+            seckillActivityApi.updateSeckillStock(updateStockReqDTO);
+        }
+        // 2)如果是砍价活动:额外扣减砍价的库存;
+        bargainActivityApi.updateBargainActivityStock(createReqVO.getBargainActivityId(), count);
         // 扣减积分 TODO 芋艿:待实现,需要前置;
         // 这个是不是应该放到支付成功之后?如果支付后的话,可能积分可以重复使用哈。资源类,都要预扣
 
@@ -321,6 +337,15 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
                     .setOrderId(tradeOrderDO.getId()));
         }
 
+        // 下单时扣减商品库存
+        productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convertNegative(orderItems));
+
+        // 删除购物车商品
+        Set<Long> cartIds = convertSet(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCartId);
+        if (CollUtil.isNotEmpty(cartIds)) {
+            cartService.deleteCart(userId, cartIds);
+        }
+
         // 生成预支付
         createPayOrder(tradeOrderDO, orderItems, calculateRespBO);
 
@@ -357,8 +382,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
         // 1、拼团活动
         if (Objects.equals(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
             // 更新拼团状态 TODO puhui999:订单支付失败或订单支付过期删除这条拼团记录
-            combinationRecordApi.updateCombinationRecordStatus(new CombinationRecordUpdateStatusReqDTO().setUserId(order.getUserId())
-                    .setOrderId(order.getId()).setStatus(CombinationRecordStatusEnum.IN_PROGRESS.getStatus()).setStartTime(LocalDateTime.now()));
+            combinationRecordApi.updateRecordStatusToInProgress(order.getUserId(), order.getId(), LocalDateTime.now());
         }
         // TODO 芋艿:发送订单变化的消息
 
@@ -371,7 +395,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
         // 增加用户经验
         getSelf().addUserExperienceAsync(order.getUserId(), order.getPayPrice(), order.getId());
         // 增加用户佣金
-        getSelf().addBrokerageAsync(order.getUserId(), BrokerageRecordBizTypeEnum.ORDER, order.getId());
+        getSelf().addBrokerageAsync(order.getUserId(), order.getId());
     }
 
     /**
@@ -473,11 +497,6 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
      */
     private TradeOrderDO validateOrderDeliverable(Long id) {
         TradeOrderDO order = validateOrderExists(id);
-        // 校验订单是否是待发货状态
-        // TODO @puhui999:已经发货,可以重新发货,修改信息;
-        if (!TradeOrderStatusEnum.isUndelivered(order.getStatus())) {
-            throw exception(ORDER_DELIVERY_FAIL_STATUS_NOT_UNDELIVERED);
-        }
         // 校验订单是否退款
         if (ObjectUtil.notEqual(TradeOrderRefundStatusEnum.NONE.getStatus(), order.getRefundStatus())) {
             throw exception(ORDER_DELIVERY_FAIL_REFUND_STATUS_NOT_NONE);
@@ -543,20 +562,35 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
     }
 
     @Override
+    // TODO @puhui999:考虑事务性
     public void updateOrderPrice(TradeOrderUpdatePriceReqVO reqVO) {
         // 校验交易订单
         TradeOrderDO order = validateOrderExists(reqVO.getId());
         if (order.getPayStatus()) {
             throw exception(ORDER_UPDATE_PRICE_FAIL_PAID);
         }
-        // TODO @puhui999:如果改价,需要校验下是否真的变化;
-
-        // 更新
-        // TODO @puhui999:TradeOrderItemDO 需要做 adjustPrice 的分摊;另外,支付订单那的价格,需要 update 下;
+        if (ObjectUtil.equal(order.getAdjustPrice(), reqVO.getAdjustPrice())) {
+            throw exception(ORDER_UPDATE_PRICE_FAIL_EQUAL);
+        }
+
+        // TODO @puhui999:应该是按照 payPrice 分配;并且要考虑取余问题;payPrice 也要考虑,item 里的
+        List<TradeOrderItemDO> itemDOs = tradeOrderItemMapper.selectListByOrderId(order.getId());
+        // TradeOrderItemDO 需要做 adjustPrice 的分摊
+        int price = reqVO.getAdjustPrice() / itemDOs.size();
+        itemDOs.forEach(item -> {
+            item.setAdjustPrice(price);
+        });
+        // 更新 TradeOrderItem
+        // TODO @puhui999:不要整个对象去更新哈;应该 new 一下;
+        tradeOrderItemMapper.updateBatch(itemDOs);
+        // 更新订单
+        // TODO @puhui999:要考虑多次修改价格,不能单单的 payPrice + 价格;
         TradeOrderDO update = TradeOrderConvert.INSTANCE.convert(reqVO);
         update.setPayPrice(update.getPayPrice() + update.getAdjustPrice());
         // TODO @芋艿:改价时,赠送的积分,要不要做改动???
         tradeOrderMapper.updateById(update);
+        // 更新支付订单
+        payOrderApi.updatePayOrderPriceById(order.getPayOrderId(), update.getPayPrice());
     }
 
     @Override
@@ -641,7 +675,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
         // 扣减用户经验
         getSelf().reduceUserExperienceAsync(order.getUserId(), orderRefundPrice, afterSaleId);
         // 更新分佣记录为已失效
-        getSelf().cancelBrokerageAsync(order.getUserId(), BrokerageRecordBizTypeEnum.ORDER, id);
+        getSelf().cancelBrokerageAsync(order.getUserId(), id);
     }
 
     @Override
@@ -751,16 +785,16 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
 
 
     @Async
-    protected void addBrokerageAsync(Long userId, BrokerageRecordBizTypeEnum bizType, Long orderId) {
+    protected void addBrokerageAsync(Long userId, Long orderId) {
         List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(orderId);
         List<BrokerageAddReqBO> list = convertList(orderItems,
                 item -> TradeOrderConvert.INSTANCE.convert(item, productSkuApi.getSku(item.getSkuId())));
-        brokerageRecordService.addBrokerage(userId, bizType, list);
+        brokerageRecordService.addBrokerage(userId, BrokerageRecordBizTypeEnum.ORDER, list);
     }
 
     @Async
-    protected void cancelBrokerageAsync(Long userId, BrokerageRecordBizTypeEnum bizType, Long orderItemId) {
-        brokerageRecordService.cancelBrokerage(userId, bizType, String.valueOf(orderItemId));
+    protected void cancelBrokerageAsync(Long userId, Long orderItemId) {
+        brokerageRecordService.cancelBrokerage(userId, BrokerageRecordBizTypeEnum.ORDER, String.valueOf(orderItemId));
     }
 
     /**

+ 0 - 5
yudao-module-member/yudao-module-member-biz/pom.xml

@@ -33,11 +33,6 @@
             <artifactId>yudao-module-infra-api</artifactId>
             <version>${revision}</version>
         </dependency>
-        <dependency>
-            <groupId>cn.iocoder.boot</groupId>
-            <artifactId>yudao-module-trade-api</artifactId>
-            <version>${revision}</version>
-        </dependency>
 
         <!-- 业务组件 -->
         <dependency>

+ 11 - 1
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.http

@@ -28,6 +28,17 @@ tenant-id: {{appTenentId}}
   "code": 9999
 }
 
+### 请求 /social-login 接口 => 成功
+POST {{appApi}}/member/auth/social-login
+Content-Type: application/json
+tenant-id: {{appTenentId}}
+
+{
+  "type": 34,
+  "code": "0e1oc9000CTjFQ1oim200bhtb61oc90g",
+  "state": "default"
+}
+
 ### 请求 /weixin-mini-app-login 接口 => 成功
 POST {{appApi}}/member/auth/weixin-mini-app-login
 Content-Type: application/json
@@ -38,7 +49,6 @@ tenant-id: {{appTenentId}}
   "loginCode": "001frTkl21JUf94VGxol2hSlff1frTkR"
 }
 
-
 ### 请求 /logout 接口 => 成功
 POST {{appApi}}/member/auth/logout
 Content-Type: application/json

+ 8 - 0
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthLoginRespVO.java

@@ -27,4 +27,12 @@ public class AppAuthLoginRespVO {
     @Schema(description = "过期时间", requiredMode = Schema.RequiredMode.REQUIRED)
     private LocalDateTime expiresTime;
 
+    /**
+     * 仅社交登录、社交绑定时会返回
+     *
+     * 为什么需要返回?微信公众号、微信小程序支付需要传递 openid 给支付接口
+     */
+    @Schema(description = "社交用户 openid", example = "qq768")
+    private String openid;
+
 }

+ 1 - 11
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/AppMemberUserController.java

@@ -8,8 +8,6 @@ import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelDO;
 import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
 import cn.iocoder.yudao.module.member.service.level.MemberLevelService;
 import cn.iocoder.yudao.module.member.service.user.MemberUserService;
-import cn.iocoder.yudao.module.trade.api.brokerage.BrokerageApi;
-import cn.iocoder.yudao.module.trade.api.brokerage.dto.BrokerageUserDTO;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import lombok.extern.slf4j.Slf4j;
@@ -18,7 +16,6 @@ import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
 import javax.validation.Valid;
-import java.util.Optional;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
@@ -32,23 +29,16 @@ public class AppMemberUserController {
 
     @Resource
     private MemberUserService userService;
-
     @Resource
     private MemberLevelService levelService;
 
-    @Resource
-    private BrokerageApi brokerageApi;
-
     @GetMapping("/get")
     @Operation(summary = "获得基本信息")
     @PreAuthenticated
     public CommonResult<AppMemberUserInfoRespVO> getUserInfo() {
         MemberUserDO user = userService.getUser(getLoginUserId());
         MemberLevelDO level = levelService.getLevel(user.getLevelId());
-        BrokerageUserDTO brokerageUser = brokerageApi.getBrokerageUser(user.getId());
-        return success(MemberUserConvert.INSTANCE.convert(user, level)
-                .setBrokerageEnabled(Optional.ofNullable(brokerageUser).map(BrokerageUserDTO::getBrokerageEnabled).orElse(false))
-        );
+        return success(MemberUserConvert.INSTANCE.convert(user, level));
     }
 
     @PutMapping("/update")

+ 1 - 1
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/auth/AuthConvert.java

@@ -25,7 +25,7 @@ public interface AuthConvert {
     SmsCodeUseReqDTO convert(AppMemberUserResetPasswordReqVO reqVO, SmsSceneEnum scene, String usedIp);
     SmsCodeUseReqDTO convert(AppAuthSmsLoginReqVO reqVO, Integer scene, String usedIp);
 
-    AppAuthLoginRespVO convert(OAuth2AccessTokenRespDTO bean);
+    AppAuthLoginRespVO convert(OAuth2AccessTokenRespDTO bean, String openid);
 
     SmsCodeValidateReqDTO convert(AppAuthSmsValidateReqVO bean);
 

+ 17 - 13
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java

@@ -20,6 +20,7 @@ import cn.iocoder.yudao.module.system.api.oauth2.dto.OAuth2AccessTokenRespDTO;
 import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
 import cn.iocoder.yudao.module.system.api.social.SocialUserApi;
 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
+import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO;
 import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum;
 import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum;
 import cn.iocoder.yudao.module.system.enums.oauth2.OAuth2ClientConstants;
@@ -65,13 +66,14 @@ public class MemberAuthServiceImpl implements MemberAuthService {
         MemberUserDO user = login0(reqVO.getMobile(), reqVO.getPassword());
 
         // 如果 socialType 非空,说明需要绑定社交用户
+        String openid = null;
         if (reqVO.getSocialType() != null) {
-            socialUserApi.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(),
+            openid = socialUserApi.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(),
                     reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState()));
         }
 
         // 创建 Token 令牌,记录登录日志
-        return createTokenAfterLoginSuccess(user, reqVO.getMobile(), LoginLogTypeEnum.LOGIN_MOBILE);
+        return createTokenAfterLoginSuccess(user, reqVO.getMobile(), LoginLogTypeEnum.LOGIN_MOBILE, openid);
     }
 
     @Override
@@ -86,32 +88,33 @@ public class MemberAuthServiceImpl implements MemberAuthService {
         Assert.notNull(user, "获取用户失败,结果为空");
 
         // 如果 socialType 非空,说明需要绑定社交用户
+        String openid = null;
         if (reqVO.getSocialType() != null) {
-            socialUserApi.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(),
+            openid = socialUserApi.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(),
                     reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState()));
         }
 
         // 创建 Token 令牌,记录登录日志
-        return createTokenAfterLoginSuccess(user, reqVO.getMobile(), LoginLogTypeEnum.LOGIN_SMS);
+        return createTokenAfterLoginSuccess(user, reqVO.getMobile(), LoginLogTypeEnum.LOGIN_SMS, openid);
     }
 
     @Override
     public AppAuthLoginRespVO socialLogin(AppAuthSocialLoginReqVO reqVO) {
         // 使用 code 授权码,进行登录。然后,获得到绑定的用户编号
-        Long userId = socialUserApi.getBindUserId(UserTypeEnum.MEMBER.getValue(), reqVO.getType(),
+        SocialUserRespDTO socialUser = socialUserApi.getSocialUser(UserTypeEnum.MEMBER.getValue(), reqVO.getType(),
                 reqVO.getCode(), reqVO.getState());
-        if (userId == null) {
+        if (socialUser == null) {
             throw exception(AUTH_THIRD_LOGIN_NOT_BIND);
         }
 
         // 自动登录
-        MemberUserDO user = userService.getUser(userId);
+        MemberUserDO user = userService.getUser(socialUser.getUserId());
         if (user == null) {
             throw exception(USER_NOT_EXISTS);
         }
 
         // 创建 Token 令牌,记录登录日志
-        return createTokenAfterLoginSuccess(user, user.getMobile(), LoginLogTypeEnum.LOGIN_SOCIAL);
+        return createTokenAfterLoginSuccess(user, user.getMobile(), LoginLogTypeEnum.LOGIN_SOCIAL, socialUser.getOpenid());
     }
 
     @Override
@@ -129,14 +132,15 @@ public class MemberAuthServiceImpl implements MemberAuthService {
         Assert.notNull(user, "获取用户失败,结果为空");
 
         // 绑定社交用户
-        socialUserApi.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(),
+        String openid = socialUserApi.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(),
                 SocialTypeEnum.WECHAT_MINI_APP.getType(), reqVO.getLoginCode(), ""));
 
         // 创建 Token 令牌,记录登录日志
-        return createTokenAfterLoginSuccess(user, user.getMobile(), LoginLogTypeEnum.LOGIN_SOCIAL);
+        return createTokenAfterLoginSuccess(user, user.getMobile(), LoginLogTypeEnum.LOGIN_SOCIAL, openid);
     }
 
-    private AppAuthLoginRespVO createTokenAfterLoginSuccess(MemberUserDO user, String mobile, LoginLogTypeEnum logType) {
+    private AppAuthLoginRespVO createTokenAfterLoginSuccess(MemberUserDO user, String mobile,
+                                                            LoginLogTypeEnum logType, String openid) {
         // 插入登陆日志
         createLoginLog(user.getId(), mobile, logType, LoginResultEnum.SUCCESS);
         // 创建 Token 令牌
@@ -144,7 +148,7 @@ public class MemberAuthServiceImpl implements MemberAuthService {
                 .setUserId(user.getId()).setUserType(getUserType().getValue())
                 .setClientId(OAuth2ClientConstants.CLIENT_ID_DEFAULT));
         // 构建返回结果
-        return AuthConvert.INSTANCE.convert(accessTokenRespDTO);
+        return AuthConvert.INSTANCE.convert(accessTokenRespDTO, openid);
     }
 
     @Override
@@ -231,7 +235,7 @@ public class MemberAuthServiceImpl implements MemberAuthService {
     public AppAuthLoginRespVO refreshToken(String refreshToken) {
         OAuth2AccessTokenRespDTO accessTokenDO = oauth2TokenApi.refreshAccessToken(refreshToken,
                 OAuth2ClientConstants.CLIENT_ID_DEFAULT);
-        return AuthConvert.INSTANCE.convert(accessTokenDO);
+        return AuthConvert.INSTANCE.convert(accessTokenDO, null);
     }
 
     private void createLogoutLog(Long userId) {

+ 9 - 0
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApi.java

@@ -29,4 +29,13 @@ public interface PayOrderApi {
      */
     PayOrderRespDTO getOrder(Long id);
 
+    // TODO @puhui999:可以去掉 byId;然后 payOrderId 参数改成 id;
+    /**
+     * 更新支付订单价格
+     *
+     * @param payOrderId 支付单编号
+     * @param payPrice   支付单价格
+     */
+    void updatePayOrderPriceById(Long payOrderId, Integer payPrice);
+
 }

+ 1 - 0
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java

@@ -28,6 +28,7 @@ public interface ErrorCodeConstants {
     ErrorCode ORDER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1007002004, "发起支付报错,错误码:{},错误提示:{}");
     ErrorCode ORDER_REFUND_FAIL_STATUS_ERROR = new ErrorCode(1007002005, "支付订单退款失败,原因:状态不是已支付或已退款");
     ErrorCode ORDER_UPDATE_PRICE_FAIL_PAID = new ErrorCode(1007002006, "支付订单调价失败,原因:支付订单已付款,不能调价");
+    ErrorCode ORDER_UPDATE_PRICE_FAIL_EQUAL = new ErrorCode(1007002007, "支付订单调价失败,原因:价格没有变化");
 
     // ========== ORDER 模块(拓展单) 1007003000 ==========
     ErrorCode ORDER_EXTENSION_NOT_FOUND = new ErrorCode(1007003000, "支付交易拓展单不存在");

+ 5 - 0
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApiImpl.java

@@ -31,4 +31,9 @@ public class PayOrderApiImpl implements PayOrderApi {
         return PayOrderConvert.INSTANCE.convert2(order);
     }
 
+    @Override
+    public void updatePayOrderPriceById(Long payOrderId, Integer payPrice) {
+        payOrderService.updatePayOrderPriceById(payOrderId, payPrice);
+    }
+
 }

+ 15 - 6
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/PayOrderController.java

@@ -6,14 +6,15 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
 import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
-import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.*;
 import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert;
 import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;
+import cn.iocoder.yudao.module.pay.framework.pay.wallet.WalletPayClient;
 import cn.iocoder.yudao.module.pay.service.app.PayAppService;
 import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
+import com.google.common.collect.Maps;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
 import io.swagger.v3.oas.annotations.tags.Tag;
@@ -25,12 +26,17 @@ import javax.annotation.Resource;
 import javax.servlet.http.HttpServletResponse;
 import javax.validation.Valid;
 import java.io.IOException;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
 import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
 import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
+import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
+import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserType;
 
 @Tag(name = "管理后台 - 支付订单")
 @RestController
@@ -70,13 +76,16 @@ public class PayOrderController {
     @PostMapping("/submit")
     @Operation(summary = "提交支付订单")
     public CommonResult<PayOrderSubmitRespVO> submitPayOrder(@RequestBody PayOrderSubmitReqVO reqVO) {
-        // 钱包支付需要 额外传 user_id 和 user_type
+        // 1. 钱包支付事,需要额外传 user_id 和 user_type
         if (Objects.equals(reqVO.getChannelCode(), PayChannelEnum.WALLET.getCode())) {
-            Map<String, String> channelExtras = reqVO.getChannelExtras() == null ? new HashMap<>(8) : reqVO.getChannelExtras();
-            channelExtras.put("user_id", String.valueOf(WebFrameworkUtils.getLoginUserId()));
-            channelExtras.put("user_type", String.valueOf(WebFrameworkUtils.getLoginUserType()));
+            Map<String, String> channelExtras = reqVO.getChannelExtras() == null ?
+                    Maps.newHashMapWithExpectedSize(2) : reqVO.getChannelExtras();
+            channelExtras.put(WalletPayClient.USER_ID_KEY, String.valueOf(getLoginUserId()));
+            channelExtras.put(WalletPayClient.USER_TYPE_KEY, String.valueOf(getLoginUserType()));
             reqVO.setChannelExtras(channelExtras);
         }
+
+        // 2. 提交支付
         PayOrderSubmitRespVO respVO = orderService.submitOrder(reqVO, getClientIP());
         return success(respVO);
     }

+ 1 - 1
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/AppPayWalletController.java

@@ -37,7 +37,7 @@ public class AppPayWalletController {
     @Operation(summary = "获取钱包")
     @PreAuthenticated
     public CommonResult<AppPayWalletRespVO> getPayWallet() {
-        PayWalletDO wallet = payWalletService.getOrCreatePayWallet(getLoginUserId(), UserTypeEnum.MEMBER.getValue());
+        PayWalletDO wallet = payWalletService.getOrCreateWallet(getLoginUserId(), UserTypeEnum.MEMBER.getValue());
         return success(PayWalletConvert.INSTANCE.convert(wallet));
     }
 

+ 2 - 2
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/vo/wallet/AppPayWalletRespVO.java

@@ -11,9 +11,9 @@ public class AppPayWalletRespVO {
     private Integer balance;
 
     @Schema(description = "累计支出, 单位分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000")
-    private Long totalExpense;
+    private Integer totalExpense;
 
     @Schema(description = "累计充值, 单位分", requiredMode = Schema.RequiredMode.REQUIRED, example = "2000")
-    private Long totalRecharge;
+    private Integer totalRecharge;
 
 }

+ 4 - 0
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/wallet/PayWalletTransactionConvert.java

@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.pay.convert.wallet;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.transaction.AppPayWalletTransactionRespVO;
 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO;
+import cn.iocoder.yudao.module.pay.service.wallet.bo.CreateWalletTransactionBO;
 import org.mapstruct.Mapper;
 import org.mapstruct.factory.Mappers;
 
@@ -12,4 +13,7 @@ public interface PayWalletTransactionConvert {
     PayWalletTransactionConvert INSTANCE = Mappers.getMapper(PayWalletTransactionConvert.class);
 
     PageResult<AppPayWalletTransactionRespVO> convertPage(PageResult<PayWalletTransactionDO> page);
+
+    PayWalletTransactionDO convert(CreateWalletTransactionBO bean);
+
 }

+ 2 - 2
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/wallet/PayWalletDO.java

@@ -45,10 +45,10 @@ public class PayWalletDO extends BaseDO {
     /**
      * 累计支出,单位分
      */
-    private Long totalExpense;
+    private Integer totalExpense;
     /**
      * 累计充值,单位分
      */
-    private Long totalRecharge;
+    private Integer totalRecharge;
 
 }

+ 18 - 39
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/wallet/PayWalletMapper.java

@@ -3,8 +3,7 @@ package cn.iocoder.yudao.module.pay.dal.mysql.wallet;
 
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO;
-import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum;
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import org.apache.ibatis.annotations.Mapper;
 
 @Mapper
@@ -16,52 +15,32 @@ public interface PayWalletMapper extends BaseMapperX<PayWalletDO> {
     }
 
     /**
-     * 当余额减少时候更新
+     * 当消费退款时候, 更新钱包
      *
-     * @param bizType 业务类型
-     * @param balance 当前余额
-     * @param totalRecharge 当前累计充值
-     * @param totalExpense 当前累计支出
-     * @param price 支出的金额
+     * @param price 消费金额
      * @param id 钱包 id
      */
-    default int updateWhenDecBalance(PayWalletBizTypeEnum bizType, Integer balance, Long totalRecharge,
-                                     Long totalExpense, Integer price, Long id) {
-        PayWalletDO updateDO = new PayWalletDO().setBalance(balance - price);
-        if(bizType == PayWalletBizTypeEnum.PAYMENT){
-            updateDO.setTotalExpense(totalExpense + price);
-        }
-        if (bizType == PayWalletBizTypeEnum.RECHARGE_REFUND) {
-            updateDO.setTotalRecharge(totalRecharge - price);
-        }
-        return update(updateDO,
-                new LambdaQueryWrapper<PayWalletDO>().eq(PayWalletDO::getId, id)
-                        .eq(PayWalletDO::getBalance, balance)
-                        .ge(PayWalletDO::getBalance, price));
+    default int updateWhenConsumptionRefund(Integer price, Long id){
+        LambdaUpdateWrapper<PayWalletDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<PayWalletDO>()
+                .setSql(" balance = balance + " + price
+                        + ", total_expense = total_expense - " + price)
+                .eq(PayWalletDO::getId, id);
+        return update(null, lambdaUpdateWrapper);
     }
 
     /**
-     * 当余额增加时候更新
+     * 当消费时候, 更新钱包
      *
-     * @param bizType  业务类型
-     * @param balance  当前余额
-     * @param totalRecharge 当前累计充值
-     * @param totalExpense 当前累计支出
-     * @param price 金额
+     * @param price 消费金额
      * @param id 钱包 id
      */
-    default int updateWhenIncBalance(PayWalletBizTypeEnum bizType, Integer balance, Long totalRecharge,
-                                     Long totalExpense, Integer price, Long id) {
-        PayWalletDO updateDO = new PayWalletDO().setBalance(balance + price);
-        if (bizType == PayWalletBizTypeEnum.PAYMENT_REFUND) {
-            updateDO.setTotalExpense(totalExpense - price);
-        }
-        if (bizType == PayWalletBizTypeEnum.RECHARGE) {
-            updateDO.setTotalExpense(totalRecharge + price);
-        }
-        return update(updateDO,
-                new LambdaQueryWrapper<PayWalletDO>().eq(PayWalletDO::getId, id)
-                        .eq(PayWalletDO::getBalance, balance));
+    default int updateWhenConsumption(Integer price, Long id){
+        LambdaUpdateWrapper<PayWalletDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<PayWalletDO>()
+                .setSql(" balance = balance - " + price
+                        + ", total_expense = total_expense + " + price)
+                .eq(PayWalletDO::getId, id)
+                .ge(PayWalletDO::getBalance, price); // cas 逻辑
+        return update(null, lambdaUpdateWrapper);
     }
 }
 

+ 17 - 17
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/wallet/WalletPayClient.java

@@ -37,13 +37,13 @@ import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.REFUND_NOT_FO
 @Slf4j
 public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> {
 
-    private PayWalletService wallService;
+    public static final String USER_ID_KEY = "user_id";
+    public static final String USER_TYPE_KEY = "user_type";
 
+    private PayWalletService wallService;
     private PayWalletTransactionService walletTransactionService;
-
-    private PayOrderService payOrderService;
-
-    private PayRefundService payRefundService;
+    private PayOrderService orderService;
+    private PayRefundService refundService;
 
     public WalletPayClient(Long channelId,  NonePayClientConfig config) {
         super(channelId, PayChannelEnum.WALLET.getCode(), config);
@@ -62,12 +62,12 @@ public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> {
     @Override
     protected PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) {
         try {
-            String userId = MapUtil.getStr(reqDTO.getChannelExtras(), "user_id");
-            String userType = MapUtil.getStr(reqDTO.getChannelExtras(), "user_type");
-            Assert.notEmpty(userId, "用户 id 不能为空");
-            Assert.notEmpty(userType, "用户类型不能为空");
-            PayWalletTransactionDO transaction = wallService.orderPay(Long.valueOf(userId), Integer.valueOf(userType),
-                    reqDTO.getOutTradeNo(), reqDTO.getPrice());
+            Long userId = MapUtil.getLong(reqDTO.getChannelExtras(), USER_ID_KEY);
+            Integer userType = MapUtil.getInt(reqDTO.getChannelExtras(), USER_TYPE_KEY);
+            Assert.notNull(userId, "用户 id 不能为空");
+            Assert.notNull(userType, "用户类型不能为空");
+            PayWalletTransactionDO transaction = wallService.orderPay(userId, userType, reqDTO.getOutTradeNo(),
+                    reqDTO.getPrice());
             return PayOrderRespDTO.successOf(transaction.getNo(), transaction.getCreator(),
                     transaction.getCreateTime(),
                     reqDTO.getOutTradeNo(), transaction);
@@ -92,10 +92,10 @@ public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> {
 
     @Override
     protected PayOrderRespDTO doGetOrder(String outTradeNo) {
-        if (payOrderService == null) {
-            payOrderService = SpringUtil.getBean(PayOrderService.class);
+        if (orderService == null) {
+            orderService = SpringUtil.getBean(PayOrderService.class);
         }
-        PayOrderExtensionDO orderExtension = payOrderService.getOrderExtensionByNo(outTradeNo);
+        PayOrderExtensionDO orderExtension = orderService.getOrderExtensionByNo(outTradeNo);
         // 支付交易拓展单不存在, 返回关闭状态
         if (orderExtension == null) {
             return PayOrderRespDTO.closedOf(String.valueOf(ORDER_EXTENSION_NOT_FOUND.getCode()),
@@ -147,10 +147,10 @@ public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> {
 
     @Override
     protected PayRefundRespDTO doGetRefund(String outTradeNo, String outRefundNo) {
-        if (payRefundService == null) {
-            payRefundService = SpringUtil.getBean(PayRefundService.class);
+        if (refundService == null) {
+            refundService = SpringUtil.getBean(PayRefundService.class);
         }
-        PayRefundDO payRefund = payRefundService.getRefundByNo(outRefundNo);
+        PayRefundDO payRefund = refundService.getRefundByNo(outRefundNo);
         // 支付退款单不存在, 返回退款失败状态
         if (payRefund == null) {
             return PayRefundRespDTO.failureOf(String.valueOf(REFUND_NOT_FOUND), REFUND_NOT_FOUND.getMsg(),

+ 11 - 3
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderService.java

@@ -33,7 +33,7 @@ public interface PayOrderService {
     /**
      * 获得支付订单
      *
-     * @param appId 应用编号
+     * @param appId           应用编号
      * @param merchantOrderId 商户订单编号
      * @return 支付订单
      */
@@ -75,7 +75,7 @@ public interface PayOrderService {
      * 提交支付
      * 此时,会发起支付渠道的调用
      *
-     * @param reqVO 提交请求
+     * @param reqVO  提交请求
      * @param userIp 提交 IP
      * @return 提交结果
      */
@@ -93,11 +93,19 @@ public interface PayOrderService {
     /**
      * 更新支付订单的退款金额
      *
-     * @param id 编号
+     * @param id              编号
      * @param incrRefundPrice 增加的退款金额
      */
     void updateOrderRefundPrice(Long id, Integer incrRefundPrice);
 
+    /**
+     * 更新支付订单价格
+     *
+     * @param payOrderId 支付单编号
+     * @param payPrice   支付单价格
+     */
+    void updatePayOrderPriceById(Long payOrderId, Integer payPrice);
+
     /**
      * 获得支付订单
      *

+ 12 - 0
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java

@@ -411,6 +411,18 @@ public class PayOrderServiceImpl implements PayOrderService {
         }
     }
 
+    @Override
+    public void updatePayOrderPriceById(Long payOrderId, Integer payPrice) {
+        // TODO @puhui999:不能直接这样修改哈;应该只有未支付状态的订单才可以改;另外,如果价格如果没变,可以直接 return 哈;
+        PayOrderDO order = orderMapper.selectById(payOrderId);
+        if (order == null) {
+            throw exception(ORDER_NOT_FOUND);
+        }
+
+        order.setPrice(payPrice);
+        orderMapper.updateById(order);
+    }
+
     @Override
     public PayOrderExtensionDO getOrderExtension(Long id) {
         return orderExtensionMapper.selectById(id);

+ 12 - 12
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletService.java

@@ -12,12 +12,14 @@ import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum;
 public interface PayWalletService {
 
     /**
-     * 获取钱包信息,如果不存在创建钱包。由于用户注册时候不会创建钱包
+     * 获取钱包信息
+     *
+     * 如果不存在,则创建钱包。由于用户注册时候不会创建钱包
      *
      * @param userId 用户编号
      * @param userType 用户类型
      */
-    PayWalletDO getOrCreatePayWallet(Long userId, Integer userType);
+    PayWalletDO getOrCreateWallet(Long userId, Integer userType);
 
     /**
      * 钱包订单支付
@@ -29,6 +31,14 @@ public interface PayWalletService {
      */
     PayWalletTransactionDO orderPay(Long userId, Integer userType, String outTradeNo, Integer price);
 
+    /**
+     * 钱包订单支付退款
+     *
+     * @param outRefundNo 外部退款号
+     * @param refundPrice 退款金额
+     * @param reason  退款原因
+     */
+    PayWalletTransactionDO orderRefund(String outRefundNo, Integer refundPrice, String reason);
 
     /**
      * 扣减钱包余额
@@ -43,7 +53,6 @@ public interface PayWalletService {
     PayWalletTransactionDO reduceWalletBalance(Long userId, Integer userType,
                                                Long bizId, PayWalletBizTypeEnum bizType, Integer price);
 
-
     /**
      * 增加钱包余额
      *
@@ -57,13 +66,4 @@ public interface PayWalletService {
     PayWalletTransactionDO addWalletBalance(Long userId, Integer userType,
                                             Long bizId, PayWalletBizTypeEnum bizType, Integer price);
 
-    /**
-     * 钱包订单支付退款
-     *
-     * @param outRefundNo 外部退款号
-     * @param refundPrice 退款金额
-     * @param reason  退款原因
-     */
-    PayWalletTransactionDO orderRefund(String outRefundNo, Integer refundPrice, String reason);
-
 }

+ 83 - 109
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletServiceImpl.java

@@ -6,10 +6,10 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO;
 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO;
 import cn.iocoder.yudao.module.pay.dal.mysql.wallet.PayWalletMapper;
-import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO;
 import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum;
 import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
 import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
+import cn.iocoder.yudao.module.pay.service.wallet.bo.CreateWalletTransactionBO;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
@@ -18,7 +18,6 @@ import org.springframework.transaction.annotation.Transactional;
 import javax.annotation.Resource;
 import java.time.LocalDateTime;
 
-import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.TOO_MANY_REQUESTS;
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
 import static cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum.PAYMENT;
@@ -33,135 +32,55 @@ import static cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum.PAYM
 @Slf4j
 public class PayWalletServiceImpl implements  PayWalletService {
 
-    /**
-     * 余额支付的 no 前缀
-     */
-    private static final String WALLET_PAY_NO_PREFIX = "WP";
-    /**
-     * 余额退款的 no 前缀
-     */
-    private static final String WALLET_REFUND_NO_PREFIX = "WR";
-
-    @Resource
-    private PayWalletMapper payWalletMapper;
     @Resource
-    private PayNoRedisDAO noRedisDAO;
-
+    private PayWalletMapper walletMapper;
     @Resource
-    private PayWalletTransactionService payWalletTransactionService;
+    private PayWalletTransactionService walletTransactionService;
     @Resource
     @Lazy
-    private PayOrderService payOrderService;
+    private PayOrderService orderService;
     @Resource
     @Lazy
-    private PayRefundService payRefundService;
+    private PayRefundService refundService;
 
     @Override
-    public PayWalletDO getOrCreatePayWallet(Long userId, Integer userType) {
-        PayWalletDO payWalletDO = payWalletMapper.selectByUserIdAndType(userId, userType);
-        if (payWalletDO == null) {
-            payWalletDO = new PayWalletDO();
-            payWalletDO.setUserId(userId);
-            payWalletDO.setUserType(userType);
-            payWalletDO.setBalance(0);
-            payWalletDO.setTotalExpense(0L);
-            payWalletDO.setTotalRecharge(0L);
-            payWalletDO.setCreateTime(LocalDateTime.now());
-            payWalletMapper.insert(payWalletDO);
+    public PayWalletDO getOrCreateWallet(Long userId, Integer userType) {
+        PayWalletDO wallet = walletMapper.selectByUserIdAndType(userId, userType);
+        if (wallet == null) {
+            wallet = new PayWalletDO().setUserId(userId).setUserType(userType)
+                    .setBalance(0).setTotalExpense(0).setTotalRecharge(0);
+            wallet.setCreateTime(LocalDateTime.now());
+            walletMapper.insert(wallet);
         }
-        return payWalletDO;
+        return wallet;
     }
 
-
     @Override
     @Transactional(rollbackFor = Exception.class)
     public PayWalletTransactionDO orderPay(Long userId, Integer userType, String outTradeNo, Integer price) {
-        // 判断支付交易拓展单是否存
-        PayOrderExtensionDO orderExtension = payOrderService.getOrderExtensionByNo(outTradeNo);
+        // 1. 判断支付交易拓展单是否存
+        PayOrderExtensionDO orderExtension = orderService.getOrderExtensionByNo(outTradeNo);
         if (orderExtension == null) {
             throw exception(ORDER_EXTENSION_NOT_FOUND);
         }
+        // 2. 扣减余额
         return reduceWalletBalance(userId, userType, orderExtension.getOrderId(), PAYMENT, price);
     }
 
-    @Override
-    public PayWalletTransactionDO reduceWalletBalance(Long userId, Integer userType,
-                                                      Long bizId, PayWalletBizTypeEnum bizType, Integer price) {
-        // 1.1 获取钱包
-        PayWalletDO payWallet = getOrCreatePayWallet(userId, userType);
-        // 1.2 判断余额是否足够
-        int afterBalance = payWallet.getBalance() - price;
-        if (afterBalance < 0) {
-            throw exception(WALLET_BALANCE_NOT_ENOUGH);
-        }
-
-        // 2.1 扣除余额
-        int number = payWalletMapper.updateWhenDecBalance(bizType,payWallet.getBalance(), payWallet.getTotalRecharge(),
-                payWallet.getTotalExpense(), price, payWallet.getId());
-        if (number == 0) {
-            throw exception(TOO_MANY_REQUESTS);
-        }
-        // 2.2 生成钱包流水
-        String walletNo = generateWalletNo(bizType);
-        PayWalletTransactionDO walletTransaction = new PayWalletTransactionDO().setWalletId(payWallet.getId())
-                .setNo(walletNo).setPrice(-price).setBalance(afterBalance)
-                .setBizId(String.valueOf(bizId)).setBizType(bizType.getType()).setTitle(bizType.getDescription());
-        payWalletTransactionService.createWalletTransaction(walletTransaction);
-        return walletTransaction;
-    }
-
-    @Override
-    public PayWalletTransactionDO addWalletBalance(Long userId, Integer userType, Long bizId,
-                                                   PayWalletBizTypeEnum bizType, Integer price) {
-        // 1.1 获取钱包
-        PayWalletDO payWallet = getOrCreatePayWallet(userId, userType);
-
-        // 2.1 增加余额
-        int number = payWalletMapper.updateWhenIncBalance(bizType, payWallet.getBalance(), payWallet.getTotalRecharge(),
-                payWallet.getTotalExpense(), price, payWallet.getId());
-        if (number == 0) {
-            throw exception(TOO_MANY_REQUESTS);
-        }
-
-        // 2.2 生成钱包流水
-        String walletNo = generateWalletNo(bizType);
-        PayWalletTransactionDO newWalletTransaction = new PayWalletTransactionDO().setWalletId(payWallet.getId())
-                .setNo(walletNo).setPrice(price).setBalance(payWallet.getBalance()+price)
-                .setBizId(String.valueOf(bizId)).setBizType(bizType.getType())
-                .setTitle(bizType.getDescription());
-        payWalletTransactionService.createWalletTransaction(newWalletTransaction);
-        return newWalletTransaction;
-    }
-
-    private String generateWalletNo(PayWalletBizTypeEnum bizType) {
-        String no = "";
-        switch(bizType){
-            case PAYMENT :
-                no = noRedisDAO.generate(WALLET_PAY_NO_PREFIX);
-                break;
-            case PAYMENT_REFUND :
-                no = noRedisDAO.generate(WALLET_REFUND_NO_PREFIX);
-                break;
-            default :
-                // TODO 待增加
-        }
-        return no;
-    }
-
     @Override
     @Transactional(rollbackFor = Exception.class)
     public PayWalletTransactionDO orderRefund(String outRefundNo, Integer refundPrice, String reason) {
         // 1.1 判断退款单是否存在
-        PayRefundDO payRefund = payRefundService.getRefundByNo(outRefundNo);
+        PayRefundDO payRefund = refundService.getRefundByNo(outRefundNo);
         if (payRefund == null) {
             throw exception(REFUND_NOT_FOUND);
         }
         // 1.2 校验是否可以退款
-        Long walletId =  validateWalletCanRefund(payRefund.getId(), payRefund.getChannelOrderNo(),  refundPrice);
-
-        PayWalletDO payWallet = payWalletMapper.selectById(walletId);
-        Assert.notNull(payWallet, "钱包 {} 不存在", walletId);
-        return addWalletBalance(payWallet.getUserId(), payWallet.getUserType(),payRefund.getId(), PAYMENT_REFUND, refundPrice);
+        Long walletId = validateWalletCanRefund(payRefund.getId(), payRefund.getChannelOrderNo(),  refundPrice);
+        PayWalletDO wallet = walletMapper.selectById(walletId);
+        Assert.notNull(wallet, "钱包 {} 不存在", walletId);
+        // 2. 增加余额
+        return addWalletBalance(wallet.getUserId(), wallet.getUserType(), payRefund.getId(), PAYMENT_REFUND, refundPrice);
     }
 
     /**
@@ -171,21 +90,76 @@ public class PayWalletServiceImpl implements  PayWalletService {
      * @param walletPayNo 钱包支付 no
      */
     private Long validateWalletCanRefund(Long refundId, String walletPayNo, Integer refundPrice) {
-        // 查询钱包支付交易
-        PayWalletTransactionDO payWalletTransaction = payWalletTransactionService.getWalletTransactionByNo(walletPayNo);
-        if (payWalletTransaction == null) {
+        // 1. 校验钱包支付交易存在
+        PayWalletTransactionDO walletTransaction = walletTransactionService.getWalletTransactionByNo(walletPayNo);
+        if (walletTransaction == null) {
             throw exception(WALLET_TRANSACTION_NOT_FOUND);
         }
         // 原来的支付金额
-        int amount = - payWalletTransaction.getPrice();
+        // TODO @jason:应该允许多次退款哈;
+        int amount = - walletTransaction.getPrice();
         if (refundPrice != amount) {
             throw exception(WALLET_REFUND_AMOUNT_ERROR);
         }
-        PayWalletTransactionDO refundTransaction = payWalletTransactionService.getWalletTransaction(
+        PayWalletTransactionDO refundTransaction = walletTransactionService.getWalletTransaction(
                 String.valueOf(refundId), PAYMENT_REFUND);
         if (refundTransaction != null) {
             throw exception(WALLET_REFUND_EXIST);
         }
-        return payWalletTransaction.getWalletId();
+        return walletTransaction.getWalletId();
+    }
+
+    @Override
+    public PayWalletTransactionDO reduceWalletBalance(Long userId, Integer userType,
+                                                      Long bizId, PayWalletBizTypeEnum bizType, Integer price) {
+        // 1. 获取钱包
+        PayWalletDO payWallet = getOrCreateWallet(userId, userType);
+
+        // 2.1 扣除余额
+        int updateCounts = 0 ;
+        switch (bizType) {
+            case PAYMENT: {
+                updateCounts = walletMapper.updateWhenConsumption(price, payWallet.getId());
+                break;
+            }
+            case RECHARGE_REFUND: {
+                // TODO
+                break;
+            }
+        }
+        if (updateCounts == 0) {
+            throw exception(WALLET_BALANCE_NOT_ENOUGH);
+        }
+        // 2.2 生成钱包流水
+        Integer afterBalance = payWallet.getBalance() - price;
+        CreateWalletTransactionBO bo = new CreateWalletTransactionBO().setWalletId(payWallet.getId())
+                .setPrice(-price).setBalance(afterBalance).setBizId(String.valueOf(bizId))
+                .setBizType(bizType.getType()).setTitle(bizType.getDescription());
+        return walletTransactionService.createWalletTransaction(bo);
     }
+
+    @Override
+    public PayWalletTransactionDO addWalletBalance(Long userId, Integer userType,
+                                                   Long bizId, PayWalletBizTypeEnum bizType, Integer price) {
+        // 1. 获取钱包
+        PayWalletDO payWallet = getOrCreateWallet(userId, userType);
+        switch (bizType) {
+            case PAYMENT_REFUND: {
+                // 更新退款
+                walletMapper.updateWhenConsumptionRefund(price, payWallet.getId());
+                break;
+            }
+            case RECHARGE: {
+                //TODO
+                break;
+            }
+        }
+
+        // 2. 生成钱包流水
+        CreateWalletTransactionBO bo = new CreateWalletTransactionBO().setWalletId(payWallet.getId())
+                .setPrice(price).setBalance(payWallet.getBalance()+price).setBizId(String.valueOf(bizId))
+                .setBizType(bizType.getType()).setTitle(bizType.getDescription());
+        return walletTransactionService.createWalletTransaction(bo);
+    }
+
 }

+ 7 - 3
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletTransactionService.java

@@ -4,6 +4,9 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.transaction.AppPayWalletTransactionPageReqVO;
 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO;
 import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum;
+import cn.iocoder.yudao.module.pay.service.wallet.bo.CreateWalletTransactionBO;
+
+import javax.validation.Valid;
 
 /**
  * 钱包余额流水 Service 接口
@@ -25,10 +28,10 @@ public interface PayWalletTransactionService {
     /**
      * 新增钱包余额流水
      *
-     * @param payWalletTransaction 余额流水
-     * @return id
+     * @param bo 创建钱包流水 bo
+     * @return 新建的钱包 do
      */
-    Long createWalletTransaction(PayWalletTransactionDO payWalletTransaction);
+    PayWalletTransactionDO createWalletTransaction(@Valid CreateWalletTransactionBO bo);
 
     /**
      * 根据 no,获取钱包余流水
@@ -45,4 +48,5 @@ public interface PayWalletTransactionService {
      * @return 钱包流水
      */
     PayWalletTransactionDO getWalletTransaction(String bizId, PayWalletBizTypeEnum type);
+    
 }

+ 17 - 4
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletTransactionServiceImpl.java

@@ -2,10 +2,13 @@ package cn.iocoder.yudao.module.pay.service.wallet;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.transaction.AppPayWalletTransactionPageReqVO;
+import cn.iocoder.yudao.module.pay.convert.wallet.PayWalletTransactionConvert;
 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO;
 import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO;
 import cn.iocoder.yudao.module.pay.dal.mysql.wallet.PayWalletTransactionMapper;
+import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO;
 import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum;
+import cn.iocoder.yudao.module.pay.service.wallet.bo.CreateWalletTransactionBO;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 
@@ -20,22 +23,31 @@ import javax.annotation.Resource;
 @Slf4j
 public class PayWalletTransactionServiceImpl implements PayWalletTransactionService {
 
+    /**
+     * 钱包流水的 no 前缀
+     */
+    private static final String WALLET_NO_PREFIX = "W";
+
     @Resource
     private PayWalletService payWalletService;
     @Resource
     private PayWalletTransactionMapper payWalletTransactionMapper;
+    @Resource
+    private PayNoRedisDAO noRedisDAO;
 
     @Override
     public PageResult<PayWalletTransactionDO> getWalletTransactionPage(Long userId, Integer userType,
                                                                        AppPayWalletTransactionPageReqVO pageVO) {
-        PayWalletDO wallet = payWalletService.getOrCreatePayWallet(userId, userType);
+        PayWalletDO wallet = payWalletService.getOrCreateWallet(userId, userType);
         return payWalletTransactionMapper.selectPage(wallet.getId(), pageVO);
     }
 
     @Override
-    public Long createWalletTransaction(PayWalletTransactionDO payWalletTransaction) {
-         payWalletTransactionMapper.insert(payWalletTransaction);
-         return payWalletTransaction.getId();
+    public PayWalletTransactionDO createWalletTransaction(CreateWalletTransactionBO bo) {
+        PayWalletTransactionDO transaction = PayWalletTransactionConvert.INSTANCE.convert(bo)
+                .setNo(noRedisDAO.generate(WALLET_NO_PREFIX));
+        payWalletTransactionMapper.insert(transaction);
+        return transaction;
     }
 
     @Override
@@ -47,4 +59,5 @@ public class PayWalletTransactionServiceImpl implements PayWalletTransactionServ
     public PayWalletTransactionDO getWalletTransaction(String bizId, PayWalletBizTypeEnum type) {
         return payWalletTransactionMapper.selectByBiz(bizId, type.getType());
     }
+
 }

+ 50 - 0
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/bo/CreateWalletTransactionBO.java

@@ -0,0 +1,50 @@
+package cn.iocoder.yudao.module.pay.service.wallet.bo;
+
+import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum;
+import lombok.Data;
+
+/**
+ * 创建钱包流水 BO
+ *
+ * @author jason
+ */
+@Data
+public class CreateWalletTransactionBO {
+
+    // TODO @jason:bo 的话,最好加个参数校验哈;
+
+    /**
+     * 钱包编号
+     *
+     */
+    private Long walletId;
+
+    /**
+     * 交易金额,单位分
+     *
+     * 正值表示余额增加,负值表示余额减少
+     */
+    private Integer price;
+
+    /**
+     * 交易后余额,单位分
+     */
+    private Integer balance;
+
+    /**
+     * 关联业务分类
+     *
+     * 枚举 {@link PayWalletBizTypeEnum#getType()}
+     */
+    private Integer bizType;
+
+    /**
+     * 关联业务编号
+     */
+    private String bizId;
+
+    /**
+     * 流水说明
+     */
+    private String title;
+}

+ 8 - 5
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialUserApi.java

@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.api.social;
 
 import cn.iocoder.yudao.framework.common.exception.ServiceException;
 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
+import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO;
 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserUnbindReqDTO;
 import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
 
@@ -27,8 +28,9 @@ public interface SocialUserApi {
      * 绑定社交用户
      *
      * @param reqDTO 绑定信息
+     * @return 社交用户 openid
      */
-    void bindSocialUser(@Valid SocialUserBindReqDTO reqDTO);
+    String bindSocialUser(@Valid SocialUserBindReqDTO reqDTO);
 
     /**
      * 取消绑定社交用户
@@ -38,16 +40,17 @@ public interface SocialUserApi {
     void unbindSocialUser(@Valid SocialUserUnbindReqDTO reqDTO);
 
     /**
-     * 获得社交用户的绑定用户编号
-     * 注意,返回的是 MemberUser 或者 AdminUser 的 id 编号!
+     * 获得社交用户
+     *
      * 在认证信息不正确的情况下,也会抛出 {@link ServiceException} 业务异常
      *
      * @param userType 用户类型
      * @param type 社交平台的类型
      * @param code 授权码
      * @param state state
-     * @return 绑定用户编号
+     * @return 社交用户
      */
-    Long getBindUserId(Integer userType, Integer type, String code, String state);
+    SocialUserRespDTO getSocialUser(Integer userType, Integer type,
+                                    String code, String state);
 
 }

+ 27 - 0
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialUserRespDTO.java

@@ -0,0 +1,27 @@
+package cn.iocoder.yudao.module.system.api.social.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 社交用户 Response DTO
+ *
+ * @author 芋道源码
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class SocialUserRespDTO {
+
+    /**
+     * 社交用户 openid
+     */
+    private String openid;
+
+    /**
+     * 关联的用户编号
+     */
+    private Long userId;
+
+}

+ 5 - 4
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialUserApiImpl.java

@@ -1,6 +1,7 @@
 package cn.iocoder.yudao.module.system.api.social;
 
 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
+import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO;
 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserUnbindReqDTO;
 import cn.iocoder.yudao.module.system.service.social.SocialUserService;
 import org.springframework.stereotype.Service;
@@ -26,8 +27,8 @@ public class SocialUserApiImpl implements SocialUserApi {
     }
 
     @Override
-    public void bindSocialUser(SocialUserBindReqDTO reqDTO) {
-        socialUserService.bindSocialUser(reqDTO);
+    public String bindSocialUser(SocialUserBindReqDTO reqDTO) {
+        return socialUserService.bindSocialUser(reqDTO);
     }
 
     @Override
@@ -37,8 +38,8 @@ public class SocialUserApiImpl implements SocialUserApi {
     }
 
     @Override
-    public Long getBindUserId(Integer userType, Integer type, String code, String state) {
-       return socialUserService.getBindUserId(userType, type, code, state);
+    public SocialUserRespDTO getSocialUser(Integer userType, Integer type, String code, String state) {
+       return socialUserService.getSocialUser(userType, type, code, state);
     }
 
 }

+ 4 - 3
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java

@@ -9,6 +9,7 @@ import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
 import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO;
 import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
+import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO;
 import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*;
 import cn.iocoder.yudao.module.system.convert.auth.AuthConvert;
 import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
@@ -155,14 +156,14 @@ public class AdminAuthServiceImpl implements AdminAuthService {
     @Override
     public AuthLoginRespVO socialLogin(AuthSocialLoginReqVO reqVO) {
         // 使用 code 授权码,进行登录。然后,获得到绑定的用户编号
-        Long userId = socialUserService.getBindUserId(UserTypeEnum.ADMIN.getValue(), reqVO.getType(),
+        SocialUserRespDTO socialUser = socialUserService.getSocialUser(UserTypeEnum.ADMIN.getValue(), reqVO.getType(),
                 reqVO.getCode(), reqVO.getState());
-        if (userId == null) {
+        if (socialUser == null) {
             throw exception(AUTH_THIRD_LOGIN_NOT_BIND);
         }
 
         // 获得用户
-        AdminUserDO user = userService.getUser(userId);
+        AdminUserDO user = userService.getUser(socialUser.getUserId());
         if (user == null) {
             throw exception(USER_NOT_EXISTS);
         }

+ 8 - 5
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialUserService.java

@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.service.social;
 
 import cn.iocoder.yudao.framework.common.exception.ServiceException;
 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
+import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO;
 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO;
 import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
 
@@ -50,8 +51,9 @@ public interface SocialUserService {
      * 绑定社交用户
      *
      * @param reqDTO 绑定信息
+     * @return 社交用户 openid
      */
-    void bindSocialUser(@Valid SocialUserBindReqDTO reqDTO);
+    String bindSocialUser(@Valid SocialUserBindReqDTO reqDTO);
 
     /**
      * 取消绑定社交用户
@@ -64,15 +66,16 @@ public interface SocialUserService {
     void unbindSocialUser(Long userId, Integer userType, Integer type, String openid);
 
     /**
-     * 获得社交用户的绑定用户编号
-     * 注意,返回的是 MemberUser 或者 AdminUser 的 id 编号!
+     * 获得社交用户
+     *
      * 在认证信息不正确的情况下,也会抛出 {@link ServiceException} 业务异常
      *
      * @param userType 用户类型
      * @param type 社交平台的类型
      * @param code 授权码
      * @param state state
-     * @return 绑定用户编号
+     * @return 社交用户
      */
-    Long getBindUserId(Integer userType, Integer type, String code, String state);
+    SocialUserRespDTO getSocialUser(Integer userType, Integer type, String code, String state);
+
 }

+ 5 - 3
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialUserServiceImpl.java

@@ -5,6 +5,7 @@ import cn.hutool.core.lang.Assert;
 import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
 import cn.iocoder.yudao.framework.social.core.YudaoAuthRequestFactory;
 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
+import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO;
 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserBindDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO;
 import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserBindMapper;
@@ -98,7 +99,7 @@ public class SocialUserServiceImpl implements SocialUserService {
 
     @Override
     @Transactional
-    public void bindSocialUser(SocialUserBindReqDTO reqDTO) {
+    public String bindSocialUser(SocialUserBindReqDTO reqDTO) {
         // 获得社交用户
         SocialUserDO socialUser = authSocialUser(reqDTO.getType(), reqDTO.getCode(), reqDTO.getState());
         Assert.notNull(socialUser, "社交用户不能为空");
@@ -115,6 +116,7 @@ public class SocialUserServiceImpl implements SocialUserService {
                 .userId(reqDTO.getUserId()).userType(reqDTO.getUserType())
                 .socialUserId(socialUser.getId()).socialType(socialUser.getType()).build();
         socialUserBindMapper.insert(socialUserBind);
+        return socialUser.getOpenid();
     }
 
     @Override
@@ -130,7 +132,7 @@ public class SocialUserServiceImpl implements SocialUserService {
     }
 
     @Override
-    public Long getBindUserId(Integer userType, Integer type, String code, String state) {
+    public SocialUserRespDTO getSocialUser(Integer userType, Integer type, String code, String state) {
         // 获得社交用户
         SocialUserDO socialUser = authSocialUser(type, code, state);
         Assert.notNull(socialUser, "社交用户不能为空");
@@ -141,7 +143,7 @@ public class SocialUserServiceImpl implements SocialUserService {
         if (socialUserBind == null) {
             throw exception(AUTH_THIRD_LOGIN_NOT_BIND);
         }
-        return socialUserBind.getUserId();
+        return new SocialUserRespDTO(socialUser.getOpenid(), socialUserBind.getUserId());
     }
 
     /**

+ 3 - 2
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImplTest.java

@@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
 import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
+import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO;
 import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*;
 import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
@@ -235,8 +236,8 @@ public class AdminAuthServiceImplTest extends BaseDbUnitTest {
         AuthSocialLoginReqVO reqVO = randomPojo(AuthSocialLoginReqVO.class);
         // mock 方法(绑定的用户编号)
         Long userId = 1L;
-        when(socialUserService.getBindUserId(eq(UserTypeEnum.ADMIN.getValue()), eq(reqVO.getType()),
-                eq(reqVO.getCode()), eq(reqVO.getState()))).thenReturn(userId);
+        when(socialUserService.getSocialUser(eq(UserTypeEnum.ADMIN.getValue()), eq(reqVO.getType()),
+                eq(reqVO.getCode()), eq(reqVO.getState()))).thenReturn(new SocialUserRespDTO(randomString(), userId));
         // mock(用户)
         AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setId(userId));
         when(userService.getUser(eq(userId))).thenReturn(user);

+ 10 - 7
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/social/SocialUserServiceImplTest.java

@@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
 import cn.iocoder.yudao.framework.social.core.YudaoAuthRequestFactory;
 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
+import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO;
 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserBindDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO;
 import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserBindMapper;
@@ -195,10 +196,11 @@ public class SocialUserServiceImplTest extends BaseDbUnitTest {
                 .setSocialType(SocialTypeEnum.GITEE.getType()).setSocialUserId(socialUser.getId()));
 
         // 调用
-        socialUserService.bindSocialUser(reqDTO);
+        String openid = socialUserService.bindSocialUser(reqDTO);
         // 断言
         List<SocialUserBindDO> socialUserBinds = socialUserBindMapper.selectList();
         assertEquals(1, socialUserBinds.size());
+        assertEquals(socialUser.getOpenid(), openid);
     }
 
     @Test
@@ -232,25 +234,26 @@ public class SocialUserServiceImplTest extends BaseDbUnitTest {
     }
 
     @Test
-    public void testGetBindUserId() {
+    public void testGetSocialUser() {
         // 准备参数
         Integer userType = UserTypeEnum.ADMIN.getValue();
         Integer type = SocialTypeEnum.GITEE.getType();
         String code = "tudou";
         String state = "yuanma";
         // mock 社交用户
-        SocialUserDO socialUser = randomPojo(SocialUserDO.class).setType(type).setCode(code).setState(state);
-        socialUserMapper.insert(socialUser);
+        SocialUserDO socialUserDO = randomPojo(SocialUserDO.class).setType(type).setCode(code).setState(state);
+        socialUserMapper.insert(socialUserDO);
         // mock 社交用户的绑定
         Long userId = randomLong();
         SocialUserBindDO socialUserBind = randomPojo(SocialUserBindDO.class).setUserType(userType).setUserId(userId)
-                .setSocialType(type).setSocialUserId(socialUser.getId());
+                .setSocialType(type).setSocialUserId(socialUserDO.getId());
         socialUserBindMapper.insert(socialUserBind);
 
         // 调用
-        Long result = socialUserService.getBindUserId(userType, type, code, state);
+        SocialUserRespDTO socialUser = socialUserService.getSocialUser(userType, type, code, state);
         // 断言
-        assertEquals(userId, result);
+        assertEquals(userId, socialUser.getUserId());
+        assertEquals(socialUserDO.getOpenid(), socialUser.getOpenid());
     }
 
 }

+ 4 - 2
yudao-server/src/main/resources/application-local.yaml

@@ -173,8 +173,10 @@ wx:
       key-prefix: wx # Redis Key 的前缀
       http-client-type: HttpClient # 采用 HttpClient 请求微信公众号平台
   miniapp: # 小程序配置(必填),参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-miniapp-spring-boot-starter/README.md 文档
-    appid: wx62056c0d5e8db250
-    secret: 333ae72f41552af1e998fe1f54e1584a
+#    appid: wx62056c0d5e8db250
+#    secret: 333ae72f41552af1e998fe1f54e1584a
+    appid: wx63c280fe3248a3e7 # wenhualian的接口测试号
+    secret: 6f270509224a7ae1296bbf1c8cb97aed
     config-storage:
       type: RedisTemplate # 采用 RedisTemplate 操作 Redis,会自动从 Spring 中获取
       key-prefix: wa # Redis Key 的前缀