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

Merge pull request !1050 from puhui999/develop
This commit is contained in:
芋道源码 2024-08-23 10:50:01 +00:00 committed by Gitee
commit 4c2ed461d4
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
7 changed files with 96 additions and 55 deletions

View File

@ -15,10 +15,9 @@ import java.util.Arrays;
@AllArgsConstructor @AllArgsConstructor
public enum PromotionProductScopeEnum implements IntArrayValuable { public enum PromotionProductScopeEnum implements IntArrayValuable {
ALL(1, "通用券"), // 全部商品 ALL(1, "全部商品"),
SPU(2, "商品券"), // 指定商品 SPU(2, "指定商品"),
CATEGORY(3, "品类券"), // 指定品类 CATEGORY(3, "指定品类");
;
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(PromotionProductScopeEnum::getScope).toArray(); 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; package cn.iocoder.yudao.module.promotion.controller.admin.reward.vo;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.iocoder.yudao.framework.common.validation.InEnum; 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.PromotionConditionTypeEnum;
import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import jakarta.validation.constraints.AssertTrue; import jakarta.validation.constraints.AssertTrue;
import jakarta.validation.constraints.Future; import jakarta.validation.constraints.Future;
import jakarta.validation.constraints.Min; import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import java.util.Objects;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
/** /**
* 满减送活动 Base VO提供给添加修改详细的子 VO 使用 * 满减送活动 Base VO提供给添加修改详细的子 VO 使用
@ -32,12 +31,10 @@ public class RewardActivityBaseVO {
@Schema(description = "开始时间", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "开始时间", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "开始时间不能为空") @NotNull(message = "开始时间不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime startTime; private LocalDateTime startTime;
@Schema(description = "结束时间", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "结束时间", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "结束时间不能为空") @NotNull(message = "结束时间不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@Future(message = "结束时间必须大于当前时间") @Future(message = "结束时间必须大于当前时间")
private LocalDateTime endTime; private LocalDateTime endTime;
@ -54,8 +51,8 @@ public class RewardActivityBaseVO {
@InEnum(value = PromotionProductScopeEnum.class, message = "商品范围必须是 {value}") @InEnum(value = PromotionProductScopeEnum.class, message = "商品范围必须是 {value}")
private Integer productScope; private Integer productScope;
@Schema(description = "商品 SPU 编号的数组", example = "1,2,3") @Schema(description = "商品范围编号的数组", example = "[1, 3]")
private List<Long> productSpuIds; private List<Long> productScopeValues;
/** /**
* 优惠规则的数组 * 优惠规则的数组
@ -63,6 +60,13 @@ public class RewardActivityBaseVO {
@Valid // 校验下子对象 @Valid // 校验下子对象
private List<Rule> rules; private List<Rule> rules;
@AssertTrue(message = "商品范围编号的数组不能为空")
@JsonIgnore
public boolean isProductScopeValuesValid() {
return Objects.equals(productScope, PromotionProductScopeEnum.ALL.getScope()) // 全部范围时可以为空
|| CollUtil.isNotEmpty(productScopeValues);
}
@Schema(description = "优惠规则") @Schema(description = "优惠规则")
@Data @Data
public static class Rule { public static class Rule {
@ -76,12 +80,20 @@ public class RewardActivityBaseVO {
private Integer discountPrice; private Integer discountPrice;
@Schema(description = "是否包邮", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") @Schema(description = "是否包邮", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
@NotNull(message = "规则是否包邮不能为空")
private Boolean freeDelivery; private Boolean freeDelivery;
@Schema(description = "是否赠送积分", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
@NotNull(message = "规则是否赠送积分不能为空")
private Boolean givePoint;
@Schema(description = "赠送的积分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") @Schema(description = "赠送的积分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
@Min(value = 1L, message = "赠送的积分必须大于等于 1")
private Integer point; private Integer point;
@Schema(description = "是否赠送优惠券", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
@NotNull(message = "规则是否赠送优惠券不能为空")
private Boolean giveCoupon;
@Schema(description = "赠送的优惠劵编号的数组", example = "1,2,3") @Schema(description = "赠送的优惠劵编号的数组", example = "1,2,3")
private List<Long> couponIds; private List<Long> couponIds;
@ -91,7 +103,13 @@ public class RewardActivityBaseVO {
@AssertTrue(message = "优惠劵和数量必须一一对应") @AssertTrue(message = "优惠劵和数量必须一一对应")
@JsonIgnore @JsonIgnore
public boolean isCouponCountsValid() { 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.combination.CombinationActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO; 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.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.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.enums.common.PromotionTypeEnum;
import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService; import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService;
import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService; 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.time.LocalDateTime;
import java.util.*; 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.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; 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) { private void getRewardActivities(Collection<Long> spuIds, LocalDateTime now, List<AppActivityRespVO> activityList) {
// TODO @puhui999 3 范围不只 spuId还有 categoryId全部 // TODO @puhui999 3 范围不只 spuId还有 categoryId全部下次 fix
List<RewardActivityDO> rewardActivityList = rewardActivityService.getRewardActivityBySpuIdsAndStatusAndDateTimeLt( //List<RewardActivityDO> rewardActivityList = rewardActivityService.getRewardActivityBySpuIdsAndStatusAndDateTimeLt(
spuIds, PromotionActivityStatusEnum.RUN.getStatus(), now); // spuIds, PromotionActivityStatusEnum.RUN.getStatus(), now);
if (CollUtil.isEmpty(rewardActivityList)) { //if (CollUtil.isEmpty(rewardActivityList)) {
return; // return;
} //}
//
Map<Long, Optional<RewardActivityDO>> spuIdAndActivityMap = spuIds.stream() //Map<Long, Optional<RewardActivityDO>> spuIdAndActivityMap = spuIds.stream()
.collect(Collectors.toMap( // .collect(Collectors.toMap(
spuId -> spuId, // spuId -> spuId,
spuId -> rewardActivityList.stream() // spuId -> rewardActivityList.stream()
.filter(activity -> activity.getProductSpuIds().contains(spuId)) // .filter(activity -> activity.getProductSpuIds().contains(spuId))
.max(Comparator.comparing(RewardActivityDO::getCreateTime)))); // .max(Comparator.comparing(RewardActivityDO::getCreateTime))));
for (Long supId : spuIdAndActivityMap.keySet()) { //for (Long supId : spuIdAndActivityMap.keySet()) {
if (spuIdAndActivityMap.get(supId).isEmpty()) { // if (spuIdAndActivityMap.get(supId).isEmpty()) {
continue; // continue;
} // }
//
RewardActivityDO rewardActivityDO = spuIdAndActivityMap.get(supId).get(); // RewardActivityDO rewardActivityDO = spuIdAndActivityMap.get(supId).get();
activityList.add(new AppActivityRespVO(rewardActivityDO.getId(), PromotionTypeEnum.REWARD_ACTIVITY.getType(), // activityList.add(new AppActivityRespVO(rewardActivityDO.getId(), PromotionTypeEnum.REWARD_ACTIVITY.getType(),
rewardActivityDO.getName(), supId, rewardActivityDO.getStartTime(), rewardActivityDO.getEndTime())); // rewardActivityDO.getName(), supId, rewardActivityDO.getStartTime(), rewardActivityDO.getEndTime()));
} //}
} }
} }

View File

@ -71,7 +71,7 @@ public class RewardActivityDO extends BaseDO {
* 商品 SPU 编号的数组 * 商品 SPU 编号的数组
*/ */
@TableField(typeHandler = LongListTypeHandler.class) @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 freeDelivery;
/**
* 是否赠送积分
*/
private Boolean givePoint;
/** /**
* 赠送的积分 * 赠送的积分
*/ */
private Integer point; 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.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.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.RewardActivityCreateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO; 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.dataobject.reward.RewardActivityDO;
import cn.iocoder.yudao.module.promotion.dal.mysql.reward.RewardActivityMapper; 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.PromotionActivityStatusEnum;
import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;
import cn.iocoder.yudao.module.promotion.util.PromotionUtils; import cn.iocoder.yudao.module.promotion.util.PromotionUtils;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -19,6 +22,7 @@ import java.time.LocalDateTime;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; 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.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.convertSet;
@ -37,12 +41,19 @@ public class RewardActivityServiceImpl implements RewardActivityService {
@Resource @Resource
private RewardActivityMapper rewardActivityMapper; private RewardActivityMapper rewardActivityMapper;
@Resource
private ProductCategoryApi productCategoryApi;
@Resource
private ProductSpuApi productSpuApi;
@Override @Override
public Long createRewardActivity(RewardActivityCreateReqVO createReqVO) { public Long createRewardActivity(RewardActivityCreateReqVO createReqVO) {
// 校验商品是否冲突 // 1.1 校验商品范围
validateRewardActivitySpuConflicts(null, createReqVO.getProductSpuIds()); validateProductScope(createReqVO.getProductScope(), createReqVO.getProductScopeValues());
// 1.2 校验商品是否冲突
//validateRewardActivitySpuConflicts(null, createReqVO.getProductSpuIds());
// 插入 // 2. 插入
RewardActivityDO rewardActivity = RewardActivityConvert.INSTANCE.convert(createReqVO) RewardActivityDO rewardActivity = RewardActivityConvert.INSTANCE.convert(createReqVO)
.setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getEndTime())); .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getEndTime()));
rewardActivityMapper.insert(rewardActivity); rewardActivityMapper.insert(rewardActivity);
@ -52,15 +63,17 @@ public class RewardActivityServiceImpl implements RewardActivityService {
@Override @Override
public void updateRewardActivity(RewardActivityUpdateReqVO updateReqVO) { public void updateRewardActivity(RewardActivityUpdateReqVO updateReqVO) {
// 校验存在 // 1.1 校验存在
RewardActivityDO dbRewardActivity = validateRewardActivityExists(updateReqVO.getId()); RewardActivityDO dbRewardActivity = validateRewardActivityExists(updateReqVO.getId());
if (dbRewardActivity.getStatus().equals(PromotionActivityStatusEnum.CLOSE.getStatus())) { // 已关闭的活动不能修改噢 if (dbRewardActivity.getStatus().equals(PromotionActivityStatusEnum.CLOSE.getStatus())) { // 已关闭的活动不能修改噢
throw exception(REWARD_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED); throw exception(REWARD_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED);
} }
// 校验商品是否冲突 // 1.2 校验商品范围
validateRewardActivitySpuConflicts(updateReqVO.getId(), updateReqVO.getProductSpuIds()); validateProductScope(updateReqVO.getProductScope(), updateReqVO.getProductScopeValues());
// 1.3 校验商品是否冲突
//validateRewardActivitySpuConflicts(updateReqVO.getId(), updateReqVO.getProductSpuIds());
// 更新 // 2. 更新
RewardActivityDO updateObj = RewardActivityConvert.INSTANCE.convert(updateReqVO) RewardActivityDO updateObj = RewardActivityConvert.INSTANCE.convert(updateReqVO)
.setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getEndTime())); .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getEndTime()));
rewardActivityMapper.updateById(updateObj); rewardActivityMapper.updateById(updateObj);
@ -103,7 +116,7 @@ public class RewardActivityServiceImpl implements RewardActivityService {
} }
// TODO @芋艿逻辑有问题需要优化要分成全场和指定来校验 // 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, private List<RewardActivityDO> getRewardActivityListBySpuIds(Collection<Long> spuIds,
Collection<Integer> statuses) { Collection<Integer> statuses) {
List<RewardActivityDO> list = rewardActivityMapper.selectListByStatus(statuses); // TODO @puhui999: 下次 fix
return CollUtil.filter(list, activity -> CollUtil.containsAny(activity.getProductSpuIds(), spuIds)); //List<RewardActivityDO> list = rewardActivityMapper.selectListByStatus(statuses);
//return CollUtil.filter(list, activity -> CollUtil.containsAny(activity.getProductSpuIds(), spuIds));
return List.of();
} }
@Override @Override

View File

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

View File

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