Commit 79304b3a7383cb1dc060e01b87e584efc82dc94f

Authored by YunaiV
1 parent 74b6ff1e

promotion:增加满减送活动的排重校验、单元测试

Showing 11 changed files with 228 additions and 88 deletions
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
@@ -29,5 +29,6 @@ public interface ErrorCodeConstants { @@ -29,5 +29,6 @@ public interface ErrorCodeConstants {
29 29
30 // ========== 满减送活动 1003006000 ========== 30 // ========== 满减送活动 1003006000 ==========
31 ErrorCode REWARD_ACTIVITY_NOT_EXISTS = new ErrorCode(1003006000, "满减送活动不存在"); 31 ErrorCode REWARD_ACTIVITY_NOT_EXISTS = new ErrorCode(1003006000, "满减送活动不存在");
  32 + ErrorCode REWARD_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1003006001, "商品({}) 已经参加满减送活动({})");
32 33
33 } 34 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/RewardActivityController.java
@@ -47,18 +47,18 @@ public class RewardActivityController { @@ -47,18 +47,18 @@ public class RewardActivityController {
47 47
48 @DeleteMapping("/delete") 48 @DeleteMapping("/delete")
49 @ApiOperation("删除满减送活动") 49 @ApiOperation("删除满减送活动")
50 - @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Integer.class) 50 + @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
51 @PreAuthorize("@ss.hasPermission('promotion:reward-activity:delete')") 51 @PreAuthorize("@ss.hasPermission('promotion:reward-activity:delete')")
52 - public CommonResult<Boolean> deleteRewardActivity(@RequestParam("id") Integer id) { 52 + public CommonResult<Boolean> deleteRewardActivity(@RequestParam("id") Long id) {
53 rewardActivityService.deleteRewardActivity(id); 53 rewardActivityService.deleteRewardActivity(id);
54 return success(true); 54 return success(true);
55 } 55 }
56 56
57 @GetMapping("/get") 57 @GetMapping("/get")
58 @ApiOperation("获得满减送活动") 58 @ApiOperation("获得满减送活动")
59 - @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Integer.class) 59 + @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
60 @PreAuthorize("@ss.hasPermission('promotion:reward-activity:query')") 60 @PreAuthorize("@ss.hasPermission('promotion:reward-activity:query')")
61 - public CommonResult<RewardActivityRespVO> getRewardActivity(@RequestParam("id") Integer id) { 61 + public CommonResult<RewardActivityRespVO> getRewardActivity(@RequestParam("id") Long id) {
62 RewardActivityDO rewardActivity = rewardActivityService.getRewardActivity(id); 62 RewardActivityDO rewardActivity = rewardActivityService.getRewardActivity(id);
63 return success(RewardActivityConvert.INSTANCE.convert(rewardActivity)); 63 return success(RewardActivityConvert.INSTANCE.convert(rewardActivity));
64 } 64 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityBaseVO.java
1 package cn.iocoder.yudao.module.promotion.controller.admin.reward.vo; 1 package cn.iocoder.yudao.module.promotion.controller.admin.reward.vo;
2 2
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.iocoder.yudao.framework.common.validation.InEnum;
  5 +import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum;
  6 +import com.fasterxml.jackson.annotation.JsonIgnore;
3 import io.swagger.annotations.ApiModel; 7 import io.swagger.annotations.ApiModel;
4 import io.swagger.annotations.ApiModelProperty; 8 import io.swagger.annotations.ApiModelProperty;
5 import lombok.Data; 9 import lombok.Data;
6 import org.springframework.format.annotation.DateTimeFormat; 10 import org.springframework.format.annotation.DateTimeFormat;
7 11
  12 +import javax.validation.Valid;
  13 +import javax.validation.constraints.AssertTrue;
  14 +import javax.validation.constraints.Future;
  15 +import javax.validation.constraints.Min;
8 import javax.validation.constraints.NotNull; 16 import javax.validation.constraints.NotNull;
9 import java.util.Date; 17 import java.util.Date;
10 import java.util.List; 18 import java.util.List;
@@ -30,6 +38,7 @@ public class RewardActivityBaseVO { @@ -30,6 +38,7 @@ public class RewardActivityBaseVO {
30 @ApiModelProperty(value = "结束时间", required = true) 38 @ApiModelProperty(value = "结束时间", required = true)
31 @NotNull(message = "结束时间不能为空") 39 @NotNull(message = "结束时间不能为空")
32 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) 40 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  41 + @Future(message = "结束时间必须大于当前时间")
33 private Date endTime; 42 private Date endTime;
34 43
35 @ApiModelProperty(value = "备注", example = "biubiubiu") 44 @ApiModelProperty(value = "备注", example = "biubiubiu")
@@ -37,10 +46,12 @@ public class RewardActivityBaseVO { @@ -37,10 +46,12 @@ public class RewardActivityBaseVO {
37 46
38 @ApiModelProperty(value = "条件类型", required = true, example = "1") 47 @ApiModelProperty(value = "条件类型", required = true, example = "1")
39 @NotNull(message = "条件类型不能为空") 48 @NotNull(message = "条件类型不能为空")
  49 + @InEnum(value = PromotionConditionTypeEnum.class, message = "条件类型必须是 {value}")
40 private Integer conditionType; 50 private Integer conditionType;
41 51
42 @ApiModelProperty(value = "商品范围", required = true, example = "1") 52 @ApiModelProperty(value = "商品范围", required = true, example = "1")
43 @NotNull(message = "商品范围不能为空") 53 @NotNull(message = "商品范围不能为空")
  54 + @InEnum(value = PromotionConditionTypeEnum.class, message = "商品范围必须是 {value}")
44 private Integer productScope; 55 private Integer productScope;
45 56
46 @ApiModelProperty(value = "商品 SPU 编号的数组", example = "1,2,3") 57 @ApiModelProperty(value = "商品 SPU 编号的数组", example = "1,2,3")
@@ -49,6 +60,7 @@ public class RewardActivityBaseVO { @@ -49,6 +60,7 @@ public class RewardActivityBaseVO {
49 /** 60 /**
50 * 优惠规则的数组 61 * 优惠规则的数组
51 */ 62 */
  63 + @Valid // 校验下子对象
52 private List<Rule> rules; 64 private List<Rule> rules;
53 65
54 @ApiModel("优惠规则") 66 @ApiModel("优惠规则")
@@ -56,15 +68,18 @@ public class RewardActivityBaseVO { @@ -56,15 +68,18 @@ public class RewardActivityBaseVO {
56 public static class Rule { 68 public static class Rule {
57 69
58 @ApiModelProperty(value = "优惠门槛", required = true, example = "100", notes = "1. 满 N 元,单位:分; 2. 满 N 件") 70 @ApiModelProperty(value = "优惠门槛", required = true, example = "100", notes = "1. 满 N 元,单位:分; 2. 满 N 件")
  71 + @Min(value = 1L, message = "优惠门槛必须大于等于 1")
59 private Integer limit; 72 private Integer limit;
60 73
61 @ApiModelProperty(value = "优惠价格", required = true, example = "100", notes = "单位:分") 74 @ApiModelProperty(value = "优惠价格", required = true, example = "100", notes = "单位:分")
  75 + @Min(value = 1L, message = "优惠价格必须大于等于 1")
62 private Integer discountPrice; 76 private Integer discountPrice;
63 77
64 @ApiModelProperty(value = "是否包邮", required = true, example = "true") 78 @ApiModelProperty(value = "是否包邮", required = true, example = "true")
65 private Boolean freeDelivery; 79 private Boolean freeDelivery;
66 80
67 @ApiModelProperty(value = "赠送的积分", required = true, example = "100") 81 @ApiModelProperty(value = "赠送的积分", required = true, example = "100")
  82 + @Min(value = 1L, message = "赠送的积分必须大于等于 1")
68 private Integer point; 83 private Integer point;
69 84
70 @ApiModelProperty(value = "赠送的优惠劵编号的数组", example = "1,2,3") 85 @ApiModelProperty(value = "赠送的优惠劵编号的数组", example = "1,2,3")
@@ -73,6 +88,12 @@ public class RewardActivityBaseVO { @@ -73,6 +88,12 @@ public class RewardActivityBaseVO {
73 @ApiModelProperty(value = "赠送的优惠卷数量的数组", example = "1,2,3") 88 @ApiModelProperty(value = "赠送的优惠卷数量的数组", example = "1,2,3")
74 private List<Integer> couponCounts; 89 private List<Integer> couponCounts;
75 90
  91 + @AssertTrue(message = "优惠劵和数量必须一一对应")
  92 + @JsonIgnore
  93 + public boolean isCouponCountsValid() {
  94 + return CollUtil.size(couponCounts) == CollUtil.size(couponCounts);
  95 + }
  96 +
76 } 97 }
77 98
78 } 99 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityUpdateReqVO.java
@@ -12,6 +12,6 @@ public class RewardActivityUpdateReqVO extends RewardActivityBaseVO { @@ -12,6 +12,6 @@ public class RewardActivityUpdateReqVO extends RewardActivityBaseVO {
12 12
13 @ApiModelProperty(value = "活动编号", required = true, example = "1024") 13 @ApiModelProperty(value = "活动编号", required = true, example = "1024")
14 @NotNull(message = "活动编号不能为空") 14 @NotNull(message = "活动编号不能为空")
15 - private Integer id; 15 + private Long id;
16 16
17 } 17 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/reward/RewardActivityDO.java
1 package cn.iocoder.yudao.module.promotion.dal.dataobject.reward; 1 package cn.iocoder.yudao.module.promotion.dal.dataobject.reward;
2 2
  3 +import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; 4 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  5 +import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler;
4 import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum; 6 import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum;
5 import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum; 7 import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum;
6 import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; 8 import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;
@@ -8,10 +10,11 @@ import com.baomidou.mybatisplus.annotation.KeySequence; @@ -8,10 +10,11 @@ import com.baomidou.mybatisplus.annotation.KeySequence;
8 import com.baomidou.mybatisplus.annotation.TableField; 10 import com.baomidou.mybatisplus.annotation.TableField;
9 import com.baomidou.mybatisplus.annotation.TableId; 11 import com.baomidou.mybatisplus.annotation.TableId;
10 import com.baomidou.mybatisplus.annotation.TableName; 12 import com.baomidou.mybatisplus.annotation.TableName;
11 -import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; 13 +import com.baomidou.mybatisplus.extension.handlers.AbstractJsonTypeHandler;
12 import lombok.Data; 14 import lombok.Data;
13 import lombok.EqualsAndHashCode; 15 import lombok.EqualsAndHashCode;
14 16
  17 +import java.io.Serializable;
15 import java.util.Date; 18 import java.util.Date;
16 import java.util.List; 19 import java.util.List;
17 20
@@ -68,19 +71,19 @@ public class RewardActivityDO extends BaseDO { @@ -68,19 +71,19 @@ public class RewardActivityDO extends BaseDO {
68 /** 71 /**
69 * 商品 SPU 编号的数组 72 * 商品 SPU 编号的数组
70 */ 73 */
71 - @TableField(typeHandler = JacksonTypeHandler.class) 74 + @TableField(typeHandler = LongListTypeHandler.class)
72 private List<Long> productSpuIds; 75 private List<Long> productSpuIds;
73 /** 76 /**
74 * 优惠规则的数组 77 * 优惠规则的数组
75 */ 78 */
76 - @TableField(typeHandler = JacksonTypeHandler.class) 79 + @TableField(typeHandler = RuleTypeHandler.class)
77 private List<Rule> rules; 80 private List<Rule> rules;
78 81
79 /** 82 /**
80 * 优惠规则 83 * 优惠规则
81 */ 84 */
82 @Data 85 @Data
83 - public static class Rule { 86 + public static class Rule implements Serializable {
84 87
85 /** 88 /**
86 * 优惠门槛 89 * 优惠门槛
@@ -112,5 +115,19 @@ public class RewardActivityDO extends BaseDO { @@ -112,5 +115,19 @@ public class RewardActivityDO extends BaseDO {
112 115
113 } 116 }
114 117
  118 + // TODO @芋艿:可以找一些新的思路
  119 + public static class RuleTypeHandler extends AbstractJsonTypeHandler<List<Rule>> {
  120 +
  121 + @Override
  122 + protected List<Rule> parse(String json) {
  123 + return JsonUtils.parseArray(json, Rule.class);
  124 + }
  125 +
  126 + @Override
  127 + protected String toJson(List<Rule> obj) {
  128 + return JsonUtils.toJsonString(obj);
  129 + }
  130 +
  131 + }
115 132
116 } 133 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityService.java
@@ -7,8 +7,6 @@ import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivi @@ -7,8 +7,6 @@ import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivi
7 import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; 7 import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO;
8 8
9 import javax.validation.Valid; 9 import javax.validation.Valid;
10 -import java.util.Collection;  
11 -import java.util.List;  
12 import java.util.Map; 10 import java.util.Map;
13 import java.util.Set; 11 import java.util.Set;
14 12
@@ -39,7 +37,7 @@ public interface RewardActivityService { @@ -39,7 +37,7 @@ public interface RewardActivityService {
39 * 37 *
40 * @param id 编号 38 * @param id 编号
41 */ 39 */
42 - void deleteRewardActivity(Integer id); 40 + void deleteRewardActivity(Long id);
43 41
44 /** 42 /**
45 * 获得满减送活动 43 * 获得满减送活动
@@ -47,15 +45,7 @@ public interface RewardActivityService { @@ -47,15 +45,7 @@ public interface RewardActivityService {
47 * @param id 编号 45 * @param id 编号
48 * @return 满减送活动 46 * @return 满减送活动
49 */ 47 */
50 - RewardActivityDO getRewardActivity(Integer id);  
51 -  
52 - /**  
53 - * 获得满减送活动列表  
54 - *  
55 - * @param ids 编号  
56 - * @return 满减送活动列表  
57 - */  
58 - List<RewardActivityDO> getRewardActivityList(Collection<Integer> ids); 48 + RewardActivityDO getRewardActivity(Long id);
59 49
60 /** 50 /**
61 * 获得满减送活动分页 51 * 获得满减送活动分页
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityServiceImpl.java
1 package cn.iocoder.yudao.module.promotion.service.reward; 1 package cn.iocoder.yudao.module.promotion.service.reward;
2 2
  3 +import cn.hutool.core.collection.CollUtil;
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityCreateReqVO; 5 import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityCreateReqVO;
5 import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO; 6 import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO;
@@ -7,6 +8,7 @@ import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivi @@ -7,6 +8,7 @@ import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivi
7 import cn.iocoder.yudao.module.promotion.convert.reward.RewardActivityConvert; 8 import cn.iocoder.yudao.module.promotion.convert.reward.RewardActivityConvert;
8 import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; 9 import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO;
9 import cn.iocoder.yudao.module.promotion.dal.mysql.reward.RewardActivityMapper; 10 import cn.iocoder.yudao.module.promotion.dal.mysql.reward.RewardActivityMapper;
  11 +import cn.iocoder.yudao.module.promotion.util.PromotionUtils;
10 import org.springframework.stereotype.Service; 12 import org.springframework.stereotype.Service;
11 import org.springframework.validation.annotation.Validated; 13 import org.springframework.validation.annotation.Validated;
12 14
@@ -18,6 +20,7 @@ import java.util.Set; @@ -18,6 +20,7 @@ import java.util.Set;
18 20
19 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 21 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
20 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.REWARD_ACTIVITY_NOT_EXISTS; 22 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.REWARD_ACTIVITY_NOT_EXISTS;
  23 +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.REWARD_ACTIVITY_SPU_CONFLICTS;
21 24
22 /** 25 /**
23 * 满减送活动 Service 实现类 26 * 满减送活动 Service 实现类
@@ -33,8 +36,12 @@ public class RewardActivityServiceImpl implements RewardActivityService { @@ -33,8 +36,12 @@ public class RewardActivityServiceImpl implements RewardActivityService {
33 36
34 @Override 37 @Override
35 public Long createRewardActivity(RewardActivityCreateReqVO createReqVO) { 38 public Long createRewardActivity(RewardActivityCreateReqVO createReqVO) {
  39 + // 校验商品是否冲突
  40 + validateRewardActivitySpuConflicts(null, createReqVO.getProductSpuIds());
  41 +
36 // 插入 42 // 插入
37 - RewardActivityDO rewardActivity = RewardActivityConvert.INSTANCE.convert(createReqVO); 43 + RewardActivityDO rewardActivity = RewardActivityConvert.INSTANCE.convert(createReqVO)
  44 + .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getStartTime(), createReqVO.getEndTime()));
38 rewardActivityMapper.insert(rewardActivity); 45 rewardActivityMapper.insert(rewardActivity);
39 // 返回 46 // 返回
40 return rewardActivity.getId(); 47 return rewardActivity.getId();
@@ -43,34 +50,64 @@ public class RewardActivityServiceImpl implements RewardActivityService { @@ -43,34 +50,64 @@ public class RewardActivityServiceImpl implements RewardActivityService {
43 @Override 50 @Override
44 public void updateRewardActivity(RewardActivityUpdateReqVO updateReqVO) { 51 public void updateRewardActivity(RewardActivityUpdateReqVO updateReqVO) {
45 // 校验存在 52 // 校验存在
46 - this.validateRewardActivityExists(updateReqVO.getId()); 53 + validateRewardActivityExists(updateReqVO.getId());
  54 + validateRewardActivitySpuConflicts(updateReqVO.getId(), updateReqVO.getProductSpuIds());
  55 +
47 // 更新 56 // 更新
48 - RewardActivityDO updateObj = RewardActivityConvert.INSTANCE.convert(updateReqVO); 57 + RewardActivityDO updateObj = RewardActivityConvert.INSTANCE.convert(updateReqVO)
  58 + .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getStartTime(), updateReqVO.getEndTime()));
49 rewardActivityMapper.updateById(updateObj); 59 rewardActivityMapper.updateById(updateObj);
50 } 60 }
51 61
52 @Override 62 @Override
53 - public void deleteRewardActivity(Integer id) { 63 + public void deleteRewardActivity(Long id) {
54 // 校验存在 64 // 校验存在
55 - this.validateRewardActivityExists(id); 65 + validateRewardActivityExists(id);
56 // 删除 66 // 删除
57 rewardActivityMapper.deleteById(id); 67 rewardActivityMapper.deleteById(id);
58 } 68 }
59 69
60 - private void validateRewardActivityExists(Integer id) { 70 + private void validateRewardActivityExists(Long id) {
61 if (rewardActivityMapper.selectById(id) == null) { 71 if (rewardActivityMapper.selectById(id) == null) {
62 throw exception(REWARD_ACTIVITY_NOT_EXISTS); 72 throw exception(REWARD_ACTIVITY_NOT_EXISTS);
63 } 73 }
64 } 74 }
65 75
66 - @Override  
67 - public RewardActivityDO getRewardActivity(Integer id) {  
68 - return rewardActivityMapper.selectById(id); 76 + /**
  77 + * 校验商品参加的活动是否冲突
  78 + *
  79 + * @param id 活动编号
  80 + * @param spuIds 商品 SPU 编号数组
  81 + */
  82 + private void validateRewardActivitySpuConflicts(Long id, Collection<Long> spuIds) {
  83 + if (CollUtil.isEmpty(spuIds)) {
  84 + return;
  85 + }
  86 + // 查询商品参加的活动
  87 + List<RewardActivityDO> rewardActivityList = getRewardActivityListBySpuIds(spuIds);
  88 + if (id != null) { // 排除活动
  89 + rewardActivityList.removeIf(activity -> id.equals(activity.getId()));
  90 + }
  91 + // 如果非空,则说明冲突
  92 + if (CollUtil.isNotEmpty(rewardActivityList)) {
  93 + throw exception(REWARD_ACTIVITY_SPU_CONFLICTS);
  94 + }
  95 + }
  96 +
  97 + /**
  98 + * 获得商品参加的满减送活动的数组
  99 + *
  100 + * @param spuIds 商品 SPU 编号数组
  101 + * @return 商品参加的满减送活动的数组
  102 + */
  103 + private List<RewardActivityDO> getRewardActivityListBySpuIds(Collection<Long> spuIds) {
  104 + List<RewardActivityDO> list = rewardActivityMapper.selectList();
  105 + return CollUtil.filter(list, activity -> CollUtil.containsAny(activity.getProductSpuIds(), spuIds));
69 } 106 }
70 107
71 @Override 108 @Override
72 - public List<RewardActivityDO> getRewardActivityList(Collection<Integer> ids) {  
73 - return rewardActivityMapper.selectBatchIds(ids); 109 + public RewardActivityDO getRewardActivity(Long id) {
  110 + return rewardActivityMapper.selectById(id);
74 } 111 }
75 112
76 @Override 113 @Override
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/util/PromotionUtils.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.util;
  2 +
  3 +import cn.iocoder.yudao.framework.common.util.date.DateUtils;
  4 +import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum;
  5 +
  6 +import java.util.Date;
  7 +
  8 +/**
  9 + * 活动工具类
  10 + *
  11 + * @author 芋道源码
  12 + */
  13 +public class PromotionUtils {
  14 +
  15 + /**
  16 + * 根据时间,计算活动状态
  17 + *
  18 + * @param startTime 开始时间
  19 + * @param endTime 结束时间
  20 + * @return 活动状态
  21 + */
  22 + public static Integer calculateActivityStatus(Date startTime, Date endTime) {
  23 + if (DateUtils.beforeNow(endTime)) {
  24 + return PromotionActivityStatusEnum.END.getStatus();
  25 + }
  26 + if (DateUtils.afterNow(startTime)) {
  27 + return PromotionActivityStatusEnum.WAIT.getStatus();
  28 + }
  29 + return PromotionActivityStatusEnum.RUN.getStatus();
  30 + }
  31 +
  32 +}
yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/rewardactivity/RewardActivityServiceImplTest.java renamed to yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityServiceImplTest.java
1 -package cn.iocoder.yudao.module.promotion.service.rewardactivity;  
2 -  
3 -import cn.iocoder.yudao.module.promotion.service.reward.RewardActivityServiceImpl;  
4 -import org.junit.jupiter.api.Disabled;  
5 -import org.junit.jupiter.api.Test;  
6 -  
7 -import javax.annotation.Resource; 1 +package cn.iocoder.yudao.module.promotion.service.reward;
8 2
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
9 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; 4 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
10 -  
11 -import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.*;  
12 -import cn.iocoder.yudao.module.promotion.dal.dataobject.rewardactivity.RewardActivityDO; 5 +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityCreateReqVO;
  6 +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO;
  7 +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityUpdateReqVO;
  8 +import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO;
13 import cn.iocoder.yudao.module.promotion.dal.mysql.reward.RewardActivityMapper; 9 import cn.iocoder.yudao.module.promotion.dal.mysql.reward.RewardActivityMapper;
14 -import cn.iocoder.yudao.framework.common.pojo.PageResult;  
15 - 10 +import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum;
  11 +import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum;
  12 +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;
  13 +import org.junit.jupiter.api.Test;
16 import org.springframework.context.annotation.Import; 14 import org.springframework.context.annotation.Import;
17 -import java.util.*;  
18 15
19 -import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;  
20 -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;  
21 -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;  
22 -import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*; 16 +import javax.annotation.Resource;
  17 +import java.time.Duration;
  18 +
  19 +import static cn.hutool.core.util.RandomUtil.randomEle;
  20 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.addTime;
  21 +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
  22 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
  23 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
  24 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
  25 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
  26 +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.REWARD_ACTIVITY_NOT_EXISTS;
23 import static org.junit.jupiter.api.Assertions.*; 27 import static org.junit.jupiter.api.Assertions.*;
24 28
25 /** 29 /**
@@ -39,15 +43,24 @@ public class RewardActivityServiceImplTest extends BaseDbUnitTest { @@ -39,15 +43,24 @@ public class RewardActivityServiceImplTest extends BaseDbUnitTest {
39 @Test 43 @Test
40 public void testCreateRewardActivity_success() { 44 public void testCreateRewardActivity_success() {
41 // 准备参数 45 // 准备参数
42 - RewardActivityCreateReqVO reqVO = randomPojo(RewardActivityCreateReqVO.class); 46 + RewardActivityCreateReqVO reqVO = randomPojo(RewardActivityCreateReqVO.class, o -> {
  47 + o.setConditionType(randomEle(PromotionConditionTypeEnum.values()).getType());
  48 + o.setProductScope(randomEle(PromotionProductScopeEnum.values()).getScope());
  49 + // 用于触发进行中的状态
  50 + o.setStartTime(addTime(Duration.ofDays(1))).setEndTime(addTime(Duration.ofDays(2)));
  51 + });
43 52
44 // 调用 53 // 调用
45 - Integer rewardActivityId = rewardActivityService.createRewardActivity(reqVO); 54 + Long rewardActivityId = rewardActivityService.createRewardActivity(reqVO);
46 // 断言 55 // 断言
47 assertNotNull(rewardActivityId); 56 assertNotNull(rewardActivityId);
48 // 校验记录的属性是否正确 57 // 校验记录的属性是否正确
49 RewardActivityDO rewardActivity = rewardActivityMapper.selectById(rewardActivityId); 58 RewardActivityDO rewardActivity = rewardActivityMapper.selectById(rewardActivityId);
50 - assertPojoEquals(reqVO, rewardActivity); 59 + assertPojoEquals(reqVO, rewardActivity, "rules");
  60 + assertEquals(rewardActivity.getStatus(), PromotionActivityStatusEnum.WAIT.getStatus());
  61 + for (int i = 0; i < reqVO.getRules().size(); i++) {
  62 + assertPojoEquals(reqVO.getRules().get(i), rewardActivity.getRules().get(i));
  63 + }
51 } 64 }
52 65
53 @Test 66 @Test
@@ -58,13 +71,21 @@ public class RewardActivityServiceImplTest extends BaseDbUnitTest { @@ -58,13 +71,21 @@ public class RewardActivityServiceImplTest extends BaseDbUnitTest {
58 // 准备参数 71 // 准备参数
59 RewardActivityUpdateReqVO reqVO = randomPojo(RewardActivityUpdateReqVO.class, o -> { 72 RewardActivityUpdateReqVO reqVO = randomPojo(RewardActivityUpdateReqVO.class, o -> {
60 o.setId(dbRewardActivity.getId()); // 设置更新的 ID 73 o.setId(dbRewardActivity.getId()); // 设置更新的 ID
  74 + o.setConditionType(randomEle(PromotionConditionTypeEnum.values()).getType());
  75 + o.setProductScope(randomEle(PromotionProductScopeEnum.values()).getScope());
  76 + // 用于触发进行中的状态
  77 + o.setStartTime(addTime(Duration.ofDays(1))).setEndTime(addTime(Duration.ofDays(2)));
61 }); 78 });
62 79
63 // 调用 80 // 调用
64 rewardActivityService.updateRewardActivity(reqVO); 81 rewardActivityService.updateRewardActivity(reqVO);
65 // 校验是否更新正确 82 // 校验是否更新正确
66 RewardActivityDO rewardActivity = rewardActivityMapper.selectById(reqVO.getId()); // 获取最新的 83 RewardActivityDO rewardActivity = rewardActivityMapper.selectById(reqVO.getId()); // 获取最新的
67 - assertPojoEquals(reqVO, rewardActivity); 84 + assertPojoEquals(reqVO, rewardActivity, "rules");
  85 + assertEquals(rewardActivity.getStatus(), PromotionActivityStatusEnum.WAIT.getStatus());
  86 + for (int i = 0; i < reqVO.getRules().size(); i++) {
  87 + assertPojoEquals(reqVO.getRules().get(i), rewardActivity.getRules().get(i));
  88 + }
68 } 89 }
69 90
70 @Test 91 @Test
@@ -82,7 +103,7 @@ public class RewardActivityServiceImplTest extends BaseDbUnitTest { @@ -82,7 +103,7 @@ public class RewardActivityServiceImplTest extends BaseDbUnitTest {
82 RewardActivityDO dbRewardActivity = randomPojo(RewardActivityDO.class); 103 RewardActivityDO dbRewardActivity = randomPojo(RewardActivityDO.class);
83 rewardActivityMapper.insert(dbRewardActivity);// @Sql: 先插入出一条存在的数据 104 rewardActivityMapper.insert(dbRewardActivity);// @Sql: 先插入出一条存在的数据
84 // 准备参数 105 // 准备参数
85 - Integer id = dbRewardActivity.getId(); 106 + Long id = dbRewardActivity.getId();
86 107
87 // 调用 108 // 调用
88 rewardActivityService.deleteRewardActivity(id); 109 rewardActivityService.deleteRewardActivity(id);
@@ -93,61 +114,35 @@ public class RewardActivityServiceImplTest extends BaseDbUnitTest { @@ -93,61 +114,35 @@ public class RewardActivityServiceImplTest extends BaseDbUnitTest {
93 @Test 114 @Test
94 public void testDeleteRewardActivity_notExists() { 115 public void testDeleteRewardActivity_notExists() {
95 // 准备参数 116 // 准备参数
96 - Integer id = randomIntegerId(); 117 + Long id = randomLongId();
97 118
98 // 调用, 并断言异常 119 // 调用, 并断言异常
99 assertServiceException(() -> rewardActivityService.deleteRewardActivity(id), REWARD_ACTIVITY_NOT_EXISTS); 120 assertServiceException(() -> rewardActivityService.deleteRewardActivity(id), REWARD_ACTIVITY_NOT_EXISTS);
100 } 121 }
101 122
102 @Test 123 @Test
103 - @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解  
104 public void testGetRewardActivityPage() { 124 public void testGetRewardActivityPage() {
105 // mock 数据 125 // mock 数据
106 RewardActivityDO dbRewardActivity = randomPojo(RewardActivityDO.class, o -> { // 等会查询到 126 RewardActivityDO dbRewardActivity = randomPojo(RewardActivityDO.class, o -> { // 等会查询到
107 - o.setName(null);  
108 - o.setStatus(null); 127 + o.setName("芋艿");
  128 + o.setStatus(PromotionActivityStatusEnum.CLOSE.getStatus());
109 }); 129 });
110 rewardActivityMapper.insert(dbRewardActivity); 130 rewardActivityMapper.insert(dbRewardActivity);
111 // 测试 name 不匹配 131 // 测试 name 不匹配
112 - rewardActivityMapper.insert(cloneIgnoreId(dbRewardActivity, o -> o.setName(null))); 132 + rewardActivityMapper.insert(cloneIgnoreId(dbRewardActivity, o -> o.setName("土豆")));
113 // 测试 status 不匹配 133 // 测试 status 不匹配
114 - rewardActivityMapper.insert(cloneIgnoreId(dbRewardActivity, o -> o.setStatus(null))); 134 + rewardActivityMapper.insert(cloneIgnoreId(dbRewardActivity, o -> o.setStatus(PromotionActivityStatusEnum.RUN.getStatus())));
115 // 准备参数 135 // 准备参数
116 RewardActivityPageReqVO reqVO = new RewardActivityPageReqVO(); 136 RewardActivityPageReqVO reqVO = new RewardActivityPageReqVO();
117 - reqVO.setName(null);  
118 - reqVO.setStatus(null); 137 + reqVO.setName("芋艿");
  138 + reqVO.setStatus(PromotionActivityStatusEnum.CLOSE.getStatus());
119 139
120 // 调用 140 // 调用
121 PageResult<RewardActivityDO> pageResult = rewardActivityService.getRewardActivityPage(reqVO); 141 PageResult<RewardActivityDO> pageResult = rewardActivityService.getRewardActivityPage(reqVO);
122 // 断言 142 // 断言
123 assertEquals(1, pageResult.getTotal()); 143 assertEquals(1, pageResult.getTotal());
124 assertEquals(1, pageResult.getList().size()); 144 assertEquals(1, pageResult.getList().size());
125 - assertPojoEquals(dbRewardActivity, pageResult.getList().get(0));  
126 - }  
127 -  
128 - @Test  
129 - @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解  
130 - public void testGetRewardActivityList() {  
131 - // mock 数据  
132 - RewardActivityDO dbRewardActivity = randomPojo(RewardActivityDO.class, o -> { // 等会查询到  
133 - o.setName(null);  
134 - o.setStatus(null);  
135 - });  
136 - rewardActivityMapper.insert(dbRewardActivity);  
137 - // 测试 name 不匹配  
138 - rewardActivityMapper.insert(cloneIgnoreId(dbRewardActivity, o -> o.setName(null)));  
139 - // 测试 status 不匹配  
140 - rewardActivityMapper.insert(cloneIgnoreId(dbRewardActivity, o -> o.setStatus(null)));  
141 - // 准备参数  
142 - RewardActivityExportReqVO reqVO = new RewardActivityExportReqVO();  
143 - reqVO.setName(null);  
144 - reqVO.setStatus(null);  
145 -  
146 - // 调用  
147 - List<RewardActivityDO> list = rewardActivityService.getRewardActivityList(reqVO);  
148 - // 断言  
149 - assertEquals(1, list.size());  
150 - assertPojoEquals(dbRewardActivity, list.get(0)); 145 + assertPojoEquals(dbRewardActivity, pageResult.getList().get(0), "rules");
151 } 146 }
152 147
153 } 148 }
yudao-module-mall/yudao-module-promotion-biz/src/test/resources/sql/clean.sql
1 DELETE FROM "market_activity"; 1 DELETE FROM "market_activity";
2 DELETE FROM "promotion_coupon_template"; 2 DELETE FROM "promotion_coupon_template";
  3 +DELETE FROM "promotion_coupon";
  4 +DELETE FROM "promotion_reward_activity";
yudao-module-mall/yudao-module-promotion-biz/src/test/resources/sql/create_tables.sql
@@ -46,3 +46,48 @@ CREATE TABLE IF NOT EXISTS &quot;promotion_coupon_template&quot; ( @@ -46,3 +46,48 @@ CREATE TABLE IF NOT EXISTS &quot;promotion_coupon_template&quot; (
46 "deleted" bit NOT NULL DEFAULT FALSE, 46 "deleted" bit NOT NULL DEFAULT FALSE,
47 PRIMARY KEY ("id") 47 PRIMARY KEY ("id")
48 ) COMMENT '优惠劵模板'; 48 ) COMMENT '优惠劵模板';
  49 +
  50 +CREATE TABLE IF NOT EXISTS "promotion_coupon" (
  51 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  52 + "template_id" bigint NOT NULL,
  53 + "name" varchar NOT NULL,
  54 + "status" int NOT NULL,
  55 + "user_id" bigint NOT NULL,
  56 + "take_type" int NOT NULL,
  57 + "useprice" int NOT NULL,
  58 + "valid_start_time" datetime NOT NULL,
  59 + "valid_end_time" datetime NOT NULL,
  60 + "product_scope" int NOT NULL,
  61 + "product_spu_ids" varchar,
  62 + "discount_type" int NOT NULL,
  63 + "discount_percent" int,
  64 + "discount_price" int,
  65 + "discount_limit_price" int,
  66 + "use_order_id" bigint,
  67 + "use_time" datetime,
  68 + "creator" varchar DEFAULT '',
  69 + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  70 + "updater" varchar DEFAULT '',
  71 + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  72 + "deleted" bit NOT NULL DEFAULT FALSE,
  73 + PRIMARY KEY ("id")
  74 +) COMMENT '优惠劵';
  75 +
  76 +CREATE TABLE IF NOT EXISTS "promotion_reward_activity" (
  77 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  78 + "name" varchar NOT NULL,
  79 + "status" int NOT NULL,
  80 + "start_time" datetime NOT NULL,
  81 + "end_time" datetime NOT NULL,
  82 + "remark" varchar,
  83 + "condition_type" int NOT NULL,
  84 + "product_scope" int NOT NULL,
  85 + "product_spu_ids" varchar,
  86 + "rules" varchar,
  87 + "creator" varchar DEFAULT '',
  88 + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  89 + "updater" varchar DEFAULT '',
  90 + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  91 + "deleted" bit NOT NULL DEFAULT FALSE,
  92 + PRIMARY KEY ("id")
  93 +) COMMENT '满减送活动';