Răsfoiți Sursa

!1050 【代码优化】商城: 满减送活动
Merge pull request !1050 from puhui999/develop

芋道源码 6 luni în urmă
părinte
comite
4c2ed461d4

+ 3 - 4
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/common/PromotionProductScopeEnum.java

@@ -15,10 +15,9 @@ import java.util.Arrays;
 @AllArgsConstructor
 public enum PromotionProductScopeEnum implements IntArrayValuable {
 
-    ALL(1, "通用券"), // 全部商品
-    SPU(2, "商品券"), // 指定商品
-    CATEGORY(3, "品类券"), // 指定品类
-    ;
+    ALL(1, "全部商品"),
+    SPU(2, "指定商品"),
+    CATEGORY(3, "指定品类");
 
     public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(PromotionProductScopeEnum::getScope).toArray();
 

+ 29 - 11
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityBaseVO.java

@@ -1,23 +1,22 @@
 package cn.iocoder.yudao.module.promotion.controller.admin.reward.vo;
 
 import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.BooleanUtil;
 import cn.iocoder.yudao.framework.common.validation.InEnum;
 import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum;
 import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;
 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.Valid;
 import jakarta.validation.constraints.AssertTrue;
 import jakarta.validation.constraints.Future;
 import jakarta.validation.constraints.Min;
 import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
 import java.time.LocalDateTime;
 import java.util.List;
-
-import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+import java.util.Objects;
 
 /**
 * 满减送活动 Base VO,提供给添加、修改、详细的子 VO 使用
@@ -32,12 +31,10 @@ public class RewardActivityBaseVO {
 
     @Schema(description = "开始时间", requiredMode = Schema.RequiredMode.REQUIRED)
     @NotNull(message = "开始时间不能为空")
-    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
     private LocalDateTime startTime;
 
     @Schema(description = "结束时间", requiredMode = Schema.RequiredMode.REQUIRED)
     @NotNull(message = "结束时间不能为空")
-    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
     @Future(message = "结束时间必须大于当前时间")
     private LocalDateTime endTime;
 
@@ -54,8 +51,8 @@ public class RewardActivityBaseVO {
     @InEnum(value = PromotionProductScopeEnum.class, message = "商品范围必须是 {value}")
     private Integer productScope;
 
-    @Schema(description = "商品 SPU 编号的数组", example = "1,2,3")
-    private List<Long> productSpuIds;
+    @Schema(description = "商品范围编号的数组", example = "[1, 3]")
+    private List<Long> productScopeValues;
 
     /**
      * 优惠规则的数组
@@ -63,6 +60,13 @@ public class RewardActivityBaseVO {
     @Valid // 校验下子对象
     private List<Rule> rules;
 
+    @AssertTrue(message = "商品范围编号的数组不能为空")
+    @JsonIgnore
+    public boolean isProductScopeValuesValid() {
+        return Objects.equals(productScope, PromotionProductScopeEnum.ALL.getScope()) // 全部范围时,可以为空
+                || CollUtil.isNotEmpty(productScopeValues);
+    }
+
     @Schema(description = "优惠规则")
     @Data
     public static class Rule {
@@ -76,12 +80,20 @@ public class RewardActivityBaseVO {
         private Integer discountPrice;
 
         @Schema(description = "是否包邮", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
+        @NotNull(message = "规则是否包邮不能为空")
         private Boolean freeDelivery;
 
+        @Schema(description = "是否赠送积分", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
+        @NotNull(message = "规则是否赠送积分不能为空")
+        private Boolean givePoint;
+
         @Schema(description = "赠送的积分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
-        @Min(value = 1L, message = "赠送的积分必须大于等于 1")
         private Integer point;
 
+        @Schema(description = "是否赠送优惠券", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
+        @NotNull(message = "规则是否赠送优惠券不能为空")
+        private Boolean giveCoupon;
+
         @Schema(description = "赠送的优惠劵编号的数组", example = "1,2,3")
         private List<Long> couponIds;
 
@@ -91,7 +103,13 @@ public class RewardActivityBaseVO {
         @AssertTrue(message = "优惠劵和数量必须一一对应")
         @JsonIgnore
         public boolean isCouponCountsValid() {
-            return CollUtil.size(couponCounts) == CollUtil.size(couponCounts);
+            return BooleanUtil.isFalse(givePoint) || CollUtil.size(couponIds) == CollUtil.size(couponCounts);
+        }
+
+        @AssertTrue(message = "赠送的积分不能小于 1")
+        @JsonIgnore
+        public boolean isPointValid() {
+            return BooleanUtil.isFalse(givePoint) || (point != null && point >= 1);
         }
 
     }

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

@@ -9,9 +9,7 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityD
 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
-import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityDO;
-import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum;
 import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum;
 import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService;
 import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService;
@@ -30,7 +28,6 @@ import org.springframework.web.bind.annotation.RestController;
 
 import java.time.LocalDateTime;
 import java.util.*;
-import java.util.stream.Collectors;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
@@ -145,28 +142,28 @@ public class AppActivityController {
     }
 
     private void getRewardActivities(Collection<Long> spuIds, LocalDateTime now, List<AppActivityRespVO> activityList) {
-        // TODO @puhui999:有 3 范围,不只 spuId,还有 categoryId,全部
-        List<RewardActivityDO> rewardActivityList = rewardActivityService.getRewardActivityBySpuIdsAndStatusAndDateTimeLt(
-                spuIds, PromotionActivityStatusEnum.RUN.getStatus(), now);
-        if (CollUtil.isEmpty(rewardActivityList)) {
-            return;
-        }
-
-        Map<Long, Optional<RewardActivityDO>> spuIdAndActivityMap = spuIds.stream()
-                .collect(Collectors.toMap(
-                        spuId -> spuId,
-                        spuId -> rewardActivityList.stream()
-                                .filter(activity -> activity.getProductSpuIds().contains(spuId))
-                                .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()));
-        }
+        // TODO @puhui999:有 3 范围,不只 spuId,还有 categoryId,全部,下次 fix
+        //List<RewardActivityDO> rewardActivityList = rewardActivityService.getRewardActivityBySpuIdsAndStatusAndDateTimeLt(
+        //        spuIds, PromotionActivityStatusEnum.RUN.getStatus(), now);
+        //if (CollUtil.isEmpty(rewardActivityList)) {
+        //    return;
+        //}
+        //
+        //Map<Long, Optional<RewardActivityDO>> spuIdAndActivityMap = spuIds.stream()
+        //        .collect(Collectors.toMap(
+        //                spuId -> spuId,
+        //                spuId -> rewardActivityList.stream()
+        //                        .filter(activity -> activity.getProductSpuIds().contains(spuId))
+        //                        .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()));
+        //}
     }
 
 }

+ 9 - 1
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/reward/RewardActivityDO.java

@@ -71,7 +71,7 @@ public class RewardActivityDO extends BaseDO {
      * 商品 SPU 编号的数组
      */
     @TableField(typeHandler = LongListTypeHandler.class)
-    private List<Long> productSpuIds;
+    private List<Long> productScopeValues;
     /**
      * 优惠规则的数组
      */
@@ -99,10 +99,18 @@ public class RewardActivityDO extends BaseDO {
          * 是否包邮
          */
         private Boolean freeDelivery;
+        /**
+         * 是否赠送积分
+         */
+        private Boolean givePoint;
         /**
          * 赠送的积分
          */
         private Integer point;
+        /**
+         * 是否赠送优惠券
+         */
+        private Boolean giveCoupon;
         /**
          * 赠送的优惠劵编号的数组
          */

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

@@ -2,6 +2,8 @@ package cn.iocoder.yudao.module.promotion.service.reward;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.product.api.category.ProductCategoryApi;
+import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
 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.RewardActivityPageReqVO;
@@ -10,6 +12,7 @@ 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;
@@ -19,6 +22,7 @@ import java.time.LocalDateTime;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
+import java.util.Objects;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
@@ -37,12 +41,19 @@ public class RewardActivityServiceImpl implements RewardActivityService {
     @Resource
     private RewardActivityMapper rewardActivityMapper;
 
+    @Resource
+    private ProductCategoryApi productCategoryApi;
+    @Resource
+    private ProductSpuApi productSpuApi;
+
     @Override
     public Long createRewardActivity(RewardActivityCreateReqVO createReqVO) {
-        // 校验商品是否冲突
-        validateRewardActivitySpuConflicts(null, createReqVO.getProductSpuIds());
+        // 1.1 校验商品范围
+        validateProductScope(createReqVO.getProductScope(), createReqVO.getProductScopeValues());
+        // 1.2 校验商品是否冲突
+        //validateRewardActivitySpuConflicts(null, createReqVO.getProductSpuIds());
 
-        // 插入
+        // 2. 插入
         RewardActivityDO rewardActivity = RewardActivityConvert.INSTANCE.convert(createReqVO)
                 .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getEndTime()));
         rewardActivityMapper.insert(rewardActivity);
@@ -52,15 +63,17 @@ public class RewardActivityServiceImpl implements RewardActivityService {
 
     @Override
     public void updateRewardActivity(RewardActivityUpdateReqVO updateReqVO) {
-        // 校验存在
+        // 1.1 校验存在
         RewardActivityDO dbRewardActivity = validateRewardActivityExists(updateReqVO.getId());
         if (dbRewardActivity.getStatus().equals(PromotionActivityStatusEnum.CLOSE.getStatus())) { // 已关闭的活动,不能修改噢
             throw exception(REWARD_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED);
         }
-        // 校验商品是否冲突
-        validateRewardActivitySpuConflicts(updateReqVO.getId(), updateReqVO.getProductSpuIds());
+        // 1.2 校验商品范围
+        validateProductScope(updateReqVO.getProductScope(), updateReqVO.getProductScopeValues());
+        // 1.3 校验商品是否冲突
+        //validateRewardActivitySpuConflicts(updateReqVO.getId(), updateReqVO.getProductSpuIds());
 
-        // 更新
+        // 2. 更新
         RewardActivityDO updateObj = RewardActivityConvert.INSTANCE.convert(updateReqVO)
                 .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getEndTime()));
         rewardActivityMapper.updateById(updateObj);
@@ -103,7 +116,7 @@ public class RewardActivityServiceImpl implements RewardActivityService {
     }
 
     // TODO @芋艿:逻辑有问题,需要优化;要分成全场、和指定来校验;
-
+    // TODO @puhui999: 下次提交 fix
     /**
      * 校验商品参加的活动是否冲突
      *
@@ -126,6 +139,14 @@ public class RewardActivityServiceImpl implements RewardActivityService {
         }
     }
 
+    private void validateProductScope(Integer productScope, List<Long> productScopeValues) {
+        if (Objects.equals(PromotionProductScopeEnum.SPU.getScope(), productScope)) {
+            productSpuApi.validateSpuList(productScopeValues);
+        } else if (Objects.equals(PromotionProductScopeEnum.CATEGORY.getScope(), productScope)) {
+            productCategoryApi.validateCategoryList(productScopeValues);
+        }
+    }
+
     /**
      * 获得商品参加的满减送活动的数组
      *
@@ -135,8 +156,10 @@ public class RewardActivityServiceImpl implements RewardActivityService {
      */
     private List<RewardActivityDO> getRewardActivityListBySpuIds(Collection<Long> spuIds,
                                                                  Collection<Integer> statuses) {
-        List<RewardActivityDO> list = rewardActivityMapper.selectListByStatus(statuses);
-        return CollUtil.filter(list, activity -> CollUtil.containsAny(activity.getProductSpuIds(), spuIds));
+        // TODO @puhui999: 下次 fix
+        //List<RewardActivityDO> list = rewardActivityMapper.selectListByStatus(statuses);
+        //return CollUtil.filter(list, activity -> CollUtil.containsAny(activity.getProductSpuIds(), spuIds));
+        return List.of();
     }
 
     @Override

+ 0 - 3
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSalePageReqVO.java

@@ -27,9 +27,6 @@ public class AfterSalePageReqVO extends PageParam {
     @Schema(description = "售后流水号", example = "202211190847450020500077")
     private String no;
 
-    @Schema(description = "用户编号", example = "1024")
-    private Long userId;
-
     @Schema(description = "售后状态", example = "10")
     @InEnum(value = AfterSaleStatusEnum.class, message = "售后状态必须是 {value}")
     private Integer status;

+ 0 - 1
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/aftersale/AfterSaleMapper.java

@@ -18,7 +18,6 @@ public interface AfterSaleMapper extends BaseMapperX<AfterSaleDO> {
         return selectPage(reqVO, new LambdaQueryWrapperX<AfterSaleDO>()
                 .eqIfPresent(AfterSaleDO::getUserId, reqVO.getUserId())
                 .likeIfPresent(AfterSaleDO::getNo, reqVO.getNo())
-                .eqIfPresent(AfterSaleDO::getUserId, reqVO.getUserId())
                 .eqIfPresent(AfterSaleDO::getStatus, reqVO.getStatus())
                 .eqIfPresent(AfterSaleDO::getType, reqVO.getType())
                 .eqIfPresent(AfterSaleDO::getWay, reqVO.getWay())