Browse Source

【代码优化】商城:价格计算相关逻辑

YunaiV 10 months ago
parent
commit
fee7267799
42 changed files with 269 additions and 844 deletions
  1. 0 45
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.java
  2. 0 3
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuDetailRespVO.java
  3. 0 3
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuRespVO.java
  4. 4 2
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/discount/dto/DiscountProductRespDTO.java
  5. 1 9
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/reward/RewardActivityApi.java
  6. 0 2
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
  7. 5 3
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/discount/DiscountActivityApiImpl.java
  8. 2 9
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/reward/RewardActivityApiImpl.java
  9. 5 61
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateBaseVO.java
  10. 12 37
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/activity/AppActivityController.java
  11. 6 6
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/reward/vo/AppRewardActivityRespVO.java
  12. 0 2
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponConvert.java
  13. 0 4
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/discount/DiscountActivityConvert.java
  14. 0 33
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/reward/RewardActivityConvert.java
  15. 7 1
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/discount/DiscountProductDO.java
  16. 0 9
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponMapper.java
  17. 1 1
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponTemplateMapper.java
  18. 11 10
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/discount/DiscountProductMapper.java
  19. 2 30
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/reward/RewardActivityMapper.java
  20. 0 4
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillconfig/SeckillConfigMapper.java
  21. 1 1
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java
  22. 1 6
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java
  23. 1 2
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityService.java
  24. 10 16
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityServiceImpl.java
  25. 3 10
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityService.java
  26. 10 29
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityServiceImpl.java
  27. 8 6
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java
  28. 0 25
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/util/PromotionUtils.java
  29. 0 26
      yudao-module-mall/yudao-module-promotion-biz/src/main/resources/mapper/discount/DiscountProductMapper.xml
  30. 86 94
      yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityServiceImplTest.java
  31. 1 3
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java
  32. 3 2
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/aftersale/AfterSaleConvert.java
  33. 2 3
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/AfterSaleServiceImpl.java
  34. 1 2
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateRespBO.java
  35. 4 6
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculator.java
  36. 61 104
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDiscountActivityPriceCalculator.java
  37. 0 93
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeMemberLevelPriceCalculator.java
  38. 0 2
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculator.java
  39. 10 9
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeRewardActivityPriceCalculator.java
  40. 0 118
      yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeMemberLevelPriceCalculatorTest.java
  41. 0 2
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java
  42. 11 11
      yudao-server/src/main/resources/application-local.yaml

+ 0 - 45
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.java

@@ -4,10 +4,6 @@ import cn.hutool.core.collection.CollUtil;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-import cn.iocoder.yudao.module.member.api.level.MemberLevelApi;
-import cn.iocoder.yudao.module.member.api.level.dto.MemberLevelRespDTO;
-import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
-import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
 import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuDetailRespVO;
 import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO;
 import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuRespVO;
@@ -51,11 +47,6 @@ public class AppProductSpuController {
     @Resource
     private ProductBrowseHistoryService productBrowseHistoryService;
 
-    @Resource
-    private MemberLevelApi memberLevelApi;
-    @Resource
-    private MemberUserApi memberUserApi;
-
     @GetMapping("/list-by-ids")
     @Operation(summary = "获得商品 SPU 列表")
     @Parameter(name = "ids", description = "编号列表", required = true)
@@ -68,9 +59,6 @@ public class AppProductSpuController {
         // 拼接返回
         list.forEach(spu -> spu.setSalesCount(spu.getSalesCount() + spu.getVirtualSalesCount()));
         List<AppProductSpuRespVO> voList = BeanUtils.toBean(list, AppProductSpuRespVO.class);
-        // 处理 vip 价格
-//        MemberLevelRespDTO memberLevel = getMemberLevel();
-//        voList.forEach(vo -> vo.setVipPrice(calculateVipPrice(vo.getPrice(), memberLevel)));
         return success(voList);
     }
 
@@ -85,9 +73,6 @@ public class AppProductSpuController {
         // 拼接返回
         pageResult.getList().forEach(spu -> spu.setSalesCount(spu.getSalesCount() + spu.getVirtualSalesCount()));
         PageResult<AppProductSpuRespVO> voPageResult = BeanUtils.toBean(pageResult, AppProductSpuRespVO.class);
-        // 处理 vip 价格
-//        MemberLevelRespDTO memberLevel = getMemberLevel();
-//        voPageResult.getList().forEach(vo -> vo.setVipPrice(calculateVipPrice(vo.getPrice(), memberLevel)));
         return success(voPageResult);
     }
 
@@ -115,37 +100,7 @@ public class AppProductSpuController {
         spu.setSalesCount(spu.getSalesCount() + spu.getVirtualSalesCount());
         AppProductSpuDetailRespVO spuVO = BeanUtils.toBean(spu, AppProductSpuDetailRespVO.class)
                 .setSkus(BeanUtils.toBean(skus, AppProductSpuDetailRespVO.Sku.class));
-        // 处理 vip 价格
-        MemberLevelRespDTO memberLevel = getMemberLevel();
-        spuVO.setVipPrice(calculateVipPrice(spuVO.getPrice(), memberLevel));
         return success(spuVO);
     }
 
-    private MemberLevelRespDTO getMemberLevel() {
-        Long userId = getLoginUserId();
-        if (userId == null) {
-            return null;
-        }
-        MemberUserRespDTO user = memberUserApi.getUser(userId);
-        if (user.getLevelId() == null || user.getLevelId() <= 0) {
-            return null;
-        }
-        return memberLevelApi.getMemberLevel(user.getLevelId());
-    }
-
-    /**
-     * 计算会员 VIP 优惠价格
-     *
-     * @param price 原价
-     * @param memberLevel 会员等级
-     * @return 优惠价格
-     */
-    public Integer calculateVipPrice(Integer price, MemberLevelRespDTO memberLevel) {
-        if (memberLevel == null || memberLevel.getDiscountPercent() == null) {
-            return null;
-        }
-        Integer newPrice = price * memberLevel.getDiscountPercent() / 100;
-        return price - newPrice;
-    }
-
 }

+ 0 - 3
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuDetailRespVO.java

@@ -46,9 +46,6 @@ public class AppProductSpuDetailRespVO {
     @Schema(description = "市场价,单位使用:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
     private Integer marketPrice;
 
-    @Schema(description = "VIP 价格,单位使用:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "968") // 通过会员等级,计算出折扣后价格
-    private Integer vipPrice;
-
     @Schema(description = "库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "666")
     private Integer stock;
 

+ 0 - 3
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuRespVO.java

@@ -38,9 +38,6 @@ public class AppProductSpuRespVO {
     @Schema(description = "市场价,单位使用:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
     private Integer marketPrice;
 
-//    @Schema(description = "VIP 价格,单位使用:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "968") // 通过会员等级,计算出折扣后价格
-//    private Integer vipPrice;
-
     @Schema(description = "库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "666")
     private Integer stock;
 

+ 4 - 2
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/discount/dto/DiscountProductRespDTO.java

@@ -46,10 +46,12 @@ public class DiscountProductRespDTO {
      * 活动标题
      */
     private String activityName;
+    /**
+     * 活动开始时间点
+     */
+    private LocalDateTime activityStartTime;
     /**
      * 活动结束时间点
-     *
-     * 冗余 {@link DiscountActivityDO#getEndTime()}
      */
     private LocalDateTime activityEndTime;
 

+ 1 - 9
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/reward/RewardActivityApi.java

@@ -13,15 +13,6 @@ import java.util.List;
  */
 public interface RewardActivityApi {
 
-    /**
-     * 获得当前时间内开启的满减送活动
-     *
-     * @param status   状态
-     * @param dateTime 当前时间,即筛选 <= dateTime 的满减送活动
-     * @return 满减送活动列表
-     */
-    List<RewardActivityMatchRespDTO> getRewardActivityListByStatusAndNow(Integer status, LocalDateTime dateTime);
-
     /**
      * 获取指定 spu 编号最近参加的活动,每个 spuId 只返回一条记录
      *
@@ -31,4 +22,5 @@ public interface RewardActivityApi {
      * @return 满减送活动列表
      */
     List<RewardActivityMatchRespDTO> getRewardActivityBySpuIdsAndStatusAndDateTimeLt(Collection<Long> spuIds, Integer status, LocalDateTime dateTime);
+
 }

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

@@ -15,7 +15,6 @@ public interface ErrorCodeConstants {
     ErrorCode DISCOUNT_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_001_002, "限时折扣活动已关闭,不能修改");
     ErrorCode DISCOUNT_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED = new ErrorCode(1_013_001_003, "限时折扣活动未关闭,不能删除");
     ErrorCode DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_001_004, "限时折扣活动已关闭,不能重复关闭");
-    ErrorCode DISCOUNT_ACTIVITY_TYPE_NOT_EXISTS = new ErrorCode(1_013_001_005, "限时折扣活动类型不存在");
 
     // ========== Banner 相关 1-013-002-000 ============
     ErrorCode BANNER_NOT_EXISTS = new ErrorCode(1_013_002_000, "Banner 不存在");
@@ -44,7 +43,6 @@ public interface ErrorCodeConstants {
     ErrorCode REWARD_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED = new ErrorCode(1_013_006_003, "满减送活动未关闭,不能删除");
     ErrorCode REWARD_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_006_004, "满减送活动已关闭,不能重复关闭");
     ErrorCode REWARD_ACTIVITY_SCOPE_EXISTS = new ErrorCode(1_013_006_005, "与该时间段已存在的满减送活动商品范围冲突");
-    ErrorCode REWARD_ACTIVITY_TYPE_NOT_EXISTS = new ErrorCode(1_013_006_006, "满减送活动类型不存在");
 
     // ========== TODO 空着 1-013-007-000 ============
 

+ 5 - 3
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/discount/DiscountActivityApiImpl.java

@@ -1,12 +1,13 @@
 package cn.iocoder.yudao.module.promotion.api.discount;
 
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO;
-import cn.iocoder.yudao.module.promotion.convert.discount.DiscountActivityConvert;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
 import cn.iocoder.yudao.module.promotion.service.discount.DiscountActivityService;
+import jakarta.annotation.Resource;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
-import jakarta.annotation.Resource;
 import java.util.Collection;
 import java.util.List;
 
@@ -24,7 +25,8 @@ public class DiscountActivityApiImpl implements DiscountActivityApi {
 
     @Override
     public List<DiscountProductRespDTO> getMatchDiscountProductList(Collection<Long> skuIds) {
-        return discountActivityService.getMatchDiscountProductList(skuIds);
+        List<DiscountProductDO> list = discountActivityService.getMatchDiscountProductList(skuIds);
+        return BeanUtils.toBean(list, DiscountProductRespDTO.class);
     }
 
 }

+ 2 - 9
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/reward/RewardActivityApiImpl.java

@@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.promotion.api.reward;
 
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO;
-import cn.iocoder.yudao.module.promotion.convert.reward.RewardActivityConvert;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO;
 import cn.iocoder.yudao.module.promotion.service.reward.RewardActivityService;
 import jakarta.annotation.Resource;
@@ -25,16 +24,10 @@ public class RewardActivityApiImpl implements RewardActivityApi {
     @Resource
     private RewardActivityService rewardActivityService;
 
-    @Override
-    public List<RewardActivityMatchRespDTO> getRewardActivityListByStatusAndNow(Integer status, LocalDateTime dateTime) {
-        List<RewardActivityDO> list = rewardActivityService.getRewardActivityListByStatusAndDateTimeLt(status, dateTime);
-        return BeanUtils.toBean(list, RewardActivityMatchRespDTO.class);
-    }
-
     @Override
     public List<RewardActivityMatchRespDTO> getRewardActivityBySpuIdsAndStatusAndDateTimeLt(Collection<Long> spuIds, Integer status, LocalDateTime dateTime) {
-        List<RewardActivityDO> rewardActivityBySpuIdsAndStatusAndDateTimeLt = rewardActivityService.getRewardActivityBySpuIdsAndStatusAndDateTimeLt(spuIds, status, dateTime);
-        return RewardActivityConvert.INSTANCE.convertList(rewardActivityBySpuIdsAndStatusAndDateTimeLt);
+        List<RewardActivityDO> list = rewardActivityService.getRewardActivityBySpuIdsAndStatusAndDateTimeLt(spuIds, status, dateTime);
+        return BeanUtils.toBean(list, RewardActivityMatchRespDTO.class);
     }
 
 }

+ 5 - 61
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateBaseVO.java

@@ -2,22 +2,19 @@ package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjectUtil;
-import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
 import cn.iocoder.yudao.framework.common.validation.InEnum;
 import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum;
 import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;
-import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum;
 import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTemplateValidityTypeEnum;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import org.springframework.format.annotation.DateTimeFormat;
-
-import jakarta.validation.Validator;
 import jakarta.validation.constraints.AssertTrue;
 import jakarta.validation.constraints.Min;
 import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
 import java.time.LocalDateTime;
 import java.util.List;
 import java.util.Objects;
@@ -40,11 +37,11 @@ public class CouponTemplateBaseVO {
     private String description;
 
     @Schema(description = "发行总量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") // -1 - 则表示不限制发放数量
-    @NotNull(message = "发行总量不能为空", groups = {User.class})
+    @NotNull(message = "发行总量不能为空")
     private Integer totalCount;
 
     @Schema(description = "每人限领个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "66") // -1 - 则表示不限制
-    @NotNull(message = "每人限领个数不能为空", groups = {User.class})
+    @NotNull(message = "每人限领个数不能为空")
     private Integer takeLimitCount;
 
     @Schema(description = "领取方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@@ -92,16 +89,13 @@ public class CouponTemplateBaseVO {
     private Integer discountType;
 
     @Schema(description = "折扣百分比", example = "80") //  例如说,80% 为 80
-    @NotNull(message = "折扣百分比不能为空", groups = {Percent.class})
     private Integer discountPercent;
 
     @Schema(description = "优惠金额", example = "10")
     @Min(value = 0, message = "优惠金额需要大于等于 0")
-    @NotNull(message = "优惠金额不能为空", groups = {Price.class})
     private Integer discountPrice;
 
     @Schema(description = "折扣上限", example = "100") // 单位:分,仅在 discountType 为 PERCENT 使用
-    @NotNull(message = "折扣上限不能为空", groups = {Percent.class})
     private Integer discountLimitPrice;
 
     @AssertTrue(message = "商品范围编号的数组不能为空")
@@ -160,54 +154,4 @@ public class CouponTemplateBaseVO {
                 || discountLimitPrice != null;
     }
 
-    //-------------------------领取方式校验start----------------------------
-
-    /**
-     * 直接领取
-     */
-    public interface User {
-    }
-
-    /**
-     * 指定发放
-     */
-    public interface Admin {
-    }
-
-    //-------------------------领取方式校验end------------------------------
-
-    //-------------------------优惠类型校验start----------------------------
-
-    /**
-     * 满减
-     */
-    public interface Price {
-    }
-
-    /**
-     * 折扣
-     */
-    public interface Percent {
-    }
-
-    //-------------------------优惠类型校验end------------------------------
-
-    public void validate(Validator validator) {
-
-        //领取方式校验
-        if (CouponTakeTypeEnum.USER.getType().equals(takeType)) {
-            ValidationUtils.validate(validator, this, User.class);
-        } else if (CouponTakeTypeEnum.ADMIN.getType().equals(takeType)) {
-            ValidationUtils.validate(validator, this, Admin.class);
-        }
-
-        //优惠类型校验
-        if (PromotionDiscountTypeEnum.PRICE.getType().equals(discountType)){
-            ValidationUtils.validate(validator, this, Price.class);
-        } else if (PromotionDiscountTypeEnum.PERCENT.getType().equals(discountType)) {
-            ValidationUtils.validate(validator, this, Percent.class);
-        }
-
-    }
-
 }

+ 12 - 37
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/activity/AppActivityController.java

@@ -2,11 +2,9 @@ package cn.iocoder.yudao.module.promotion.controller.app.activity;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.map.MapUtil;
-import cn.hutool.core.util.ObjUtil;
 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
-import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
 import cn.iocoder.yudao.module.promotion.controller.app.activity.vo.AppActivityRespVO;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
@@ -151,46 +149,23 @@ public class AppActivityController {
     }
 
     private void getRewardActivityList(Collection<Long> spuIds, LocalDateTime now, List<AppActivityRespVO> activityList) {
-        // TODO @puhui999:有 3 范围,不只 spuId,还有 categoryId,全部,下次 fix
-        List<RewardActivityDO> rewardActivityList = rewardActivityService.getRewardActivityBySpuIdsAndStatusAndDateTimeLt(
+        List<RewardActivityDO> rewardActivities = rewardActivityService.getRewardActivityBySpuIdsAndStatusAndDateTimeLt(
                 spuIds, CommonStatusEnum.ENABLE.getStatus(), now);
-        if (CollUtil.isEmpty(rewardActivityList)) {
+        if (CollUtil.isEmpty(rewardActivities)) {
             return;
         }
 
-        Map<Long, Optional<RewardActivityDO>> spuIdAndActivityMap = spuIds.stream()
-                .collect(Collectors.toMap(
-                        spuId -> spuId,
-                        spuId -> rewardActivityList.stream()
-                                .filter(activity ->
-                                        ( activity.getProductScopeValues()!=null &&
-                                                (activity.getProductScopeValues().contains(spuId) ||
-                                                        activity.getProductScopeValues().contains(productSpuApi.getSpu(spuId).getCategoryId()))) ||
-                                                activity.getProductScope()==1
-                                )
-                                .max(Comparator.comparing(RewardActivityDO::getCreateTime))));
+        Map<Long, Optional<RewardActivityDO>> spuIdAndActivityMap = spuIds.stream().collect(Collectors.toMap(spuId -> spuId, spuId -> rewardActivities.stream()
+                .filter(activity -> PromotionProductScopeEnum.isAll(activity.getProductScope())
+                                || PromotionProductScopeEnum.isSpu(activity.getProductScope()) // 商品范围
+                                    && CollUtil.contains(activity.getProductScopeValues(), spuId)
+                                || PromotionProductScopeEnum.isCategory(activity.getProductScope()) // 分类范围
+                                    && CollUtil.contains(activity.getProductScopeValues(), productSpuApi.getSpu(spuId).getCategoryId()))
+                .max(Comparator.comparing(RewardActivityDO::getCreateTime))));
         for (Long supId : spuIdAndActivityMap.keySet()) {
-            if (spuIdAndActivityMap.get(supId).isEmpty()) {
-                continue;
-            }
-
-            RewardActivityDO rewardActivityDO = spuIdAndActivityMap.get(supId).get();
-            activityList.add(new AppActivityRespVO(rewardActivityDO.getId(), PromotionTypeEnum.REWARD_ACTIVITY.getType(),
-                    rewardActivityDO.getName(), supId, rewardActivityDO.getStartTime(), rewardActivityDO.getEndTime()));
-        }
-    }
-
-    private static void buildAppActivityRespVO(RewardActivityDO rewardActivity, Collection<Long> spuIds,
-                                               List<AppActivityRespVO> activityList) {
-        for (Long spuId : spuIds) {
-            // 校验商品是否已经加入过活动
-            if (anyMatch(activityList, appActivity -> ObjUtil.equal(appActivity.getId(), rewardActivity.getId()) &&
-                    ObjUtil.equal(appActivity.getSpuId(), spuId))) {
-                continue;
-            }
-            activityList.add(new AppActivityRespVO(rewardActivity.getId(),
-                    PromotionTypeEnum.REWARD_ACTIVITY.getType(), rewardActivity.getName(), spuId,
-                    rewardActivity.getStartTime(), rewardActivity.getEndTime()));
+            spuIdAndActivityMap.get(supId).ifPresent(rewardActivity -> activityList.add(
+                    new AppActivityRespVO(rewardActivity.getId(), PromotionTypeEnum.REWARD_ACTIVITY.getType(),
+                            rewardActivity.getName(), supId, rewardActivity.getStartTime(), rewardActivity.getEndTime())));
         }
     }
 

+ 6 - 6
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/reward/vo/AppRewardActivityRespVO.java

@@ -20,6 +20,12 @@ public class AppRewardActivityRespVO {
     @Schema(description = "活动标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "满啦满啦")
     private String name;
 
+    @Schema(description = "开始时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    private LocalDateTime startTime;
+
+    @Schema(description = "结束时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    private LocalDateTime endTime;
+
     @Schema(description = "条件类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
     private Integer conditionType;
 
@@ -32,10 +38,4 @@ public class AppRewardActivityRespVO {
     @Schema(description = "优惠规则的数组")
     private List<RewardActivityBaseVO.Rule> rules;
 
-    @Schema(description = "开始时间")
-    private LocalDateTime startTime;
-
-    @Schema(description = "结束时间")
-    private LocalDateTime endTime;
-
 }

+ 0 - 2
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponConvert.java

@@ -29,8 +29,6 @@ public interface CouponConvert {
 
     CouponRespDTO convert(CouponDO bean);
 
-    AppCouponMatchRespVO convert2(CouponDO bean);
-
     default CouponDO convert(CouponTemplateDO template, Long userId) {
         CouponDO couponDO = new CouponDO()
                 .setTemplateId(template.getId())

+ 0 - 4
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/discount/DiscountActivityConvert.java

@@ -5,7 +5,6 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
-import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO;
 import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.*;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
@@ -34,9 +33,6 @@ public interface DiscountActivityConvert {
 
     List<DiscountActivityRespVO> convertList(List<DiscountActivityDO> list);
     List<DiscountActivityBaseVO.Product> convertList2(List<DiscountProductDO> list);
-
-    List<DiscountProductRespDTO> convertList02(List<DiscountProductDO> list);
-
     PageResult<DiscountActivityRespVO> convertPage(PageResult<DiscountActivityDO> page);
 
     default PageResult<DiscountActivityRespVO> convertPage(PageResult<DiscountActivityDO> page,

+ 0 - 33
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/reward/RewardActivityConvert.java

@@ -1,33 +0,0 @@
-package cn.iocoder.yudao.module.promotion.convert.reward;
-
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO;
-import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityCreateReqVO;
-import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityRespVO;
-import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityUpdateReqVO;
-import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO;
-import org.mapstruct.Mapper;
-import org.mapstruct.factory.Mappers;
-
-import java.util.List;
-
-/**
- * 满减送活动 Convert
- *
- * @author 芋道源码
- */
-@Mapper
-public interface RewardActivityConvert {
-
-    RewardActivityConvert INSTANCE = Mappers.getMapper(RewardActivityConvert.class);
-
-    RewardActivityDO convert(RewardActivityCreateReqVO bean);
-
-    RewardActivityDO convert(RewardActivityUpdateReqVO bean);
-
-    RewardActivityRespVO convert(RewardActivityDO bean);
-
-    PageResult<RewardActivityRespVO> convertPage(PageResult<RewardActivityDO> page);
-
-    List<RewardActivityMatchRespDTO> convertList(List<RewardActivityDO> rewardActivityBySpuIdsAndStatusAndDateTimeLt);
-}

+ 7 - 1
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/discount/DiscountProductDO.java

@@ -66,10 +66,16 @@ public class DiscountProductDO extends BaseDO {
      */
     private Integer discountPrice;
 
+    /**
+     * 活动标题
+     *
+     * 冗余 {@link DiscountActivityDO#getName()}
+     */
+    private String activityName;
     /**
      * 活动状态
      *
-     * 关联 {@link DiscountActivityDO#getStatus()}
+     * 冗余 {@link DiscountActivityDO#getStatus()}
      */
     private Integer activityStatus;
     /**

+ 0 - 9
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponMapper.java

@@ -80,15 +80,6 @@ public interface CouponMapper extends BaseMapperX<CouponDO> {
         return convertMap(list, map -> MapUtil.getLong(map, templateIdAlias), map -> MapUtil.getInt(map, countAlias));
     }
 
-    default List<CouponDO> selectListByUserIdAndStatusAndUsePriceLeAndProductScope(
-            Long userId, Integer status) {
-        List<CouponDO> couponDOS = selectList(new LambdaQueryWrapperX<CouponDO>()
-                .eq(CouponDO::getUserId, userId)
-                .eq(CouponDO::getStatus, status)
-        );
-        return couponDOS;
-    }
-
     default List<CouponDO> selectListByStatusAndValidEndTimeLe(Integer status, LocalDateTime validEndTime) {
         return selectList(new LambdaQueryWrapperX<CouponDO>()
                 .eq(CouponDO::getStatus, status)

+ 1 - 1
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponTemplateMapper.java

@@ -70,7 +70,7 @@ public interface CouponTemplateMapper extends BaseMapperX<CouponTemplateDO> {
                             .in(CouponTemplateDO::getTakeType, canTakeTypes) // 2. 领取方式一致
                             .and(ww -> ww.gt(CouponTemplateDO::getValidEndTime, LocalDateTime.now())  // 3.1 未过期
                                     .or().eq(CouponTemplateDO::getValidityType, CouponTemplateValidityTypeEnum.TERM.getType())) // 3.2 领取之后
-                            .apply(" (take_count < total_count OR total_count = -1 or total_count is null)"); // 4. 剩余数量大于 0,或者无限领取,或者是指定发放的券
+                            .apply(" (take_count < total_count OR total_count = -1)"); // 4. 剩余数量大于 0,或者无限领取
         }
         return canTakeConsumer;
     }

+ 11 - 10
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/discount/DiscountProductMapper.java

@@ -1,12 +1,12 @@
 package cn.iocoder.yudao.module.promotion.dal.mysql.discount;
 
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
-import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import org.apache.ibatis.annotations.Mapper;
-import org.apache.ibatis.annotations.Param;
 
+import java.time.LocalDateTime;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
@@ -19,20 +19,21 @@ import java.util.Map;
 @Mapper
 public interface DiscountProductMapper extends BaseMapperX<DiscountProductDO> {
 
-    default List<DiscountProductDO> selectListBySkuId(Collection<Long> skuIds) {
-        return selectList(DiscountProductDO::getSkuId, skuIds);
-    }
-
     default List<DiscountProductDO> selectListByActivityId(Long activityId) {
         return selectList(DiscountProductDO::getActivityId, activityId);
     }
 
-    default List<DiscountProductDO> selectListByActivityId(Collection<Long> activityIds) {
-        return selectList(DiscountProductDO::getActivityId, activityIds);
+    default List<DiscountProductDO> selectListBySkuIds(Collection<Long> skuIds) {
+        return selectList(DiscountProductDO::getSkuId, skuIds);
     }
 
-    // TODO @zhangshuai:逻辑里,尽量避免写 join 语句哈,你可以看看这个查询,有什么办法优化?目前的一个思路,是分 2 次查询,性能也是 ok 的
-    List<DiscountProductRespDTO> getMatchDiscountProductList(@Param("skuIds") Collection<Long> skuIds);
+    default List<DiscountProductDO> selectListByStatusAndDateTimeLt(Collection<Long> skuIds, Integer status, LocalDateTime dateTime) {
+        return selectList(new LambdaQueryWrapperX<DiscountProductDO>()
+                .in(DiscountProductDO::getSkuId, skuIds)
+                .eq(DiscountProductDO::getActivityStatus,status)
+                .lt(DiscountProductDO::getActivityStartTime, dateTime)
+                .gt(DiscountProductDO::getActivityEndTime, dateTime));
+    }
 
     /**
      * 查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号

+ 2 - 30
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/reward/RewardActivityMapper.java

@@ -7,7 +7,6 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO;
 import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import org.apache.ibatis.annotations.Mapper;
 
 import java.time.LocalDateTime;
@@ -31,34 +30,7 @@ public interface RewardActivityMapper extends BaseMapperX<RewardActivityDO> {
                 .orderByDesc(RewardActivityDO::getId));
     }
 
-    default List<RewardActivityDO> selectListBySpuIdsAndStatus(Collection<Long> spuIds, Integer status) {
-        Function<Collection<Long>, String> productScopeValuesFindInSetFunc = ids -> ids.stream()
-                .map(id -> StrUtil.format("FIND_IN_SET({}, product_scope_values) ", id))
-                .collect(Collectors.joining(" OR "));
-        return selectList(new QueryWrapper<RewardActivityDO>()
-                .eq("status", status)
-                .apply(productScopeValuesFindInSetFunc.apply(spuIds)));
-    }
-
-    /**
-     * 获取指定活动编号的活动列表且
-     * 开始时间和结束时间小于给定时间 dateTime 的活动列表
-     *
-     * @param status   状态
-     * @param dateTime 指定日期
-     * @return 活动列表
-     */
-    default List<RewardActivityDO> selectListByStatusAndDateTimeLt(Integer status, LocalDateTime dateTime) {
-        return selectList(new LambdaQueryWrapperX<RewardActivityDO>()
-                .eq(RewardActivityDO::getStatus, status)
-                .lt(RewardActivityDO::getStartTime, dateTime)
-                .gt(RewardActivityDO::getEndTime, dateTime)// 开始时间 < 指定时间 < 结束时间,也就是说获取指定时间段的活动
-                .orderByAsc(RewardActivityDO::getStartTime)
-        );
-    }
-
-    default List<RewardActivityDO> getRewardActivityByStatusAndDateTimeLt(Collection<Long> spuIds,Collection<Long> categoryIds, Integer status, LocalDateTime dateTime) {
-        //拼接通用券查询语句
+    default List<RewardActivityDO> selectListByStatusAndDateTimeLt(Collection<Long> spuIds, Collection<Long> categoryIds, Integer status, LocalDateTime dateTime) {
         Function<Collection<Long>, String> productScopeValuesFindInSetFunc = ids -> ids.stream()
                 .map(id -> StrUtil.format("FIND_IN_SET({}, product_scope_values) ", id))
                 .collect(Collectors.joining(" OR "));
@@ -67,7 +39,7 @@ public interface RewardActivityMapper extends BaseMapperX<RewardActivityDO> {
                 .lt(RewardActivityDO::getStartTime, dateTime)
                 .gt(RewardActivityDO::getEndTime, dateTime)
                 .and(i -> i.eq(RewardActivityDO::getProductScope, PromotionProductScopeEnum.SPU.getScope())
-                        .and(i1 -> i1.apply(productScopeValuesFindInSetFunc.apply(spuIds)))
+                            .and(i1 -> i1.apply(productScopeValuesFindInSetFunc.apply(spuIds)))
                         .or(i1 -> i1.eq(RewardActivityDO::getProductScope, PromotionProductScopeEnum.ALL.getScope()))
                         .or(i1 -> i1.eq(RewardActivityDO::getProductScope, PromotionProductScopeEnum.CATEGORY.getScope())
                                 .and(i2 -> i2.apply(productScopeValuesFindInSetFunc.apply(categoryIds)))))

+ 0 - 4
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillconfig/SeckillConfigMapper.java

@@ -1,16 +1,12 @@
 package cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillconfig;
 
-import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigPageReqVO;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillConfigDO;
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import org.apache.ibatis.annotations.Mapper;
 
-import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
 import java.util.List;
 
 @Mapper

+ 1 - 1
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java

@@ -279,7 +279,7 @@ public class CouponServiceImpl implements CouponService {
             }
         }
         // 校验领取方式
-        if (ObjectUtil.notEqual(couponTemplate.getTakeType(), takeType.getValue())) {
+        if (ObjectUtil.notEqual(couponTemplate.getTakeType(), takeType.getType())) {
             throw exception(COUPON_TEMPLATE_CANNOT_TAKE);
         }
     }

+ 1 - 6
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java

@@ -12,11 +12,10 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO;
 import cn.iocoder.yudao.module.promotion.dal.mysql.coupon.CouponTemplateMapper;
 import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;
 import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum;
+import jakarta.annotation.Resource;
 import org.springframework.stereotype.Service;
-import jakarta.validation.Validator;
 import org.springframework.validation.annotation.Validated;
 
-import jakarta.annotation.Resource;
 import java.util.Collection;
 import java.util.List;
 import java.util.Objects;
@@ -41,13 +40,9 @@ public class CouponTemplateServiceImpl implements CouponTemplateService {
     private ProductCategoryApi productCategoryApi;
     @Resource
     private ProductSpuApi productSpuApi;
-    @Resource
-    private Validator validator;
 
     @Override
     public Long createCouponTemplate(CouponTemplateCreateReqVO createReqVO) {
-        // 校验参数
-        createReqVO.validate(validator);
         // 校验商品范围
         validateProductScope(createReqVO.getProductScope(), createReqVO.getProductScopeValues());
         // 插入

+ 1 - 2
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityService.java

@@ -1,7 +1,6 @@
 package cn.iocoder.yudao.module.promotion.service.discount;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO;
 import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityCreateReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityPageReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityUpdateReqVO;
@@ -28,7 +27,7 @@ public interface DiscountActivityService {
      * @param skuIds SKU 编号数组
      * @return 匹配的限时折扣商品
      */
-    List<DiscountProductRespDTO> getMatchDiscountProductList(Collection<Long> skuIds);
+    List<DiscountProductDO> getMatchDiscountProductList(Collection<Long> skuIds);
 
     /**
      * 创建限时折扣活动

+ 10 - 16
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityServiceImpl.java

@@ -6,7 +6,6 @@ import cn.hutool.core.map.MapUtil;
 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO;
 import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityBaseVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityCreateReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityPageReqVO;
@@ -16,8 +15,6 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivit
 import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
 import cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountActivityMapper;
 import cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountProductMapper;
-import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum;
-import cn.iocoder.yudao.module.promotion.util.PromotionUtils;
 import jakarta.annotation.Resource;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -28,7 +25,6 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
-import java.util.stream.Collectors;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
@@ -50,8 +46,8 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
     private DiscountProductMapper discountProductMapper;
 
     @Override
-    public List<DiscountProductRespDTO> getMatchDiscountProductList(Collection<Long> skuIds) {
-        return discountProductMapper.getMatchDiscountProductList(skuIds);
+    public List<DiscountProductDO> getMatchDiscountProductList(Collection<Long> skuIds) {
+        return discountProductMapper.selectListByStatusAndDateTimeLt(skuIds, CommonStatusEnum.ENABLE.getStatus(), LocalDateTime.now());
     }
 
     @Override
@@ -66,10 +62,10 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
         discountActivityMapper.insert(discountActivity);
         // 插入商品
         List<DiscountProductDO> discountProducts = BeanUtils.toBean(createReqVO.getProducts(), DiscountProductDO.class,
-                product -> product.setActivityId(discountActivity.getId()).setActivityStatus(discountActivity.getStatus())
+                product -> product.setActivityId(discountActivity.getId())
+                        .setActivityName(discountActivity.getName()).setActivityStatus(discountActivity.getStatus())
                         .setActivityStartTime(createReqVO.getStartTime()).setActivityEndTime(createReqVO.getEndTime()));
         discountProductMapper.insertBatch(discountProducts);
-        // 返回
         return discountActivity.getId();
     }
 
@@ -85,8 +81,7 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
         validateDiscountActivityProductConflicts(updateReqVO.getId(), updateReqVO.getProducts());
 
         // 更新活动
-        DiscountActivityDO updateObj = DiscountActivityConvert.INSTANCE.convert(updateReqVO)
-                .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getEndTime()));
+        DiscountActivityDO updateObj = DiscountActivityConvert.INSTANCE.convert(updateReqVO);
         discountActivityMapper.updateById(updateObj);
         // 更新商品
         updateDiscountProduct(updateReqVO);
@@ -101,12 +96,13 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
                 discountProductDO -> updateReqVO.getProducts().stream()
                         .noneMatch(product -> DiscountActivityConvert.INSTANCE.isEquals(discountProductDO, product)));
         if (CollUtil.isNotEmpty(deleteIds)) {
-            discountProductMapper.deleteBatchIds(deleteIds);
+            discountProductMapper.deleteByIds(deleteIds);
         }
         // 计算新增的记录
         List<DiscountProductDO> newDiscountProducts = convertList(updateReqVO.getProducts(),
                 product -> DiscountActivityConvert.INSTANCE.convert(product)
                         .setActivityId(updateReqVO.getId())
+                        .setActivityName(updateReqVO.getName())
                         .setActivityStartTime(updateReqVO.getStartTime())
                         .setActivityEndTime(updateReqVO.getEndTime()));
         newDiscountProducts.removeIf(product -> dbDiscountProducts.stream().anyMatch(
@@ -127,11 +123,9 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
             return;
         }
         // 查询商品参加的活动
-        // TODO @zhangshuai:下面 121 这个查询,是不是不用做呀;直接 convert 出 skuId 集合就 ok 啦;
         List<DiscountProductDO> list = discountProductMapper.selectListByActivityId(id);
-        // TODO @zhangshuai:一般简单的 stream 方法,建议是使用 CollectionUtils,例如说这里是 convertList 对把。
-        List<Long> skuIds = list.stream().map(item -> item.getSkuId()).collect(Collectors.toList());
-        List<DiscountProductRespDTO> matchDiscountProductList = getMatchDiscountProductList(skuIds);
+        List<DiscountProductDO> matchDiscountProductList = discountProductMapper.selectListBySkuIds(
+                convertSet(list, DiscountProductDO::getSkuId));
         if (id != null) { // 排除自己这个活动
             matchDiscountProductList.removeIf(product -> id.equals(product.getActivityId()));
         }
@@ -150,7 +144,7 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
         }
 
         // 更新
-        DiscountActivityDO updateObj = new DiscountActivityDO().setId(id).setStatus(PromotionActivityStatusEnum.CLOSE.getStatus());
+        DiscountActivityDO updateObj = new DiscountActivityDO().setId(id).setStatus(CommonStatusEnum.DISABLE.getStatus());
         discountActivityMapper.updateById(updateObj);
     }
 

+ 3 - 10
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityService.java

@@ -63,15 +63,6 @@ public interface RewardActivityService {
      */
     PageResult<RewardActivityDO> getRewardActivityPage(RewardActivityPageReqVO pageReqVO);
 
-    /**
-     * 开始时间 < 指定时间 < 结束时间,也就是说获取指定时间段的活动
-     *
-     * @param status   状态
-     * @param dateTime 当前日期时间
-     * @return 满减送活动列表
-     */
-    List<RewardActivityDO> getRewardActivityListByStatusAndDateTimeLt(Integer status, LocalDateTime dateTime);
-
     /**
      * 获取指定 spu 编号最近参加的活动,每个 spuId 只返回一条记录
      *
@@ -80,6 +71,8 @@ public interface RewardActivityService {
      * @param dateTime 当前日期时间
      * @return 满减送活动列表
      */
-    List<RewardActivityDO> getRewardActivityBySpuIdsAndStatusAndDateTimeLt(Collection<Long> spuIds, Integer status, LocalDateTime dateTime);
+    List<RewardActivityDO> getRewardActivityBySpuIdsAndStatusAndDateTimeLt(Collection<Long> spuIds,
+                                                                           Integer status,
+                                                                           LocalDateTime dateTime);
 
 }

+ 10 - 29
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityServiceImpl.java

@@ -12,22 +12,15 @@ import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivi
 import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityCreateReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityUpdateReqVO;
-import cn.iocoder.yudao.module.promotion.convert.reward.RewardActivityConvert;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO;
 import cn.iocoder.yudao.module.promotion.dal.mysql.reward.RewardActivityMapper;
-import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum;
 import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;
-import cn.iocoder.yudao.module.promotion.util.PromotionUtils;
 import jakarta.annotation.Resource;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
 import java.time.LocalDateTime;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-import java.util.stream.Collectors;
+import java.util.*;
 
 import static cn.hutool.core.collection.CollUtil.intersectionDistinct;
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@@ -59,12 +52,8 @@ public class RewardActivityServiceImpl implements RewardActivityService {
         validateRewardActivitySpuConflicts(null, createReqVO);
 
         // 插入
-        RewardActivityDO rewardActivity = RewardActivityConvert.INSTANCE.convert(createReqVO)
-                .setStatus(
-                        PromotionUtils.calculateActivityStatus(createReqVO.getEndTime()).equals(CommonStatusEnum.DISABLE.getStatus())?
-                                PromotionActivityStatusEnum.WAIT.getStatus():
-                                PromotionActivityStatusEnum.RUN.getStatus()
-                );
+        RewardActivityDO rewardActivity = BeanUtils.toBean(createReqVO, RewardActivityDO.class)
+                .setStatus(CommonStatusEnum.ENABLE.getStatus());
         rewardActivityMapper.insert(rewardActivity);
         // 返回
         return rewardActivity.getId();
@@ -83,8 +72,7 @@ public class RewardActivityServiceImpl implements RewardActivityService {
         validateRewardActivitySpuConflicts(updateReqVO.getId(), updateReqVO);
 
         // 2. 更新
-        RewardActivityDO updateObj = BeanUtils.toBean(updateReqVO, RewardActivityDO.class)
-                .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getEndTime()));
+        RewardActivityDO updateObj = BeanUtils.toBean(updateReqVO, RewardActivityDO.class);
         rewardActivityMapper.updateById(updateObj);
     }
 
@@ -204,24 +192,17 @@ public class RewardActivityServiceImpl implements RewardActivityService {
         return rewardActivityMapper.selectPage(pageReqVO);
     }
 
-    @Override
-    public List<RewardActivityDO> getRewardActivityListByStatusAndDateTimeLt(Integer status, LocalDateTime dateTime) {
-        return rewardActivityMapper.selectListByStatusAndDateTimeLt(status, dateTime);
-    }
-
     @Override
     public List<RewardActivityDO> getRewardActivityBySpuIdsAndStatusAndDateTimeLt(Collection<Long> spuIds, Integer status, LocalDateTime dateTime) {
-        List<ProductSpuRespDTO> spuList = productSpuApi.validateSpuList(spuIds);
-        //查询出商品的分类ids
-        List<Long> categoryIds = spuList.stream().map(ProductSpuRespDTO::getCategoryId).collect(Collectors.toList());
-        // 1. 查询出指定 spuId 的 spu 参加的活动
-        List<RewardActivityDO> rewardActivityList = rewardActivityMapper.getRewardActivityByStatusAndDateTimeLt(spuIds, categoryIds,status,dateTime);
-        if (CollUtil.isEmpty(rewardActivityList)) {
+        // 1. 查询商品分类
+        List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(spuIds);
+        if (CollUtil.isEmpty(spuList)) {
             return Collections.emptyList();
         }
+        Set<Long> categoryIds = convertSet(spuList, ProductSpuRespDTO::getCategoryId);
 
-        // 2. 查询活动详情
-        return rewardActivityList;
+        // 2. 查询出指定 spuId 的 spu 参加的活动
+        return rewardActivityMapper.selectListByStatusAndDateTimeLt(spuIds, categoryIds, status, dateTime);
     }
 
 }

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

@@ -23,12 +23,11 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillConfigDO;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO;
 import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity.SeckillActivityMapper;
 import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity.SeckillProductMapper;
-import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillconfig.SeckillConfigMapper;
+import jakarta.annotation.Resource;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
 
-import jakarta.annotation.Resource;
 import java.time.LocalDateTime;
 import java.util.Collection;
 import java.util.Collections;
@@ -58,8 +57,6 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
     @Resource
     private SeckillProductMapper seckillProductMapper;
     @Resource
-    private SeckillConfigMapper seckillConfigMapper;
-    @Resource
     private SeckillConfigService seckillConfigService;
     @Resource
     private ProductSpuApi productSpuApi;
@@ -279,7 +276,7 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
     }
 
     @Override
-    public List<SeckillProductDO> getSeckillProductListByActivityId(Collection<Long> activityIds) {
+    public List<SeckillProductDO> getSeckillProductListByActivityIds(Collection<Long> activityIds) {
         return seckillProductMapper.selectListByActivityId(activityIds);
     }
 
@@ -292,7 +289,7 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
 
     @Override
     public PageResult<SeckillActivityDO> getSeckillActivityAppPageByConfigId(AppSeckillActivityPageReqVO pageReqVO) {
-        return seckillActivityMapper.selectPage(pageReqVO, CommonStatusEnum.ENABLE.getStatus(),LocalDateTime.now());
+        return seckillActivityMapper.selectPage(pageReqVO, CommonStatusEnum.ENABLE.getStatus(), LocalDateTime.now());
     }
 
     @Override
@@ -339,4 +336,9 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
                 convertSet(spuIdAndActivityIdMaps, map -> MapUtil.getLong(map, "activityId")), dateTime);
     }
 
+    @Override
+    public List<SeckillActivityDO> getSeckillActivityListByIds(Collection<Long> ids) {
+        return List.of();
+    }
+
 }

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

@@ -1,25 +0,0 @@
-package cn.iocoder.yudao.module.promotion.util;
-
-import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
-import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
-
-import java.time.LocalDateTime;
-
-/**
- * 活动工具类
- *
- * @author 芋道源码
- */
-public class PromotionUtils {
-
-    /**
-     * 根据时间,计算活动状态
-     *
-     * @param endTime 结束时间
-     * @return 活动状态
-     */
-    public static Integer calculateActivityStatus(LocalDateTime endTime) {
-        return LocalDateTimeUtils.beforeNow(endTime) ? CommonStatusEnum.DISABLE.getStatus() : CommonStatusEnum.ENABLE.getStatus();
-    }
-
-}

+ 0 - 26
yudao-module-mall/yudao-module-promotion-biz/src/main/resources/mapper/discount/DiscountProductMapper.xml

@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountProductMapper">
-
-
-    <select id="getMatchDiscountProductList"   resultType="cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO">
-        SELECT pdp.*,pda.name as activity_name
-        FROM promotion_discount_product pdp
-        LEFT JOIN promotion_discount_activity pda
-        ON pdp.activity_id = pda.id
-        <where>
-            <if test="skuIds != null and skuIds.size > 0">
-                AND pdp.sku_id in
-                <foreach collection="skuIds" item="skuId" index="index" open="(" close=")" separator=",">
-                    #{skuId}
-                </foreach>
-            </if>
-            AND pda.start_time &lt;= CURRENT_TIME AND pda.end_time &gt;= CURRENT_TIME
-            AND pda.`status` = 0
-            AND pda.deleted =0
-            AND pdp.deleted = 0
-        </where>
-        ORDER BY pdp.id DESC
-    </select>
-
-</mapper>

+ 86 - 94
yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityServiceImplTest.java

@@ -18,15 +18,8 @@ import org.mockito.InjectMocks;
 import org.mockito.Mock;
 
 import java.time.Duration;
-import java.time.LocalDateTime;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
 
-import static cn.hutool.core.collection.CollUtil.intersectionDistinct;
 import static cn.hutool.core.util.RandomUtil.randomEle;
-import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet;
 import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime;
 import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
@@ -34,8 +27,6 @@ import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServic
 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.REWARD_ACTIVITY_NOT_EXISTS;
-import static com.google.common.primitives.Longs.asList;
-import static java.util.Collections.singletonList;
 import static org.junit.jupiter.api.Assertions.*;
 
 /**
@@ -176,90 +167,91 @@ public class RewardActivityServiceImplTest extends BaseMockitoUnitTest {
         assertPojoEquals(dbRewardActivity, pageResult.getList().get(0), "rules");
     }
 
-    @Test
-    public void testGetRewardActivities_all() {
-        LocalDateTime now = LocalDateTime.now();
-        // mock 数据
-        RewardActivityDO allActivity = randomPojo(RewardActivityDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())
-                .setProductScope(PromotionProductScopeEnum.ALL.getScope()).setStartTime(now.minusDays(1)).setEndTime(now.plusDays(1)));
-        rewardActivityMapper.insert(allActivity);
-        RewardActivityDO productActivity = randomPojo(RewardActivityDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())
-                .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductScopeValues(asList(1L, 2L))
-                .setStartTime(now.minusDays(1)).setEndTime(now.plusDays(1)));
-        rewardActivityMapper.insert(productActivity);
-        // 准备参数
-        Set<Long> spuIds = asSet(1L, 2L);
-
-        // 调用
-        List<RewardActivityDO> activityList = rewardActivityServiceImpl.getRewardActivityListByStatusAndDateTimeLt(
-                CommonStatusEnum.ENABLE.getStatus(), now);
-        List<RewardActivityDO> matchRewardActivityList = filterMatchActivity(spuIds, activityList);
-        // 断言
-        assertEquals(matchRewardActivityList.size(), 1);
-        matchRewardActivityList.forEach((activity) -> {
-            if (activity.getId().equals(productActivity.getId())) {
-                assertPojoEquals(activity, productActivity);
-                assertEquals(activity.getProductScopeValues(), asList(1L, 2L));
-            } else {
-                fail();
-            }
-        });
-    }
-
-    @Test
-    public void testGetRewardActivities_product() {
-        LocalDateTime now = LocalDateTime.now();
-        // mock 数据
-        RewardActivityDO productActivity01 = randomPojo(RewardActivityDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())
-                .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductScopeValues(asList(1L, 2L))
-                .setStartTime(now.minusDays(1)).setEndTime(now.plusDays(1)));
-        rewardActivityMapper.insert(productActivity01);
-        RewardActivityDO productActivity02 = randomPojo(RewardActivityDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())
-                .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductScopeValues(singletonList(3L))
-                .setStartTime(now.minusDays(1)).setEndTime(now.plusDays(1)));
-        rewardActivityMapper.insert(productActivity02);
-        // 准备参数
-        Set<Long> spuIds = asSet(1L, 2L, 3L);
-
-        List<RewardActivityDO> activityList = rewardActivityServiceImpl.getRewardActivityListByStatusAndDateTimeLt(
-                CommonStatusEnum.ENABLE.getStatus(), now);
-        List<RewardActivityDO> matchRewardActivityList = filterMatchActivity(spuIds, activityList);
-        // 断言
-        assertEquals(matchRewardActivityList.size(), 2);
-        matchRewardActivityList.forEach((activity) -> {
-            if (activity.getId().equals(productActivity01.getId())) {
-                assertPojoEquals(activity, productActivity01);
-                assertEquals(activity.getProductScopeValues(), asList(1L, 2L));
-            } else if (activity.getId().equals(productActivity02.getId())) {
-                assertPojoEquals(activity, productActivity02);
-                assertEquals(activity.getProductScopeValues(), singletonList(3L));
-            } else {
-                fail();
-            }
-        });
-    }
-
-    /**
-     * 获得满减送的订单项(商品)列表
-     *
-     * @param spuIds       商品编号
-     * @param activityList 活动列表
-     * @return 订单项(商品)列表
-     */
-    private List<RewardActivityDO> filterMatchActivity(Collection<Long> spuIds, List<RewardActivityDO> activityList) {
-        List<RewardActivityDO> resultActivityList = new ArrayList<>();
-        for (RewardActivityDO activity : activityList) {
-            // 情况一:全部商品都可以参与
-            if (PromotionProductScopeEnum.isAll(activity.getProductScope())) {
-                resultActivityList.add(activity);
-            }
-            // 情况二:指定商品参与
-            if (PromotionProductScopeEnum.isSpu(activity.getProductScope()) &&
-                    !intersectionDistinct(activity.getProductScopeValues(), spuIds).isEmpty()) {
-                resultActivityList.add(activity);
-            }
-        }
-        return resultActivityList;
-    }
+    // TODO 芋艿:后续完善单测
+//    @Test
+//    public void testGetRewardActivities_all() {
+//        LocalDateTime now = LocalDateTime.now();
+//        // mock 数据
+//        RewardActivityDO allActivity = randomPojo(RewardActivityDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())
+//                .setProductScope(PromotionProductScopeEnum.ALL.getScope()).setStartTime(now.minusDays(1)).setEndTime(now.plusDays(1)));
+//        rewardActivityMapper.insert(allActivity);
+//        RewardActivityDO productActivity = randomPojo(RewardActivityDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())
+//                .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductScopeValues(asList(1L, 2L))
+//                .setStartTime(now.minusDays(1)).setEndTime(now.plusDays(1)));
+//        rewardActivityMapper.insert(productActivity);
+//        // 准备参数
+//        Set<Long> spuIds = asSet(1L, 2L);
+//
+//        // 调用
+//        List<RewardActivityDO> activityList = rewardActivityServiceImpl.getRewardActivityListByStatusAndDateTimeLt(
+//                CommonStatusEnum.ENABLE.getStatus(), now);
+//        List<RewardActivityDO> matchRewardActivityList = filterMatchActivity(spuIds, activityList);
+//        // 断言
+//        assertEquals(matchRewardActivityList.size(), 1);
+//        matchRewardActivityList.forEach((activity) -> {
+//            if (activity.getId().equals(productActivity.getId())) {
+//                assertPojoEquals(activity, productActivity);
+//                assertEquals(activity.getProductScopeValues(), asList(1L, 2L));
+//            } else {
+//                fail();
+//            }
+//        });
+//    }
+//
+//    @Test
+//    public void testGetRewardActivities_product() {
+//        LocalDateTime now = LocalDateTime.now();
+//        // mock 数据
+//        RewardActivityDO productActivity01 = randomPojo(RewardActivityDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())
+//                .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductScopeValues(asList(1L, 2L))
+//                .setStartTime(now.minusDays(1)).setEndTime(now.plusDays(1)));
+//        rewardActivityMapper.insert(productActivity01);
+//        RewardActivityDO productActivity02 = randomPojo(RewardActivityDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())
+//                .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductScopeValues(singletonList(3L))
+//                .setStartTime(now.minusDays(1)).setEndTime(now.plusDays(1)));
+//        rewardActivityMapper.insert(productActivity02);
+//        // 准备参数
+//        Set<Long> spuIds = asSet(1L, 2L, 3L);
+//
+//        List<RewardActivityDO> activityList = rewardActivityServiceImpl.getRewardActivityListByStatusAndDateTimeLt(
+//                CommonStatusEnum.ENABLE.getStatus(), now);
+//        List<RewardActivityDO> matchRewardActivityList = filterMatchActivity(spuIds, activityList);
+//        // 断言
+//        assertEquals(matchRewardActivityList.size(), 2);
+//        matchRewardActivityList.forEach((activity) -> {
+//            if (activity.getId().equals(productActivity01.getId())) {
+//                assertPojoEquals(activity, productActivity01);
+//                assertEquals(activity.getProductScopeValues(), asList(1L, 2L));
+//            } else if (activity.getId().equals(productActivity02.getId())) {
+//                assertPojoEquals(activity, productActivity02);
+//                assertEquals(activity.getProductScopeValues(), singletonList(3L));
+//            } else {
+//                fail();
+//            }
+//        });
+//    }
+//
+//    /**
+//     * 获得满减送的订单项(商品)列表
+//     *
+//     * @param spuIds       商品编号
+//     * @param activityList 活动列表
+//     * @return 订单项(商品)列表
+//     */
+//    private List<RewardActivityDO> filterMatchActivity(Collection<Long> spuIds, List<RewardActivityDO> activityList) {
+//        List<RewardActivityDO> resultActivityList = new ArrayList<>();
+//        for (RewardActivityDO activity : activityList) {
+//            // 情况一:全部商品都可以参与
+//            if (PromotionProductScopeEnum.isAll(activity.getProductScope())) {
+//                resultActivityList.add(activity);
+//            }
+//            // 情况二:指定商品参与
+//            if (PromotionProductScopeEnum.isSpu(activity.getProductScope()) &&
+//                    !intersectionDistinct(activity.getProductScopeValues(), spuIds).isEmpty()) {
+//                resultActivityList.add(activity);
+//            }
+//        }
+//        return resultActivityList;
+//    }
 
 }

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

@@ -44,11 +44,9 @@ import org.springframework.web.bind.annotation.*;
 import java.time.LocalDateTime;
 import java.util.*;
 
-import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
-import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.DISCOUNT_ACTIVITY_TYPE_NOT_EXISTS;
 
 @Tag(name = "用户 App - 交易订单")
 @RestController
@@ -314,7 +312,7 @@ public class AppTradeOrderController {
                 Integer newPrice = price * discountProductRespDTO.getDiscountPercent() / 100;
                 sku.setPrice(price - newPrice);
             }else{
-                throw exception(DISCOUNT_ACTIVITY_TYPE_NOT_EXISTS);
+                throw new IllegalArgumentException("限时折扣活动类型不存在");
             }
             return sku;
         }

+ 3 - 2
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/aftersale/AfterSaleConvert.java

@@ -43,9 +43,10 @@ public interface AfterSaleConvert {
             @Mapping(source = "afterSale.orderId", target = "merchantOrderId"),
             @Mapping(source = "afterSale.id", target = "merchantRefundId"),
             @Mapping(source = "afterSale.applyReason", target = "reason"),
-            @Mapping(source = "afterSale.refundPrice", target = "price")
+            @Mapping(source = "afterSale.refundPrice", target = "price"),
+            @Mapping(source = "orderProperties.payAppKey", target = "appKey")
     })
-    PayRefundCreateReqDTO convert(String userIp, AfterSaleDO afterSale);
+    PayRefundCreateReqDTO convert(String userIp, AfterSaleDO afterSale, TradeOrderProperties orderProperties);
 
     MemberUserRespVO convert(MemberUserRespDTO bean);
 

+ 2 - 3
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/AfterSaleServiceImpl.java

@@ -385,9 +385,8 @@ public class AfterSaleServiceImpl implements AfterSaleService {
             @Override
             public void afterCommit() {
                 // 创建退款单
-                PayRefundCreateReqDTO createReqDTO = AfterSaleConvert.INSTANCE.convert(userIp, afterSale)
-                        .setReason(StrUtil.format("退款【{}】", afterSale.getSpuName()));
-                createReqDTO.setAppKey(tradeOrderProperties.getPayAppKey());
+                PayRefundCreateReqDTO createReqDTO = AfterSaleConvert.INSTANCE.convert(userIp, afterSale, tradeOrderProperties)
+                        .setReason(StrUtil.format("退款【{}】", afterSale.getSpuName()));;
                 Long payRefundId = payRefundApi.createRefund(createReqDTO);
                 // 更新售后单的退款单号
                 tradeAfterSaleMapper.updateById(new AfterSaleDO().setId(afterSale.getId()).setPayRefundId(payRefundId));

+ 1 - 2
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateRespBO.java

@@ -73,11 +73,10 @@ public class TradePriceCalculateRespBO {
      */
     private Long bargainActivityId;
 
-
     /**
      * 是否包邮
      */
-    private Boolean freeDelivery = false;
+    private Boolean freeDelivery;
 
     /**
      * 赠送的优惠劵

+ 4 - 6
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculator.java

@@ -121,13 +121,11 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
      * @return 是否包邮
      */
     private boolean isGlobalExpressFree(TradePriceCalculateRespBO result) {
-
         TradeConfigDO config = tradeConfigService.getTradeConfig();
-        return  result.getFreeDelivery() ||
-                (config != null
-                && Boolean.TRUE.equals(config.getDeliveryExpressFreeEnabled()) // 开启包邮
-                && result.getPrice().getPayPrice() >= config.getDeliveryExpressFreePrice()
-                ); // 满足包邮的价格
+        return config == null
+                || Boolean.TRUE.equals(config.getDeliveryExpressFreeEnabled()) // 开启包邮
+                || result.getFreeDelivery() //满减包邮
+                || result.getPrice().getPayPrice() >= config.getDeliveryExpressFreePrice(); // 满足包邮的价格
     }
 
     private void calculateDeliveryPrice(List<OrderItem> selectedSkus,

+ 61 - 104
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDiscountActivityPriceCalculator.java

@@ -1,8 +1,8 @@
 package cn.iocoder.yudao.module.trade.service.price.calculator;
 
-import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
 import cn.iocoder.yudao.module.member.api.level.MemberLevelApi;
 import cn.iocoder.yudao.module.member.api.level.dto.MemberLevelRespDTO;
 import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
@@ -14,12 +14,10 @@ import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum;
 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
+import jakarta.annotation.Resource;
 import org.springframework.core.annotation.Order;
 import org.springframework.stereotype.Component;
 
-import jakarta.annotation.Resource;
-
-import java.math.BigDecimal;
 import java.util.List;
 import java.util.Map;
 
@@ -30,6 +28,8 @@ import static cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceC
 /**
  * 限时折扣的 {@link TradePriceCalculator} 实现类
  *
+ * 由于“会员折扣”和“限时折扣”是冲突,需要选择优惠金额多的,所以也放在这里计算
+ *
  * @author 芋道源码
  */
 @Component
@@ -50,132 +50,89 @@ public class TradeDiscountActivityPriceCalculator implements TradePriceCalculato
             return;
         }
 
-        boolean discount;
-        boolean vip;
-
-        //----------------------------------限时折扣计算-----------------------------------------
-        // 获得 SKU 对应的限时折扣活动
+        // 1.1 获得 SKU 对应的限时折扣活动
         List<DiscountProductRespDTO> discountProducts = discountActivityApi.getMatchDiscountProductList(
                 convertSet(result.getItems(), TradePriceCalculateRespBO.OrderItem::getSkuId));
-        if (CollUtil.isEmpty(discountProducts)) {
-            discount = false;
-        }else {
-            discount = true;
-        }
         Map<Long, DiscountProductRespDTO> discountProductMap = convertMap(discountProducts, DiscountProductRespDTO::getSkuId);
-
-
-
-        //----------------------------------会员计算-----------------------------------------
-        MemberLevelRespDTO level;
-        // 获得用户的会员等级
+        // 1.2 获得会员等级
         MemberUserRespDTO user = memberUserApi.getUser(param.getUserId());
-        if (user.getLevelId() != null && user.getLevelId() > 0) {
-            level = memberLevelApi.getMemberLevel(user.getLevelId());
-            if (level != null && level.getDiscountPercent() != null) {
-                vip = true;
-            }else {
-                vip = false;
-            }
-        }else {
-            level = null;
-            vip = false;
-        }
-
+        MemberLevelRespDTO level = user != null && user.getLevelId() > 0 ? memberLevelApi.getMemberLevel(user.getLevelId()) : null;
 
         // 2. 计算每个 SKU 的优惠金额
         result.getItems().forEach(orderItem -> {
-
-            //----------------------------------限时折扣计算-----------------------------------------
-            DiscountProductRespDTO discountProduct = null;
-            Integer newDiscountPrice = 0;
-            if (discount){
-                // 2.1  计算限时折扣优惠信息
-                discountProduct = discountProductMap.get(orderItem.getSkuId());
-                if (discountProduct != null) {
-                    // 2.2 计算优惠金额
-                    Integer newPayPrice = calculatePayPrice(discountProduct, orderItem);
-                    newDiscountPrice = orderItem.getPayPrice() - newPayPrice;
-                }
+            if (!orderItem.getSelected()) {
+                return;
             }
-
-
-            //----------------------------------会员计算-----------------------------------------
-            Integer vipPrice = 0;
-            if (vip){
-                // 2.3 计算会员优惠金额
-                vipPrice = calculateVipPrice(orderItem.getPayPrice(), level.getDiscountPercent());
+            // 2.1 计算限时折扣的优惠金额
+            DiscountProductRespDTO discountProduct = discountProductMap.get(orderItem.getSkuId());
+            Integer discountPrice = calculateActivityPrice(discountProduct, orderItem);
+            // 2.2 计算 VIP 优惠金额
+            Integer vipPrice = calculateVipPrice(level, orderItem);
+            if (discountPrice <= 0 && vipPrice <= 0) {
+                return;
             }
 
-
-            // 2.4 记录优惠明细
-            // 注意,只有在选中的情况下,才会记录到优惠明细。否则仅仅是更新 SKU 优惠金额,用于展示
-            if (orderItem.getSelected()) {
-                if (discount && vip){
-                    if(newDiscountPrice > vipPrice){
-                        TradePriceCalculatorHelper.addPromotion(result, orderItem,
-                                discountProduct.getActivityId(), discountProduct.getActivityName(), PromotionTypeEnum.DISCOUNT_ACTIVITY.getType(),
-                                StrUtil.format("限时折扣:省 {} 元", formatPrice(newDiscountPrice)),
-                                newDiscountPrice);
-                        // 2.5 更新 SKU 优惠金额
-                        orderItem.setDiscountPrice(orderItem.getDiscountPrice() + newDiscountPrice);
-                    }else{
-                        TradePriceCalculatorHelper.addPromotion(result, orderItem,
-                                level.getId(), level.getName(), PromotionTypeEnum.MEMBER_LEVEL.getType(),
-                                String.format("会员等级折扣:省 %s 元", formatPrice(vipPrice)),
-                                vipPrice);
-                        // 2.5 更新 SKU 的优惠金额
-                        orderItem.setVipPrice(vipPrice);
-                    }
-                }else if (discount){
-                    TradePriceCalculatorHelper.addPromotion(result, orderItem,
-                            discountProduct.getActivityId(), discountProduct.getActivityName(), PromotionTypeEnum.DISCOUNT_ACTIVITY.getType(),
-                            StrUtil.format("限时折扣:省 {} 元", formatPrice(newDiscountPrice)),
-                            newDiscountPrice);
-                    // 2.5 更新 SKU 优惠金额
-                    orderItem.setDiscountPrice(orderItem.getDiscountPrice() + newDiscountPrice);
-                }else if (vip){
-                    TradePriceCalculatorHelper.addPromotion(result, orderItem,
-                            level.getId(), level.getName(), PromotionTypeEnum.MEMBER_LEVEL.getType(),
-                            String.format("会员等级折扣:省 %s 元", formatPrice(vipPrice)),
-                            vipPrice);
-                    // 2.5 更新 SKU 的优惠金额
-                    orderItem.setVipPrice(vipPrice);
-                }
+            // 3. 选择优惠金额多的
+            if (discountPrice > vipPrice) {
+                TradePriceCalculatorHelper.addPromotion(result, orderItem,
+                        discountProduct.getActivityId(), discountProduct.getActivityName(), PromotionTypeEnum.DISCOUNT_ACTIVITY.getType(),
+                        StrUtil.format("限时折扣:省 {} 元", formatPrice(discountPrice)),
+                        discountPrice);
+                // 更新 SKU 优惠金额
+                orderItem.setDiscountPrice(orderItem.getDiscountPrice() + discountPrice);
+            } else {
+                assert level != null;
+                TradePriceCalculatorHelper.addPromotion(result, orderItem,
+                        level.getId(), level.getName(), PromotionTypeEnum.MEMBER_LEVEL.getType(),
+                        String.format("会员等级折扣:省 %s 元", formatPrice(vipPrice)),
+                        vipPrice);
+                // 更新 SKU 的优惠金额
+                orderItem.setVipPrice(vipPrice);
             }
 
+            // 4. 分摊优惠
             TradePriceCalculatorHelper.recountPayPrice(orderItem);
+            TradePriceCalculatorHelper.recountAllPrice(result);
         });
-        TradePriceCalculatorHelper.recountAllPrice(result);
     }
 
-    private Integer calculatePayPrice(DiscountProductRespDTO discountProduct,
-                                      TradePriceCalculateRespBO.OrderItem orderItem) {
-        Integer price = orderItem.getPayPrice();
-        if (PromotionDiscountTypeEnum.PRICE.getType().equals(discountProduct.getDiscountType())) { // 减价
-            price -= discountProduct.getDiscountPrice() * orderItem.getCount();
-        } else if (PromotionDiscountTypeEnum.PERCENT.getType().equals(discountProduct.getDiscountType())) { // 打折
-            price = price * discountProduct.getDiscountPercent() / 100;
+    /**
+     * 计算优惠活动的价格
+     *
+     * @param discount 优惠活动
+     * @param orderItem 交易项
+     * @return 优惠价格
+     */
+    private Integer calculateActivityPrice(DiscountProductRespDTO discount,
+                                           TradePriceCalculateRespBO.OrderItem orderItem) {
+        if (discount == null) {
+            return 0;
+        }
+        Integer newPrice = orderItem.getPayPrice();
+        if (PromotionDiscountTypeEnum.PRICE.getType().equals(discount.getDiscountType())) { // 减价
+            newPrice -= discount.getDiscountPrice() * orderItem.getCount();
+        } else if (PromotionDiscountTypeEnum.PERCENT.getType().equals(discount.getDiscountType())) { // 打折
+            newPrice = newPrice * discount.getDiscountPercent() / 100;
         } else {
-            throw new IllegalArgumentException(String.format("优惠活动的商品(%s) 的优惠类型不正确", discountProduct));
+            throw new IllegalArgumentException(String.format("优惠活动的商品(%s) 的优惠类型不正确", discount));
         }
-        return price;
+        return orderItem.getPayPrice() - newPrice;
     }
 
     /**
-     * 计算会员 VIP 优惠价格
+     * 计算会员 VIP 优惠价格
      *
-     * @param price 原价
-     * @param discountPercent 折扣
+     * @param level 会员等级
+     * @param orderItem 交易项
      * @return 优惠价格
      */
-    public Integer calculateVipPrice(Integer price, Integer discountPercent) {
-        if (discountPercent == null) {
+    public Integer calculateVipPrice(MemberLevelRespDTO level,
+                                     TradePriceCalculateRespBO.OrderItem orderItem) {
+        if (level == null || level.getDiscountPercent() == null) {
             return 0;
         }
-        BigDecimal divide = new BigDecimal(price).multiply(new BigDecimal(discountPercent)).divide(new BigDecimal(100));
-        Integer newPrice =  divide.intValue();
-        return price - newPrice;
+        Integer newPrice = MoneyUtils.calculateRatePrice(orderItem.getPayPrice(), level.getDiscountPercent().doubleValue());
+        return orderItem.getPayPrice() - newPrice;
     }
 
 }

+ 0 - 93
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeMemberLevelPriceCalculator.java

@@ -1,93 +0,0 @@
-package cn.iocoder.yudao.module.trade.service.price.calculator;
-
-import cn.hutool.core.util.ObjectUtil;
-import cn.iocoder.yudao.module.member.api.level.MemberLevelApi;
-import cn.iocoder.yudao.module.member.api.level.dto.MemberLevelRespDTO;
-import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
-import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
-import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum;
-import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
-import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
-import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
-import org.springframework.core.annotation.Order;
-import org.springframework.stereotype.Component;
-
-import jakarta.annotation.Resource;
-
-import static cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculatorHelper.formatPrice;
-
-/**
- * 会员 VIP 折扣的 {@link TradePriceCalculator} 实现类
- *
- * @author 芋道源码
- */
-@Component
-@Order(TradePriceCalculator.ORDER_MEMBER_LEVEL)
-public class TradeMemberLevelPriceCalculator implements TradePriceCalculator {
-
-    @Resource
-    private MemberLevelApi memberLevelApi;
-    @Resource
-    private MemberUserApi memberUserApi;
-
-    /**
-     * 会员计算迁移到限时优惠计算里
-     * @param param
-     * @param result
-     */
-    @Override
-    public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) {
-//        // 0. 只有【普通】订单,才计算该优惠
-//        if (ObjectUtil.notEqual(result.getType(), TradeOrderTypeEnum.NORMAL.getType())) {
-//            return;
-//        }
-//        // 1. 获得用户的会员等级
-//        MemberUserRespDTO user = memberUserApi.getUser(param.getUserId());
-//        if (user.getLevelId() == null || user.getLevelId() <= 0) {
-//            return;
-//        }
-//        MemberLevelRespDTO level = memberLevelApi.getMemberLevel(user.getLevelId());
-//        if (level == null || level.getDiscountPercent() == null) {
-//            return;
-//        }
-//
-//        // 2. 计算每个 SKU 的优惠金额
-//        result.getItems().forEach(orderItem -> {
-//            // 2.1 计算优惠金额
-//            Integer vipPrice = calculateVipPrice(orderItem.getPayPrice(), level.getDiscountPercent());
-//            if (vipPrice <= 0) {
-//                return;
-//            }
-//
-//            // 2.2 记录优惠明细
-//            if (orderItem.getSelected()) {
-//                // 注意,只有在选中的情况下,才会记录到优惠明细。否则仅仅是更新 SKU 优惠金额,用于展示
-//                TradePriceCalculatorHelper.addPromotion(result, orderItem,
-//                        level.getId(), level.getName(), PromotionTypeEnum.MEMBER_LEVEL.getType(),
-//                        String.format("会员等级折扣:省 %s 元", formatPrice(vipPrice)),
-//                        vipPrice);
-//            }
-//
-//            // 2.3 更新 SKU 的优惠金额
-//            orderItem.setVipPrice(vipPrice);
-//            TradePriceCalculatorHelper.recountPayPrice(orderItem);
-//        });
-//        TradePriceCalculatorHelper.recountAllPrice(result);
-    }
-
-    /**
-     * 计算会员 VIP 优惠价格
-     *
-     * @param price 原价
-     * @param discountPercent 折扣
-     * @return 优惠价格
-     */
-    public Integer calculateVipPrice(Integer price, Integer discountPercent) {
-        if (discountPercent == null) {
-            return 0;
-        }
-        Integer newPrice = price * discountPercent / 100;
-        return price - newPrice;
-    }
-
-}

+ 0 - 2
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculator.java

@@ -13,8 +13,6 @@ import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
  */
 public interface TradePriceCalculator {
 
-    int ORDER_MEMBER_LEVEL = 5;
-
     int ORDER_SECKILL_ACTIVITY = 8;
     int ORDER_BARGAIN_ACTIVITY = 8;
     int ORDER_COMBINATION_ACTIVITY = 8;

+ 10 - 9
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeRewardActivityPriceCalculator.java

@@ -23,10 +23,8 @@ import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
 
-import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
-import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.REWARD_ACTIVITY_TYPE_NOT_EXISTS;
 import static cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculatorHelper.formatPrice;
 
 // TODO @puhui999:相关的单测,建议改一改
@@ -81,8 +79,10 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator
         Integer newDiscountPrice = rule.getDiscountPrice();
         // 2.2 计算分摊的优惠金额
         List<Integer> divideDiscountPrices = TradePriceCalculatorHelper.dividePrice(orderItems, newDiscountPrice);
-        //计算是否包邮
-        result.setFreeDelivery(rule.getFreeDelivery());
+        // 2.3 计算是否包邮
+        if (Boolean.TRUE.equals(rule.getFreeDelivery())) {
+            result.setFreeDelivery(true);
+        }
 
         // 3.1 记录使用的优惠劵
         result.setCouponId(param.getCouponId());
@@ -132,16 +132,17 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator
     private List<TradePriceCalculateRespBO.OrderItem> filterMatchActivityOrderItems(TradePriceCalculateRespBO result,
                                                                                     RewardActivityMatchRespDTO rewardActivity) {
         Integer productScope = rewardActivity.getProductScope();
-        if(PromotionProductScopeEnum.isAll(productScope)){
+        if (PromotionProductScopeEnum.isAll(productScope)){
             return result.getItems();
-        }else if (PromotionProductScopeEnum.isSpu(productScope)) {
+        } else if (PromotionProductScopeEnum.isSpu(productScope)) {
             return filterList(result.getItems(),
                     orderItem -> CollUtil.contains(rewardActivity.getProductScopeValues(), orderItem.getSpuId()));
-        }else if (PromotionProductScopeEnum.isCategory(productScope)) {
+        } else if (PromotionProductScopeEnum.isCategory(productScope)) {
             return filterList(result.getItems(),
                     orderItem -> CollUtil.contains(rewardActivity.getProductScopeValues(), orderItem.getCategoryId()));
-        }else{
-            throw exception(REWARD_ACTIVITY_TYPE_NOT_EXISTS);
+        } else {
+            throw new IllegalArgumentException(StrUtil.format("满减送活动({})的类型({})不存在",
+                    rewardActivity.getId(), productScope));
         }
     }
 

+ 0 - 118
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeMemberLevelPriceCalculatorTest.java

@@ -1,118 +0,0 @@
-package cn.iocoder.yudao.module.trade.service.price.calculator;
-
-import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
-import cn.iocoder.yudao.module.member.api.level.MemberLevelApi;
-import cn.iocoder.yudao.module.member.api.level.dto.MemberLevelRespDTO;
-import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
-import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
-import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum;
-import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
-import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
-import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
-import org.junit.jupiter.api.Test;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-
-import java.util.ArrayList;
-
-import static java.util.Arrays.asList;
-import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.when;
-
-/**
- * {@link TradeMemberLevelPriceCalculator} 的单元测试类
- *
- * @author 芋道源码
- */
-public class TradeMemberLevelPriceCalculatorTest extends BaseMockitoUnitTest {
-
-    @InjectMocks
-    private TradeMemberLevelPriceCalculator memberLevelPriceCalculator;
-
-    @Mock
-    private MemberLevelApi memberLevelApi;
-    @Mock
-    private MemberUserApi memberUserApi;
-
-    @Test
-    public void testCalculate() {
-        // 准备参数
-        TradePriceCalculateReqBO param = new TradePriceCalculateReqBO()
-                .setUserId(1024L)
-                .setItems(asList(
-                        new TradePriceCalculateReqBO.Item().setSkuId(10L).setCount(2).setSelected(true), // 匹配活动,且已选中
-                        new TradePriceCalculateReqBO.Item().setSkuId(20L).setCount(3).setSelected(false) // 匹配活动,但未选中
-                ));
-        TradePriceCalculateRespBO result = new TradePriceCalculateRespBO()
-                .setType(TradeOrderTypeEnum.NORMAL.getType())
-                .setPrice(new TradePriceCalculateRespBO.Price())
-                .setPromotions(new ArrayList<>())
-                .setItems(asList(
-                        new TradePriceCalculateRespBO.OrderItem().setSkuId(10L).setCount(2).setSelected(true)
-                                .setPrice(100),
-                        new TradePriceCalculateRespBO.OrderItem().setSkuId(20L).setCount(3).setSelected(false)
-                                .setPrice(50)
-                ));
-        // 保证价格被初始化上
-        TradePriceCalculatorHelper.recountPayPrice(result.getItems());
-        TradePriceCalculatorHelper.recountAllPrice(result);
-
-        // mock 方法(会员等级)
-        when(memberUserApi.getUser(eq(1024L))).thenReturn(new MemberUserRespDTO().setLevelId(2048L));
-        when(memberLevelApi.getMemberLevel(eq(2048L))).thenReturn(
-                new MemberLevelRespDTO().setId(2048L).setName("VIP 会员").setDiscountPercent(60));
-
-        // 调用
-        memberLevelPriceCalculator.calculate(param, result);
-        // 断言:Price 部分
-        TradePriceCalculateRespBO.Price price = result.getPrice();
-        assertEquals(price.getTotalPrice(), 200);
-        assertEquals(price.getDiscountPrice(), 0);
-        assertEquals(price.getPointPrice(), 0);
-        assertEquals(price.getDeliveryPrice(), 0);
-        assertEquals(price.getCouponPrice(), 0);
-        assertEquals(price.getVipPrice(), 80);
-        assertEquals(price.getPayPrice(), 120);
-        assertNull(result.getCouponId());
-        // 断言:SKU 1
-        assertEquals(result.getItems().size(), 2);
-        TradePriceCalculateRespBO.OrderItem orderItem01 = result.getItems().get(0);
-        assertEquals(orderItem01.getSkuId(), 10L);
-        assertEquals(orderItem01.getCount(), 2);
-        assertEquals(orderItem01.getPrice(), 100);
-        assertEquals(orderItem01.getDiscountPrice(), 0);
-        assertEquals(orderItem01.getDeliveryPrice(), 0);
-        assertEquals(orderItem01.getCouponPrice(), 0);
-        assertEquals(orderItem01.getPointPrice(), 0);
-        assertEquals(orderItem01.getVipPrice(), 80);
-        assertEquals(orderItem01.getPayPrice(), 120);
-        // 断言:SKU 2
-        TradePriceCalculateRespBO.OrderItem orderItem02 = result.getItems().get(1);
-        assertEquals(orderItem02.getSkuId(), 20L);
-        assertEquals(orderItem02.getCount(), 3);
-        assertEquals(orderItem02.getPrice(), 50);
-        assertEquals(orderItem02.getDiscountPrice(), 0);
-        assertEquals(orderItem02.getDeliveryPrice(), 0);
-        assertEquals(orderItem02.getCouponPrice(), 0);
-        assertEquals(orderItem02.getPointPrice(), 0);
-        assertEquals(orderItem02.getVipPrice(), 60);
-        assertEquals(orderItem02.getPayPrice(), 90);
-        // 断言:Promotion 部分
-        assertEquals(result.getPromotions().size(), 1);
-        TradePriceCalculateRespBO.Promotion promotion01 = result.getPromotions().get(0);
-        assertEquals(promotion01.getId(), 2048L);
-        assertEquals(promotion01.getName(), "VIP 会员");
-        assertEquals(promotion01.getType(), PromotionTypeEnum.MEMBER_LEVEL.getType());
-        assertEquals(promotion01.getTotalPrice(), 200);
-        assertEquals(promotion01.getDiscountPrice(), 80);
-        assertTrue(promotion01.getMatch());
-        assertEquals(promotion01.getDescription(), "会员等级折扣:省 0.80 元");
-        TradePriceCalculateRespBO.PromotionItem promotionItem01 = promotion01.getItems().get(0);
-        assertEquals(promotion01.getItems().size(), 1);
-        assertEquals(promotionItem01.getSkuId(), 10L);
-        assertEquals(promotionItem01.getTotalPrice(), 200);
-        assertEquals(promotionItem01.getDiscountPrice(), 80);
-    }
-
-}

+ 0 - 2
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java

@@ -11,7 +11,6 @@ import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
 import cn.iocoder.yudao.framework.datapermission.core.util.DataPermissionUtils;
-import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
 import cn.iocoder.yudao.module.infra.api.config.ConfigApi;
 import cn.iocoder.yudao.module.infra.api.file.FileApi;
 import cn.iocoder.yudao.module.system.controller.admin.auth.vo.AuthRegisterReqVO;
@@ -105,7 +104,6 @@ public class AdminUserServiceImpl implements AdminUserService {
         AdminUserDO user = BeanUtils.toBean(createReqVO, AdminUserDO.class);
         user.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启
         user.setPassword(encodePassword(createReqVO.getPassword())); // 加密密码
-        user.setTenantId(TenantContextHolder.getRequiredTenantId());
         userMapper.insert(user);
         // 2.2 插入关联岗位
         if (CollectionUtil.isNotEmpty(user.getPostIds())) {

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

@@ -6,7 +6,7 @@ spring:
   # 数据源配置项
   autoconfigure:
     exclude:
-      #- org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration # 默认 local 环境,不开启 Quartz 的自动配置
+      - org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration # 默认 local 环境,不开启 Quartz 的自动配置
       - de.codecentric.boot.admin.server.config.AdminServerAutoConfiguration # 禁用 Spring Boot Admin 的 Server 的自动配置
       - de.codecentric.boot.admin.server.ui.config.AdminServerUiAutoConfiguration # 禁用 Spring Boot Admin 的 Server UI 的自动配置
       - de.codecentric.boot.admin.client.config.SpringBootAdminClientAutoConfiguration # 禁用 Spring Boot Admin 的 Client 的自动配置
@@ -45,7 +45,7 @@ spring:
       primary: master
       datasource:
         master:
-          url: jdbc:mysql://192.168.10.207:3306/specialty?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
+          url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
           #          url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true # MySQL Connector/J 5.X 连接的示例
           #          url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL 连接的示例
           #          url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例
@@ -61,19 +61,19 @@ spring:
           #          password: SYSDBA001 # DM 连接的示例
           #          username: root # OpenGauss 连接的示例
           #          password: Yudao@2024 # OpenGauss 连接的示例
-#        slave: # 模拟从库,可根据自己需要修改
-#          lazy: true # 开启懒加载,保证启动速度
-#          url: jdbc:mysql://192.168.10.207:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true&nullCatalogMeansCurrent=true
-#          username: root
-#          password: 123456
+        slave: # 模拟从库,可根据自己需要修改
+          lazy: true # 开启懒加载,保证启动速度
+          url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true&nullCatalogMeansCurrent=true
+          username: root
+          password: 123456
 
   # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
   data:
     redis:
-      host: 192.168.10.207 # 地址
+      host: 127.0.0.1 # 地址
       port: 6379 # 端口
       database: 0 # 数据库索引
-      password: 123456 # 密码,建议生产环境开启
+#    password: dev # 密码,建议生产环境开启
 
 --- #################### 定时任务相关配置 ####################
 
@@ -200,8 +200,8 @@ wx:
 #    secret: 6f270509224a7ae1296bbf1c8cb97aed
 #    appid: wxc4598c446f8a9cb3 # 测试号(Kongdy 提供的)
 #    secret: 4a1a04e07f6a4a0751b39c3064a92c8b
-    appid: wx9a0a5b259d852380 # 测试号(puhui 提供的)
-    secret: 70e65fa9d1a4f2c4e1b2aa8751d3b75e
+    appid: wx66186af0759f47c9 # 测试号(puhui 提供的)
+    secret: 3218bcbd112cbc614c7264ceb20144ac
     config-storage:
       type: RedisTemplate # 采用 RedisTemplate 操作 Redis,会自动从 Spring 中获取
       key-prefix: wa # Redis Key 的前缀