【代码优化】商城: 满减送活动

This commit is contained in:
puhui999 2024-08-22 18:23:54 +08:00
parent 2b681f90ca
commit 32e25cf4a2
7 changed files with 96 additions and 55 deletions

View File

@ -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();

View File

@ -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);
}
}

View File

@ -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()));
//}
}
}

View File

@ -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;
/**
* 赠送的优惠劵编号的数组
*/

View File

@ -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

View File

@ -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;

View File

@ -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())