!604 优惠券优化

Merge pull request !604 from 疯狂的世界/coupon
This commit is contained in:
芋道源码 2023-09-03 09:48:21 +00:00 committed by Gitee
commit e67b62f2f6
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
11 changed files with 65 additions and 20 deletions

View File

@ -17,7 +17,7 @@ import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Documented @Documented
@Constraint( @Constraint(
validatedBy = InEnumValidator.class validatedBy = {InEnumValidator.class, InEnumCollectionValidator.class}
) )
public @interface InEnum { public @interface InEnum {

View File

@ -0,0 +1,42 @@
package cn.iocoder.yudao.framework.common.validation;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public class InEnumCollectionValidator implements ConstraintValidator<InEnum, Collection<Integer>> {
private List<Integer> values;
@Override
public void initialize(InEnum annotation) {
IntArrayValuable[] values = annotation.value().getEnumConstants();
if (values.length == 0) {
this.values = Collections.emptyList();
} else {
this.values = Arrays.stream(values[0].array()).boxed().collect(Collectors.toList());
}
}
@Override
public boolean isValid(Collection<Integer> list, ConstraintValidatorContext context) {
// 校验通过
if (CollUtil.containsAll(values, list)) {
return true;
}
// 校验不通过自定义提示语句因为注解上的 value 是枚举类无法获得枚举类的实际值
context.disableDefaultConstraintViolation(); // 禁用默认的 message 的值
context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate()
.replaceAll("\\{value}", CollUtil.join(list, ","))).addConstraintViolation(); // 重新添加错误提示语句
return false;
}
}

View File

@ -71,9 +71,9 @@ public class CouponRespDTO {
*/ */
private Integer productScope; private Integer productScope;
/** /**
* 商品 SPU 编号的数组 * 商品范围编号的数组
*/ */
private List<Long> productSpuIds; private List<Long> productScopeValues;
// ========== 使用规则 END ========== // ========== 使用规则 END ==========
// ========== 使用效果 BEGIN ========== // ========== 使用效果 BEGIN ==========

View File

@ -67,8 +67,8 @@ public class CouponBaseVO {
@InEnum(PromotionProductScopeEnum.class) @InEnum(PromotionProductScopeEnum.class)
private Integer productScope; private Integer productScope;
@Schema(description = "商品 SPU 编号的数组", example = "1,3") @Schema(description = "商品范围编号的数组", example = "1,3")
private List<Long> productSpuIds; private List<Long> productScopeValues;
// ========== 使用规则 END ========== // ========== 使用规则 END ==========
// ========== 使用效果 BEGIN ========== // ========== 使用效果 BEGIN ==========

View File

@ -54,8 +54,8 @@ public class CouponTemplateBaseVO {
@InEnum(PromotionProductScopeEnum.class) @InEnum(PromotionProductScopeEnum.class)
private Integer productScope; private Integer productScope;
@Schema(description = "商品 SPU 编号的数组", example = "1,3") @Schema(description = "商品范围编号的数组", example = "1,3")
private List<Long> productSpuIds; private List<Long> productScopeValues;
@Schema(description = "生效日期类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @Schema(description = "生效日期类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "生效日期类型不能为空") @NotNull(message = "生效日期类型不能为空")
@ -95,11 +95,11 @@ public class CouponTemplateBaseVO {
@Schema(description = "折扣上限", example = "100") // 单位仅在 discountType PERCENT 使用 @Schema(description = "折扣上限", example = "100") // 单位仅在 discountType PERCENT 使用
private Integer discountLimitPrice; private Integer discountLimitPrice;
@AssertTrue(message = "商品 SPU 编号的数组不能为空") @AssertTrue(message = "商品范围编号的数组不能为空")
@JsonIgnore @JsonIgnore
public boolean isProductSpuIdsValid() { public boolean isProductScopeValuesValid() {
return Objects.equals(productScope, PromotionProductScopeEnum.ALL.getScope()) // 全部范围时可以为空 return Objects.equals(productScope, PromotionProductScopeEnum.ALL.getScope()) // 全部范围时可以为空
|| CollUtil.isNotEmpty(productSpuIds); || CollUtil.isNotEmpty(productScopeValues);
} }
@AssertTrue(message = "生效开始时间不能为空") @AssertTrue(message = "生效开始时间不能为空")

View File

@ -28,8 +28,8 @@ public class AppCouponTemplateRespVO {
// @InEnum(PromotionProductScopeEnum.class) // @InEnum(PromotionProductScopeEnum.class)
// private Integer productScope; // private Integer productScope;
// //
// @Schema(description = "商品 SPU 编号的数组", example = "1,3") // @Schema(description = "商品范围编号的数组", example = "1,3")
// private List<Long> productSpuIds; // private List<Long> productScopeValues;
@Schema(description = "生效日期类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @Schema(description = "生效日期类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Integer validityType; private Integer validityType;

View File

@ -33,7 +33,7 @@ public interface CouponConvert {
.setTakeType(template.getTakeType()) .setTakeType(template.getTakeType())
.setUsePrice(template.getUsePrice()) .setUsePrice(template.getUsePrice())
.setProductScope(template.getProductScope()) .setProductScope(template.getProductScope())
.setProductSpuIds(template.getProductSpuIds()) .setProductScopeValues(template.getProductScopeValues())
.setDiscountType(template.getDiscountType()) .setDiscountType(template.getDiscountType())
.setDiscountPercent(template.getDiscountPercent()) .setDiscountPercent(template.getDiscountPercent())
.setDiscountPrice(template.getDiscountPrice()) .setDiscountPrice(template.getDiscountPrice())

View File

@ -89,12 +89,12 @@ public class CouponDO extends BaseDO {
*/ */
private Integer productScope; private Integer productScope;
/** /**
* 商品 SPU 编号的数组 * 商品范围编号的数组
* *
* 冗余 {@link CouponTemplateDO#getProductSpuIds()} * 冗余 {@link CouponTemplateDO#getProductScopeValues()}
*/ */
@TableField(typeHandler = LongListTypeHandler.class) @TableField(typeHandler = LongListTypeHandler.class)
private List<Long> productSpuIds; private List<Long> productScopeValues;
// ========== 使用规则 END ========== // ========== 使用规则 END ==========
// ========== 使用效果 BEGIN ========== // ========== 使用效果 BEGIN ==========

View File

@ -85,10 +85,10 @@ public class CouponTemplateDO extends BaseDO {
*/ */
private Integer productScope; private Integer productScope;
/** /**
* 商品 SPU 编号的数组 * 商品范围编号的数组
*/ */
@TableField(typeHandler = LongListTypeHandler.class) @TableField(typeHandler = LongListTypeHandler.class)
private List<Long> productSpuIds; private List<Long> productScopeValues;
/** /**
* 生效日期类型 * 生效日期类型
* *

View File

@ -102,7 +102,10 @@ public class TradeCouponPriceCalculator implements TradePriceCalculator {
Predicate<TradePriceCalculateRespBO.OrderItem> matchPredicate = TradePriceCalculateRespBO.OrderItem::getSelected; Predicate<TradePriceCalculateRespBO.OrderItem> matchPredicate = TradePriceCalculateRespBO.OrderItem::getSelected;
if (PromotionProductScopeEnum.SPU.getScope().equals(coupon.getProductScope())) { if (PromotionProductScopeEnum.SPU.getScope().equals(coupon.getProductScope())) {
matchPredicate = matchPredicate // 额外加如下条件 matchPredicate = matchPredicate // 额外加如下条件
.and(orderItem -> coupon.getProductSpuIds().contains(orderItem.getSpuId())); .and(orderItem -> coupon.getProductScopeValues().contains(orderItem.getSpuId()));
} else if (PromotionProductScopeEnum.CATEGORY.getScope().equals(coupon.getProductScope())) {
matchPredicate = matchPredicate // 额外加如下条件
.and(orderItem -> coupon.getProductScopeValues().contains(orderItem.getCategoryId()));
} }
return filterList(result.getItems(), matchPredicate); return filterList(result.getItems(), matchPredicate);
} }

View File

@ -65,7 +65,7 @@ public class TradeCouponPriceCalculatorTest extends BaseMockitoUnitTest {
// mock 方法优惠劵 Coupon 信息 // mock 方法优惠劵 Coupon 信息
CouponRespDTO coupon = randomPojo(CouponRespDTO.class, o -> o.setId(1024L).setName("程序员节") CouponRespDTO coupon = randomPojo(CouponRespDTO.class, o -> o.setId(1024L).setName("程序员节")
.setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductSpuIds(asList(1L, 2L)) .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductScopeValues(asList(1L, 2L))
.setUsePrice(350).setDiscountType(PromotionDiscountTypeEnum.PERCENT.getType()) .setUsePrice(350).setDiscountType(PromotionDiscountTypeEnum.PERCENT.getType())
.setDiscountPercent(50).setDiscountLimitPrice(70)); .setDiscountPercent(50).setDiscountLimitPrice(70));
when(couponApi.validateCoupon(eq(new CouponValidReqDTO().setId(1024L).setUserId(233L)))).thenReturn(coupon); when(couponApi.validateCoupon(eq(new CouponValidReqDTO().setId(1024L).setUserId(233L)))).thenReturn(coupon);