Commit 2c39405bcea22737be3a49beb23cc67fa7a99c7d
1 parent
8ae8a4a6
promotion:完善的优惠卷的实体
Showing
5 changed files
with
93 additions
and
57 deletions
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponStatusEnum.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.promotion.enums.coupon; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; | ||
| 4 | +import lombok.AllArgsConstructor; | ||
| 5 | +import lombok.Getter; | ||
| 6 | + | ||
| 7 | +import java.util.Arrays; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * 优惠劵状态枚举 | ||
| 11 | + * | ||
| 12 | + * @author 芋道源码 | ||
| 13 | + */ | ||
| 14 | +@AllArgsConstructor | ||
| 15 | +@Getter | ||
| 16 | +public enum CouponStatusEnum implements IntArrayValuable { | ||
| 17 | + | ||
| 18 | + UNUSED(1, "未使用"), | ||
| 19 | + USED(2, "已使用"), | ||
| 20 | + EXPIRE(3, "已过期"), | ||
| 21 | + ; | ||
| 22 | + | ||
| 23 | + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CouponStatusEnum::getValue).toArray(); | ||
| 24 | + | ||
| 25 | + /** | ||
| 26 | + * 值 | ||
| 27 | + */ | ||
| 28 | + private final Integer value; | ||
| 29 | + /** | ||
| 30 | + * 名字 | ||
| 31 | + */ | ||
| 32 | + private final String name; | ||
| 33 | + | ||
| 34 | + @Override | ||
| 35 | + public int[] array() { | ||
| 36 | + return ARRAYS; | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | +} |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponDO.java
| 1 | package cn.iocoder.yudao.module.promotion.dal.dataobject.coupon; | 1 | package cn.iocoder.yudao.module.promotion.dal.dataobject.coupon; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | 3 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| 4 | +import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler; | ||
| 5 | +import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; | ||
| 4 | import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; | 6 | import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; |
| 7 | +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum; | ||
| 8 | +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum; | ||
| 5 | import com.baomidou.mybatisplus.annotation.KeySequence; | 9 | import com.baomidou.mybatisplus.annotation.KeySequence; |
| 6 | import com.baomidou.mybatisplus.annotation.TableField; | 10 | import com.baomidou.mybatisplus.annotation.TableField; |
| 7 | import com.baomidou.mybatisplus.annotation.TableName; | 11 | import com.baomidou.mybatisplus.annotation.TableName; |
| 8 | -import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; | ||
| 9 | import lombok.Data; | 12 | import lombok.Data; |
| 10 | import lombok.EqualsAndHashCode; | 13 | import lombok.EqualsAndHashCode; |
| 11 | 14 | ||
| @@ -14,9 +17,11 @@ import java.util.List; | @@ -14,9 +17,11 @@ import java.util.List; | ||
| 14 | 17 | ||
| 15 | /** | 18 | /** |
| 16 | * 优惠劵 DO | 19 | * 优惠劵 DO |
| 20 | + * | ||
| 21 | + * @author 芋道源码 | ||
| 17 | */ | 22 | */ |
| 18 | @TableName(value = "promotion_coupon", autoResultMap = true) | 23 | @TableName(value = "promotion_coupon", autoResultMap = true) |
| 19 | -@KeySequence("promotion_coupo_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 | 24 | +@KeySequence("promotion_coupon_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 |
| 20 | @Data | 25 | @Data |
| 21 | @EqualsAndHashCode(callSuper = true) | 26 | @EqualsAndHashCode(callSuper = true) |
| 22 | public class CouponDO extends BaseDO { | 27 | public class CouponDO extends BaseDO { |
| @@ -35,21 +40,13 @@ public class CouponDO extends BaseDO { | @@ -35,21 +40,13 @@ public class CouponDO extends BaseDO { | ||
| 35 | /** | 40 | /** |
| 36 | * 优惠劵名 | 41 | * 优惠劵名 |
| 37 | * | 42 | * |
| 38 | - * 冗余自 {@link CouponTemplateDO} 的 title | ||
| 39 | - * | ||
| 40 | - * TODO 芋艿,暂时不考虑冗余的更新 | 43 | + * 冗余 {@link CouponTemplateDO#getName()} |
| 41 | */ | 44 | */ |
| 42 | - private String title; | ||
| 43 | -// /** | ||
| 44 | -// * 核销码 | ||
| 45 | -// */ | ||
| 46 | -// private String verifyCode; | 45 | + private String name; |
| 47 | /** | 46 | /** |
| 48 | * 优惠码状态 | 47 | * 优惠码状态 |
| 49 | * | 48 | * |
| 50 | - * 1-未使用 | ||
| 51 | - * 2-已使用 | ||
| 52 | - * 3-已失效 | 49 | + * 枚举 {@link CouponStatusEnum} |
| 53 | */ | 50 | */ |
| 54 | private Integer status; | 51 | private Integer status; |
| 55 | 52 | ||
| @@ -58,13 +55,14 @@ public class CouponDO extends BaseDO { | @@ -58,13 +55,14 @@ public class CouponDO extends BaseDO { | ||
| 58 | // ========== 领取情况 BEGIN ========== | 55 | // ========== 领取情况 BEGIN ========== |
| 59 | /** | 56 | /** |
| 60 | * 用户编号 | 57 | * 用户编号 |
| 58 | + * | ||
| 59 | + * 关联 MemberUserDO 的 id 字段 | ||
| 61 | */ | 60 | */ |
| 62 | - private Integer userId; | 61 | + private Long userId; |
| 63 | /** | 62 | /** |
| 64 | * 领取类型 | 63 | * 领取类型 |
| 65 | * | 64 | * |
| 66 | - * 1 - 用户主动领取 | ||
| 67 | - * 2 - 后台自动发放 | 65 | + * 枚举 {@link CouponTakeTypeEnum} |
| 68 | */ | 66 | */ |
| 69 | private Integer takeType; | 67 | private Integer takeType; |
| 70 | // ========== 领取情况 END ========== | 68 | // ========== 领取情况 END ========== |
| @@ -72,8 +70,10 @@ public class CouponDO extends BaseDO { | @@ -72,8 +70,10 @@ public class CouponDO extends BaseDO { | ||
| 72 | // ========== 使用规则 BEGIN ========== | 70 | // ========== 使用规则 BEGIN ========== |
| 73 | /** | 71 | /** |
| 74 | * 是否设置满多少金额可用,单位:分 | 72 | * 是否设置满多少金额可用,单位:分 |
| 73 | + * | ||
| 74 | + * 冗余 {@link CouponTemplateDO#getUsePrice()} | ||
| 75 | */ | 75 | */ |
| 76 | - private Integer priceAvailable; | 76 | + private Integer usePrice; |
| 77 | /** | 77 | /** |
| 78 | * 生效开始时间 | 78 | * 生效开始时间 |
| 79 | */ | 79 | */ |
| @@ -90,50 +90,49 @@ public class CouponDO extends BaseDO { | @@ -90,50 +90,49 @@ public class CouponDO extends BaseDO { | ||
| 90 | private Integer productScope; | 90 | private Integer productScope; |
| 91 | /** | 91 | /** |
| 92 | * 商品 SPU 编号的数组 | 92 | * 商品 SPU 编号的数组 |
| 93 | + * | ||
| 94 | + * 冗余 {@link CouponTemplateDO#getProductSpuIds()} | ||
| 93 | */ | 95 | */ |
| 94 | - @TableField(typeHandler = JacksonTypeHandler.class) | ||
| 95 | - private List<Long> spuIds; | 96 | + @TableField(typeHandler = LongListTypeHandler.class) |
| 97 | + private List<Long> productSpuIds; | ||
| 96 | // ========== 使用规则 END ========== | 98 | // ========== 使用规则 END ========== |
| 97 | 99 | ||
| 98 | // ========== 使用效果 BEGIN ========== | 100 | // ========== 使用效果 BEGIN ========== |
| 99 | /** | 101 | /** |
| 100 | - * 优惠类型 | 102 | + * 折扣类型 |
| 101 | * | 103 | * |
| 102 | - * 1-代金卷 | ||
| 103 | - * 2-折扣卷 | 104 | + * 冗余 {@link CouponTemplateDO#getDiscountType()} |
| 104 | */ | 105 | */ |
| 105 | - private Integer preferentialType; | 106 | + private Integer discountType; |
| 106 | /** | 107 | /** |
| 107 | - * 折扣 | 108 | + * 折扣百分比 |
| 109 | + * | ||
| 110 | + * 冗余 {@link CouponTemplateDO#getDiscountPercent()} | ||
| 108 | */ | 111 | */ |
| 109 | - private Integer percentOff; | 112 | + private Integer discountPercent; |
| 110 | /** | 113 | /** |
| 111 | - * 优惠金额,单位:分。 | 114 | + * 优惠金额,单位:分 |
| 115 | + * | ||
| 116 | + * 冗余 {@link CouponTemplateDO#getDiscountPrice()} | ||
| 112 | */ | 117 | */ |
| 113 | - private Integer priceOff; | 118 | + private Integer discountPrice; |
| 114 | /** | 119 | /** |
| 115 | - * 折扣上限,仅在 {@link #preferentialType} 等于 2 时生效。 | 120 | + * 折扣上限,仅在 {@link #discountType} 等于 {@link PromotionDiscountTypeEnum#PERCENT} 时生效 |
| 116 | * | 121 | * |
| 117 | - * 例如,折扣上限为 20 元,当使用 8 折优惠券,订单金额为 1000 元时,最高只可折扣 20 元,而非 80 元。 | 122 | + * 冗余 {@link CouponTemplateDO#getDiscountLimitPrice()} |
| 118 | */ | 123 | */ |
| 119 | - private Integer discountPriceLimit; | 124 | + private Integer discountLimitPrice; |
| 120 | // ========== 使用效果 END ========== | 125 | // ========== 使用效果 END ========== |
| 121 | 126 | ||
| 122 | // ========== 使用情况 BEGIN ========== | 127 | // ========== 使用情况 BEGIN ========== |
| 123 | -// /** | ||
| 124 | -// * 使用订单号 | ||
| 125 | -// */ | ||
| 126 | -// private Integer usedOrderId; // TODO 芋艿,暂时不考虑这个字段 | ||
| 127 | -// /** | ||
| 128 | -// * 订单中优惠面值,单位:分 | ||
| 129 | -// */ | ||
| 130 | -// private Integer usedPrice; // TODO 芋艿,暂时不考虑这个字段 | 128 | + /** |
| 129 | + * 使用订单号 | ||
| 130 | + */ | ||
| 131 | + private Long useOrderId; | ||
| 131 | /** | 132 | /** |
| 132 | * 使用时间 | 133 | * 使用时间 |
| 133 | */ | 134 | */ |
| 134 | - private Date usedTime; | ||
| 135 | - | ||
| 136 | - // TODO 芋艿,后续要加优惠劵的使用日志,因为下单后,可能会取消。 | 135 | + private Date useTime; |
| 137 | 136 | ||
| 138 | // ========== 使用情况 END ========== | 137 | // ========== 使用情况 END ========== |
| 139 | 138 |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponTemplateDO.java
| @@ -21,6 +21,8 @@ import java.util.List; | @@ -21,6 +21,8 @@ import java.util.List; | ||
| 21 | * 优惠劵模板 DO | 21 | * 优惠劵模板 DO |
| 22 | * | 22 | * |
| 23 | * 当用户领取时,会生成 {@link CouponDO} 优惠劵 | 23 | * 当用户领取时,会生成 {@link CouponDO} 优惠劵 |
| 24 | + * | ||
| 25 | + * @author 芋道源码 | ||
| 24 | */ | 26 | */ |
| 25 | @TableName(value = "promotion_coupon_template", autoResultMap = true) | 27 | @TableName(value = "promotion_coupon_template", autoResultMap = true) |
| 26 | @KeySequence("promotion_coupon_template_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 | 28 | @KeySequence("promotion_coupon_template_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/price/PriceServiceImpl.java
| @@ -10,10 +10,7 @@ import cn.iocoder.yudao.module.promotion.convert.price.PriceConvert; | @@ -10,10 +10,7 @@ import cn.iocoder.yudao.module.promotion.convert.price.PriceConvert; | ||
| 10 | import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; | 10 | import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; |
| 11 | import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; | 11 | import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; |
| 12 | import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; | 12 | import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; |
| 13 | -import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum; | ||
| 14 | -import cn.iocoder.yudao.module.promotion.enums.common.PromotionLevelEnum; | ||
| 15 | -import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; | ||
| 16 | -import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; | 13 | +import cn.iocoder.yudao.module.promotion.enums.common.*; |
| 17 | import cn.iocoder.yudao.module.promotion.service.coupon.CouponService; | 14 | import cn.iocoder.yudao.module.promotion.service.coupon.CouponService; |
| 18 | import cn.iocoder.yudao.module.promotion.service.discount.DiscountService; | 15 | import cn.iocoder.yudao.module.promotion.service.discount.DiscountService; |
| 19 | import cn.iocoder.yudao.module.promotion.service.reward.RewardService; | 16 | import cn.iocoder.yudao.module.promotion.service.reward.RewardService; |
| @@ -283,7 +280,7 @@ public class PriceServiceImpl implements PriceService { | @@ -283,7 +280,7 @@ public class PriceServiceImpl implements PriceService { | ||
| 283 | // 计算是否满足优惠劵的使用金额 | 280 | // 计算是否满足优惠劵的使用金额 |
| 284 | Integer originPrice = getSumValue(orderItems, PriceCalculateRespDTO.OrderItem::getOrderDividePrice, Integer::sum); | 281 | Integer originPrice = getSumValue(orderItems, PriceCalculateRespDTO.OrderItem::getOrderDividePrice, Integer::sum); |
| 285 | assert originPrice != null; | 282 | assert originPrice != null; |
| 286 | - if (originPrice < coupon.getPriceAvailable()) { | 283 | + if (originPrice < coupon.getUsePrice()) { |
| 287 | throw exception(COUPON_NO_MATCH_MIN_PRICE); | 284 | throw exception(COUPON_NO_MATCH_MIN_PRICE); |
| 288 | } | 285 | } |
| 289 | 286 | ||
| @@ -294,7 +291,7 @@ public class PriceServiceImpl implements PriceService { | @@ -294,7 +291,7 @@ public class PriceServiceImpl implements PriceService { | ||
| 294 | // TODO 芋艿:limit 不能超过最大价格 | 291 | // TODO 芋艿:limit 不能超过最大价格 |
| 295 | List<Integer> couponPartPrices = dividePrice(orderItems, couponPrice); | 292 | List<Integer> couponPartPrices = dividePrice(orderItems, couponPrice); |
| 296 | // 记录优惠明细 | 293 | // 记录优惠明细 |
| 297 | - addPromotion(priceCalculate, orderItems, coupon.getId(), coupon.getTitle(), | 294 | + addPromotion(priceCalculate, orderItems, coupon.getId(), coupon.getName(), |
| 298 | PromotionTypeEnum.COUPON.getType(), PromotionLevelEnum.COUPON.getLevel(), couponPartPrices, | 295 | PromotionTypeEnum.COUPON.getType(), PromotionLevelEnum.COUPON.getLevel(), couponPartPrices, |
| 299 | true, StrUtil.format("优惠劵:省 {} 元", formatPrice(couponPrice))); | 296 | true, StrUtil.format("优惠劵:省 {} 元", formatPrice(couponPrice))); |
| 300 | // 修改 SKU 的分摊 | 297 | // 修改 SKU 的分摊 |
| @@ -309,19 +306,18 @@ public class PriceServiceImpl implements PriceService { | @@ -309,19 +306,18 @@ public class PriceServiceImpl implements PriceService { | ||
| 309 | return priceCalculate.getOrder().getItems(); | 306 | return priceCalculate.getOrder().getItems(); |
| 310 | } | 307 | } |
| 311 | return CollectionUtils.filterList(priceCalculate.getOrder().getItems(), | 308 | return CollectionUtils.filterList(priceCalculate.getOrder().getItems(), |
| 312 | - orderItem -> coupon.getSpuIds().contains(orderItem.getSpuId())); | 309 | + orderItem -> coupon.getProductSpuIds().contains(orderItem.getSpuId())); |
| 313 | } | 310 | } |
| 314 | 311 | ||
| 315 | private Integer getCouponPrice(CouponDO coupon, Integer originPrice) { | 312 | private Integer getCouponPrice(CouponDO coupon, Integer originPrice) { |
| 316 | - // TODO 芋艿 getPreferentialType 的枚举判断 | ||
| 317 | - if (coupon.getPreferentialType().equals(1)) { // 减价 | ||
| 318 | - return coupon.getPriceOff(); | ||
| 319 | - } else if (coupon.getPreferentialType().equals(2)) { // 打折 | ||
| 320 | - Integer couponPrice = originPrice * coupon.getPercentOff() / 100; | ||
| 321 | - return coupon.getDiscountPriceLimit() == null ? couponPrice | ||
| 322 | - : Math.min(couponPrice, coupon.getDiscountPriceLimit()); // 优惠上限 | 313 | + if (PromotionDiscountTypeEnum.PRICE.getType().equals(coupon.getDiscountType())) { // 减价 |
| 314 | + return coupon.getDiscountPrice(); | ||
| 315 | + } else if (PromotionDiscountTypeEnum.PERCENT.getType().equals(coupon.getDiscountType())) { // 打折 | ||
| 316 | + int couponPrice = originPrice * coupon.getDiscountPercent() / 100; | ||
| 317 | + return coupon.getDiscountLimitPrice() == null ? couponPrice | ||
| 318 | + : Math.min(couponPrice, coupon.getDiscountLimitPrice()); // 优惠上限 | ||
| 323 | } | 319 | } |
| 324 | - throw new IllegalArgumentException(String.format("优惠劵(%s) 的优惠类型不正确", coupon.toString())); | 320 | + throw new IllegalArgumentException(String.format("优惠劵(%s) 的优惠类型不正确", coupon)); |
| 325 | } | 321 | } |
| 326 | 322 | ||
| 327 | // ========== 其它相对通用的方法 ========== | 323 | // ========== 其它相对通用的方法 ========== |
yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/price/PriceServiceTest.java
| @@ -373,7 +373,7 @@ public class PriceServiceTest extends BaseMockitoUnitTest { | @@ -373,7 +373,7 @@ public class PriceServiceTest extends BaseMockitoUnitTest { | ||
| 373 | ProductSkuRespDTO productSku03 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(30L).setPrice(30).setSpuId(3L)); | 373 | ProductSkuRespDTO productSku03 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(30L).setPrice(30).setSpuId(3L)); |
| 374 | when(productSkuApi.getSkuList(eq(asSet(10L, 20L, 30L)))).thenReturn(asList(productSku01, productSku02, productSku03)); | 374 | when(productSkuApi.getSkuList(eq(asSet(10L, 20L, 30L)))).thenReturn(asList(productSku01, productSku02, productSku03)); |
| 375 | // mock 方法(优惠劵 Coupon 信息) | 375 | // mock 方法(优惠劵 Coupon 信息) |
| 376 | - CouponDO coupon = randomPojo(CouponDO.class, o -> o.setId(1024L).setTitle("程序员节") | 376 | + CouponDO coupon = randomPojo(CouponDO.class, o -> o.setId(1024L).setName("程序员节") |
| 377 | .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setSpuIds(asList(1L, 2L)) | 377 | .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setSpuIds(asList(1L, 2L)) |
| 378 | .setPriceAvailable(350).setPreferentialType(2).setPercentOff(50).setDiscountPriceLimit(70)); | 378 | .setPriceAvailable(350).setPreferentialType(2).setPercentOff(50).setDiscountPriceLimit(70)); |
| 379 | when(couponService.validCoupon(eq(1024L), eq(calculateReqDTO.getUserId()))).thenReturn(coupon); | 379 | when(couponService.validCoupon(eq(1024L), eq(calculateReqDTO.getUserId()))).thenReturn(coupon); |