Commit 0631c51d93aec31c42533bf54b30b2dfc6f84d3e
1 parent
55dbff75
mall + trade:review 配置管理列表
Showing
75 changed files
with
1588 additions
and
758 deletions
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/string/StrUtils.java
| ... | ... | @@ -40,15 +40,14 @@ public class StrUtils { |
| 40 | 40 | return false; |
| 41 | 41 | } |
| 42 | 42 | |
| 43 | - public static List<Long> splitToLong(String value, CharSequence separator) { | |
| 43 | + public static List<Long> splitToLong(String value, CharSequence separator) { | |
| 44 | 44 | long[] longs = StrUtil.splitToLong(value, separator); |
| 45 | 45 | return Arrays.stream(longs).boxed().collect(Collectors.toList()); |
| 46 | 46 | } |
| 47 | 47 | |
| 48 | - public static List<Integer> splitToInteger(String value, CharSequence separator) { | |
| 48 | + public static List<Integer> splitToInteger(String value, CharSequence separator) { | |
| 49 | 49 | int[] integers = StrUtil.splitToInt(value, separator); |
| 50 | 50 | return Arrays.stream(integers).boxed().collect(Collectors.toList()); |
| 51 | 51 | } |
| 52 | 52 | |
| 53 | - | |
| 54 | 53 | } | ... | ... |
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java
| ... | ... | @@ -113,7 +113,7 @@ public interface BaseMapperX<T> extends MPJBaseMapper<T> { |
| 113 | 113 | Db.saveBatch(entities, size); |
| 114 | 114 | } |
| 115 | 115 | |
| 116 | - // @芋艿 是不是叫 updateByDo 或者 updateByEntity 更合适 | |
| 116 | + // @芋艿 是不是叫 updateByDo 或者 updateByEntity 更合适;回复:因为是使用实体作为条件去批量更新,所以没加 ByEntity,保持和 mybatis plus 风格一致 | |
| 117 | 117 | default void updateBatch(T update) { |
| 118 | 118 | update(update, new QueryWrapper<>()); |
| 119 | 119 | } | ... | ... |
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApi.java
| 1 | 1 | package cn.iocoder.yudao.module.promotion.api.coupon; |
| 2 | 2 | |
| 3 | +import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponRespDTO; | |
| 3 | 4 | import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO; |
| 5 | +import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponValidReqDTO; | |
| 4 | 6 | |
| 5 | 7 | import javax.validation.Valid; |
| 6 | 8 | |
| ... | ... | @@ -18,4 +20,12 @@ public interface CouponApi { |
| 18 | 20 | */ |
| 19 | 21 | void useCoupon(@Valid CouponUseReqDTO useReqDTO); |
| 20 | 22 | |
| 23 | + /** | |
| 24 | + * 校验优惠劵 | |
| 25 | + * | |
| 26 | + * @param validReqDTO 校验请求 | |
| 27 | + * @return 优惠劵 | |
| 28 | + */ | |
| 29 | + CouponRespDTO validateCoupon(@Valid CouponValidReqDTO validReqDTO); | |
| 30 | + | |
| 21 | 31 | } | ... | ... |
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/dto/CouponRespDTO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.promotion.api.coupon.dto; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; | |
| 4 | +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum; | |
| 5 | +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum; | |
| 6 | +import lombok.Data; | |
| 7 | + | |
| 8 | +import java.time.LocalDateTime; | |
| 9 | +import java.util.List; | |
| 10 | + | |
| 11 | +/** | |
| 12 | + * 优惠劵 Response DTO | |
| 13 | + * | |
| 14 | + * @author 芋道源码 | |
| 15 | + */ | |
| 16 | +@Data | |
| 17 | +public class CouponRespDTO { | |
| 18 | + | |
| 19 | + // ========== 基本信息 BEGIN ========== | |
| 20 | + /** | |
| 21 | + * 优惠劵编号 | |
| 22 | + */ | |
| 23 | + private Long id; | |
| 24 | + /** | |
| 25 | + * 优惠劵模板编号 | |
| 26 | + */ | |
| 27 | + private Integer templateId; | |
| 28 | + /** | |
| 29 | + * 优惠劵名 | |
| 30 | + */ | |
| 31 | + private String name; | |
| 32 | + /** | |
| 33 | + * 优惠码状态 | |
| 34 | + * | |
| 35 | + * 枚举 {@link CouponStatusEnum} | |
| 36 | + */ | |
| 37 | + private Integer status; | |
| 38 | + | |
| 39 | + // ========== 基本信息 END ========== | |
| 40 | + | |
| 41 | + // ========== 领取情况 BEGIN ========== | |
| 42 | + /** | |
| 43 | + * 用户编号 | |
| 44 | + * | |
| 45 | + * 关联 MemberUserDO 的 id 字段 | |
| 46 | + */ | |
| 47 | + private Long userId; | |
| 48 | + /** | |
| 49 | + * 领取类型 | |
| 50 | + * | |
| 51 | + * 枚举 {@link CouponTakeTypeEnum} | |
| 52 | + */ | |
| 53 | + private Integer takeType; | |
| 54 | + // ========== 领取情况 END ========== | |
| 55 | + | |
| 56 | + // ========== 使用规则 BEGIN ========== | |
| 57 | + /** | |
| 58 | + * 是否设置满多少金额可用,单位:分 | |
| 59 | + */ | |
| 60 | + private Integer usePrice; | |
| 61 | + /** | |
| 62 | + * 生效开始时间 | |
| 63 | + */ | |
| 64 | + private LocalDateTime validStartTime; | |
| 65 | + /** | |
| 66 | + * 生效结束时间 | |
| 67 | + */ | |
| 68 | + private LocalDateTime validEndTime; | |
| 69 | + /** | |
| 70 | + * 商品范围 | |
| 71 | + */ | |
| 72 | + private Integer productScope; | |
| 73 | + /** | |
| 74 | + * 商品 SPU 编号的数组 | |
| 75 | + */ | |
| 76 | + private List<Long> productSpuIds; | |
| 77 | + // ========== 使用规则 END ========== | |
| 78 | + | |
| 79 | + // ========== 使用效果 BEGIN ========== | |
| 80 | + /** | |
| 81 | + * 折扣类型 | |
| 82 | + */ | |
| 83 | + private Integer discountType; | |
| 84 | + /** | |
| 85 | + * 折扣百分比 | |
| 86 | + */ | |
| 87 | + private Integer discountPercent; | |
| 88 | + /** | |
| 89 | + * 优惠金额,单位:分 | |
| 90 | + */ | |
| 91 | + private Integer discountPrice; | |
| 92 | + /** | |
| 93 | + * 折扣上限,仅在 {@link #discountType} 等于 {@link PromotionDiscountTypeEnum#PERCENT} 时生效 | |
| 94 | + */ | |
| 95 | + private Integer discountLimitPrice; | |
| 96 | + // ========== 使用效果 END ========== | |
| 97 | + | |
| 98 | + // ========== 使用情况 BEGIN ========== | |
| 99 | + /** | |
| 100 | + * 使用订单号 | |
| 101 | + */ | |
| 102 | + private Long useOrderId; | |
| 103 | + /** | |
| 104 | + * 使用时间 | |
| 105 | + */ | |
| 106 | + private LocalDateTime useTime; | |
| 107 | + | |
| 108 | + // ========== 使用情况 END ========== | |
| 109 | +} | ... | ... |
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/dto/CouponValidReqDTO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.promotion.api.coupon.dto; | |
| 2 | + | |
| 3 | +import lombok.Data; | |
| 4 | + | |
| 5 | +import javax.validation.constraints.NotNull; | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * 优惠劵使用 Request DTO | |
| 9 | + * | |
| 10 | + * @author 芋道源码 | |
| 11 | + */ | |
| 12 | +@Data | |
| 13 | +public class CouponValidReqDTO { | |
| 14 | + | |
| 15 | + /** | |
| 16 | + * 优惠劵编号 | |
| 17 | + */ | |
| 18 | + @NotNull(message = "优惠劵编号不能为空") | |
| 19 | + private Long id; | |
| 20 | + | |
| 21 | + /** | |
| 22 | + * 用户编号 | |
| 23 | + */ | |
| 24 | + @NotNull(message = "用户编号不能为空") | |
| 25 | + private Long userId; | |
| 26 | + | |
| 27 | +} | ... | ... |
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/discount/DiscountActivityApi.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.promotion.api.discount; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO; | |
| 4 | + | |
| 5 | +import java.util.Collection; | |
| 6 | +import java.util.List; | |
| 7 | + | |
| 8 | +/** | |
| 9 | + * 限时折扣 API 接口 | |
| 10 | + * | |
| 11 | + * @author 芋道源码 | |
| 12 | + */ | |
| 13 | +public interface DiscountActivityApi { | |
| 14 | + | |
| 15 | + /** | |
| 16 | + * 获得商品匹配的的限时折扣信息 | |
| 17 | + * | |
| 18 | + * @param skuIds 商品 SKU 编号数组 | |
| 19 | + * @return 限时折扣信息 | |
| 20 | + */ | |
| 21 | + List<DiscountProductRespDTO> getMatchDiscountProductList(Collection<Long> skuIds); | |
| 22 | + | |
| 23 | +} | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/bo/DiscountProductDetailBO.java renamed to yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/discount/dto/DiscountProductRespDTO.java
| 1 | -package cn.iocoder.yudao.module.promotion.service.discount.bo; | |
| 1 | +package cn.iocoder.yudao.module.promotion.api.discount.dto; | |
| 2 | 2 | |
| 3 | 3 | import lombok.Data; |
| 4 | 4 | |
| 5 | 5 | /** |
| 6 | - * 限时折扣活动商品 BO | |
| 6 | + * 限时折扣活动商品 Response DTO | |
| 7 | 7 | * |
| 8 | 8 | * @author 芋道源码 |
| 9 | 9 | */ |
| 10 | 10 | @Data |
| 11 | -public class DiscountProductDetailBO { | |
| 12 | - | |
| 13 | - // ========== DiscountProductDO 字段 ========== | |
| 11 | +public class DiscountProductRespDTO { | |
| 14 | 12 | |
| 15 | 13 | /** |
| 16 | 14 | * 编号,主键自增 |
| 17 | 15 | */ |
| 18 | 16 | private Long id; |
| 19 | 17 | /** |
| 20 | - * 限时折扣活动的编号 | |
| 21 | - */ | |
| 22 | - private Long activityId; | |
| 23 | - /** | |
| 24 | 18 | * 商品 SPU 编号 |
| 25 | 19 | */ |
| 26 | 20 | private Long spuId; |
| ... | ... | @@ -41,7 +35,11 @@ public class DiscountProductDetailBO { |
| 41 | 35 | */ |
| 42 | 36 | private Integer discountPrice; |
| 43 | 37 | |
| 44 | - // ========== DiscountActivityDO 字段 ========== | |
| 38 | + // ========== 活动字段 ========== | |
| 39 | + /** | |
| 40 | + * 限时折扣活动的编号 | |
| 41 | + */ | |
| 42 | + private Long activityId; | |
| 45 | 43 | /** |
| 46 | 44 | * 活动标题 |
| 47 | 45 | */ | ... | ... |
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/package-info.java deleted
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/price/dto/PriceCalculateReqDTO.java
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/price/dto/PriceCalculateRespDTO.java
| ... | ... | @@ -24,6 +24,7 @@ import java.util.List; |
| 24 | 24 | * @author 芋道源码 |
| 25 | 25 | */ |
| 26 | 26 | @Data |
| 27 | +@Deprecated | |
| 27 | 28 | public class PriceCalculateRespDTO { |
| 28 | 29 | |
| 29 | 30 | /** |
| ... | ... | @@ -174,6 +175,7 @@ public class PriceCalculateRespDTO { |
| 174 | 175 | * 营销明细 |
| 175 | 176 | */ |
| 176 | 177 | @Data |
| 178 | + @Deprecated | |
| 177 | 179 | public static class Promotion { |
| 178 | 180 | |
| 179 | 181 | /** |
| ... | ... | @@ -216,14 +218,14 @@ public class PriceCalculateRespDTO { |
| 216 | 218 | /** |
| 217 | 219 | * 是否满足优惠条件 |
| 218 | 220 | */ |
| 219 | - private Boolean meet; | |
| 221 | + private Boolean match; | |
| 220 | 222 | /** |
| 221 | 223 | * 满足条件的提示 |
| 222 | 224 | * |
| 223 | - * 如果 {@link #meet} = true 满足,则提示“圣诞价:省 150.00 元” | |
| 224 | - * 如果 {@link #meet} = false 不满足,则提示“购满 85 元,可减 40 元” | |
| 225 | + * 如果 {@link #match} = true 满足,则提示“圣诞价:省 150.00 元” | |
| 226 | + * 如果 {@link #match} = false 不满足,则提示“购满 85 元,可减 40 元” | |
| 225 | 227 | */ |
| 226 | - private String meetTip; | |
| 228 | + private String description; | |
| 227 | 229 | |
| 228 | 230 | } |
| 229 | 231 | ... | ... |
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/reward/RewardActivityApi.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.promotion.api.reward; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO; | |
| 4 | + | |
| 5 | +import java.util.Collection; | |
| 6 | +import java.util.List; | |
| 7 | + | |
| 8 | +/** | |
| 9 | + * 满减送活动 API 接口 | |
| 10 | + * | |
| 11 | + * @author 芋道源码 | |
| 12 | + */ | |
| 13 | +public interface RewardActivityApi { | |
| 14 | + | |
| 15 | + | |
| 16 | + /** | |
| 17 | + * 基于指定的 SPU 编号数组,获得它们匹配的满减送活动 | |
| 18 | + * | |
| 19 | + * @param spuIds SPU 编号数组 | |
| 20 | + * @return 满减送活动列表 | |
| 21 | + */ | |
| 22 | + List<RewardActivityMatchRespDTO> getMatchRewardActivityList(Collection<Long> spuIds); | |
| 23 | + | |
| 24 | +} | ... | ... |
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/reward/dto/RewardActivityMatchRespDTO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.promotion.api.reward.dto; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum; | |
| 4 | +import lombok.Data; | |
| 5 | + | |
| 6 | +import java.util.List; | |
| 7 | + | |
| 8 | +/** | |
| 9 | + * 满减送活动的匹配 Response DTO | |
| 10 | + * | |
| 11 | + * @author 芋道源码 | |
| 12 | + */ | |
| 13 | +@Data | |
| 14 | +public class RewardActivityMatchRespDTO { | |
| 15 | + | |
| 16 | + /** | |
| 17 | + * 活动编号,主键自增 | |
| 18 | + */ | |
| 19 | + private Long id; | |
| 20 | + /** | |
| 21 | + * 活动标题 | |
| 22 | + */ | |
| 23 | + private String name; | |
| 24 | + /** | |
| 25 | + * 条件类型 | |
| 26 | + * | |
| 27 | + * 枚举 {@link PromotionConditionTypeEnum} | |
| 28 | + */ | |
| 29 | + private Integer conditionType; | |
| 30 | + /** | |
| 31 | + * 优惠规则的数组 | |
| 32 | + */ | |
| 33 | + private List<Rule> rules; | |
| 34 | + | |
| 35 | + /** | |
| 36 | + * 商品 SPU 编号的数组 | |
| 37 | + */ | |
| 38 | + private List<Long> spuIds; | |
| 39 | + | |
| 40 | + // TODO 芋艿:后面 RewardActivityRespDTO 有了之后,Rule 可以放过去 | |
| 41 | + /** | |
| 42 | + * 优惠规则 | |
| 43 | + */ | |
| 44 | + @Data | |
| 45 | + public static class Rule { | |
| 46 | + | |
| 47 | + /** | |
| 48 | + * 优惠门槛 | |
| 49 | + * | |
| 50 | + * 1. 满 N 元,单位:分 | |
| 51 | + * 2. 满 N 件 | |
| 52 | + */ | |
| 53 | + private Integer limit; | |
| 54 | + /** | |
| 55 | + * 优惠价格,单位:分 | |
| 56 | + */ | |
| 57 | + private Integer discountPrice; | |
| 58 | + /** | |
| 59 | + * 是否包邮 | |
| 60 | + */ | |
| 61 | + private Boolean freeDelivery; | |
| 62 | + /** | |
| 63 | + * 赠送的积分 | |
| 64 | + */ | |
| 65 | + private Integer point; | |
| 66 | + /** | |
| 67 | + * 赠送的优惠劵编号的数组 | |
| 68 | + */ | |
| 69 | + private List<Long> couponIds; | |
| 70 | + /** | |
| 71 | + * 赠送的优惠卷数量的数组 | |
| 72 | + */ | |
| 73 | + private List<Integer> couponCounts; | |
| 74 | + | |
| 75 | + } | |
| 76 | + | |
| 77 | +} | ... | ... |
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/common/PromotionLevelEnum.java deleted
| 1 | -package cn.iocoder.yudao.module.promotion.enums.common; | |
| 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 | - * 参考有赞:<a href="https://img01.yzcdn.cn/upload_files/2021/11/02/FhDjUrNDq-G0wjNdYDtgUX09fdGj.png">营销级别</a> | |
| 13 | - * | |
| 14 | - * @author 芋道源码 | |
| 15 | - */ | |
| 16 | -@Getter | |
| 17 | -@AllArgsConstructor | |
| 18 | -public enum PromotionLevelEnum implements IntArrayValuable { | |
| 19 | - | |
| 20 | - ORDER(1, "订单级"), // 多个商品,进行组合后优惠。例如说:满减送、打包一口价、第二件半价 | |
| 21 | - SKU(2, "商品级"), // 单个商品,直接优惠。例如说:限时折扣、会员折扣 | |
| 22 | - COUPON(3, "优惠劵"), // 多个商品,进行组合后优惠。例如说:优惠劵 | |
| 23 | - ; | |
| 24 | - | |
| 25 | - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(PromotionLevelEnum::getLevel).toArray(); | |
| 26 | - | |
| 27 | - /** | |
| 28 | - * 级别值 | |
| 29 | - */ | |
| 30 | - private final Integer level; | |
| 31 | - /** | |
| 32 | - * 类型名 | |
| 33 | - */ | |
| 34 | - private final String name; | |
| 35 | - | |
| 36 | - @Override | |
| 37 | - public int[] array() { | |
| 38 | - return ARRAYS; | |
| 39 | - } | |
| 40 | -} |
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/common/PromotionTypeEnum.java
| ... | ... | @@ -18,7 +18,7 @@ public enum PromotionTypeEnum implements IntArrayValuable { |
| 18 | 18 | DISCOUNT_ACTIVITY(1, "限时折扣"), |
| 19 | 19 | REWARD_ACTIVITY(2, "满减送"), |
| 20 | 20 | |
| 21 | - MEMBER(3, "会员折扣"), | |
| 21 | + MEMBER(3, "会员折扣"), // TODO 芋艿:待实现 StrUtil.format("会员折扣:省 {} 元", formatPrice(orderItem.getPayPrice() - memberPrice) | |
| 22 | 22 | COUPON(4, "优惠劵") |
| 23 | 23 | ; |
| 24 | 24 | |
| ... | ... | @@ -37,4 +37,5 @@ public enum PromotionTypeEnum implements IntArrayValuable { |
| 37 | 37 | public int[] array() { |
| 38 | 38 | return ARRAYS; |
| 39 | 39 | } |
| 40 | + | |
| 40 | 41 | } | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApiImpl.java
| 1 | 1 | package cn.iocoder.yudao.module.promotion.api.coupon; |
| 2 | 2 | |
| 3 | 3 | |
| 4 | +import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponRespDTO; | |
| 4 | 5 | import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO; |
| 6 | +import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponValidReqDTO; | |
| 7 | +import cn.iocoder.yudao.module.promotion.convert.coupon.CouponConvert; | |
| 8 | +import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; | |
| 5 | 9 | import cn.iocoder.yudao.module.promotion.service.coupon.CouponService; |
| 6 | 10 | import org.springframework.stereotype.Service; |
| 7 | 11 | |
| ... | ... | @@ -24,4 +28,10 @@ public class CouponApiImpl implements CouponApi { |
| 24 | 28 | useReqDTO.getOrderId()); |
| 25 | 29 | } |
| 26 | 30 | |
| 31 | + @Override | |
| 32 | + public CouponRespDTO validateCoupon(CouponValidReqDTO validReqDTO) { | |
| 33 | + CouponDO coupon = couponService.validCoupon(validReqDTO.getId(), validReqDTO.getUserId()); | |
| 34 | + return CouponConvert.INSTANCE.convert(coupon); | |
| 35 | + } | |
| 36 | + | |
| 27 | 37 | } | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/discount/DiscountActivityApiImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.promotion.api.discount; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO; | |
| 4 | +import cn.iocoder.yudao.module.promotion.convert.discount.DiscountActivityConvert; | |
| 5 | +import cn.iocoder.yudao.module.promotion.service.discount.DiscountActivityService; | |
| 6 | +import org.springframework.stereotype.Service; | |
| 7 | + | |
| 8 | +import javax.annotation.Resource; | |
| 9 | +import java.util.Collection; | |
| 10 | +import java.util.List; | |
| 11 | + | |
| 12 | +/** | |
| 13 | + * 限时折扣 API 实现类 | |
| 14 | + * | |
| 15 | + * @author 芋道源码 | |
| 16 | + */ | |
| 17 | +@Service | |
| 18 | +public class DiscountActivityApiImpl implements DiscountActivityApi { | |
| 19 | + | |
| 20 | + @Resource | |
| 21 | + private DiscountActivityService discountActivityService; | |
| 22 | + | |
| 23 | + @Override | |
| 24 | + public List<DiscountProductRespDTO> getMatchDiscountProductList(Collection<Long> skuIds) { | |
| 25 | + return DiscountActivityConvert.INSTANCE.convertList02(discountActivityService.getMatchDiscountProductList(skuIds)); | |
| 26 | + } | |
| 27 | + | |
| 28 | +} | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/discount/package-info.java deleted
| 1 | -package cn.iocoder.yudao.module.promotion.api.discount; |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/reward/RewardActivityApiImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.promotion.api.reward; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO; | |
| 4 | +import cn.iocoder.yudao.module.promotion.service.reward.RewardActivityService; | |
| 5 | +import org.springframework.stereotype.Service; | |
| 6 | + | |
| 7 | +import javax.annotation.Resource; | |
| 8 | +import java.util.Collection; | |
| 9 | +import java.util.List; | |
| 10 | + | |
| 11 | +/** | |
| 12 | + * 满减送活动 API 实现类 | |
| 13 | + * | |
| 14 | + * @author 芋道源码 | |
| 15 | + */ | |
| 16 | +@Service | |
| 17 | +public class RewardActivityApiImpl implements RewardActivityApi { | |
| 18 | + | |
| 19 | + @Resource | |
| 20 | + private RewardActivityService rewardActivityService; | |
| 21 | + | |
| 22 | + @Override | |
| 23 | + public List<RewardActivityMatchRespDTO> getMatchRewardActivityList(Collection<Long> spuIds) { | |
| 24 | + return rewardActivityService.getMatchRewardActivityList(spuIds); | |
| 25 | + } | |
| 26 | + | |
| 27 | +} | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponConvert.java
| 1 | 1 | package cn.iocoder.yudao.module.promotion.convert.coupon; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | +import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponRespDTO; | |
| 4 | 5 | import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponPageItemRespVO; |
| 5 | 6 | import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; |
| 6 | 7 | import org.mapstruct.Mapper; |
| ... | ... | @@ -18,4 +19,6 @@ public interface CouponConvert { |
| 18 | 19 | |
| 19 | 20 | PageResult<CouponPageItemRespVO> convertPage(PageResult<CouponDO> page); |
| 20 | 21 | |
| 22 | + CouponRespDTO convert(CouponDO bean); | |
| 23 | + | |
| 21 | 24 | } | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/discount/DiscountActivityConvert.java
| ... | ... | @@ -2,18 +2,15 @@ package cn.iocoder.yudao.module.promotion.convert.discount; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.util.ObjectUtil; |
| 4 | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | |
| 6 | -import cn.iocoder.yudao.framework.common.util.collection.MapUtils; | |
| 5 | +import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO; | |
| 7 | 6 | import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.*; |
| 8 | 7 | import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO; |
| 9 | 8 | import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; |
| 10 | 9 | import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; |
| 11 | -import cn.iocoder.yudao.module.promotion.service.discount.bo.DiscountProductDetailBO; | |
| 12 | 10 | import org.mapstruct.Mapper; |
| 13 | 11 | import org.mapstruct.factory.Mappers; |
| 14 | 12 | |
| 15 | 13 | import java.util.List; |
| 16 | -import java.util.Map; | |
| 17 | 14 | |
| 18 | 15 | /** |
| 19 | 16 | * 限时折扣活动 Convert |
| ... | ... | @@ -33,19 +30,9 @@ public interface DiscountActivityConvert { |
| 33 | 30 | |
| 34 | 31 | List<DiscountActivityRespVO> convertList(List<DiscountActivityDO> list); |
| 35 | 32 | |
| 36 | - PageResult<DiscountActivityRespVO> convertPage(PageResult<DiscountActivityDO> page); | |
| 37 | - | |
| 38 | - DiscountProductDetailBO convert(DiscountProductDO product); | |
| 33 | + List<DiscountProductRespDTO> convertList02(List<DiscountProductDO> list); | |
| 39 | 34 | |
| 40 | - default List<DiscountProductDetailBO> convertList(List<DiscountProductDO> products, Map<Long, DiscountActivityDO> activityMap) { | |
| 41 | - return CollectionUtils.convertList(products, product -> { | |
| 42 | - DiscountProductDetailBO detail = convert(product); | |
| 43 | - MapUtils.findAndThen(activityMap, product.getActivityId(), activity -> { | |
| 44 | - detail.setActivityName(activity.getName()); | |
| 45 | - }); | |
| 46 | - return detail; | |
| 47 | - }); | |
| 48 | - } | |
| 35 | + PageResult<DiscountActivityRespVO> convertPage(PageResult<DiscountActivityDO> page); | |
| 49 | 36 | |
| 50 | 37 | DiscountProductDO convert(DiscountActivityBaseVO.Product bean); |
| 51 | 38 | |
| ... | ... | @@ -99,4 +86,5 @@ public interface DiscountActivityConvert { |
| 99 | 86 | return true; |
| 100 | 87 | } |
| 101 | 88 | |
| 89 | + | |
| 102 | 90 | } | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/discount/DiscountActivityDO.java
| 1 | 1 | package cn.iocoder.yudao.module.promotion.dal.dataobject.discount; |
| 2 | 2 | |
| 3 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | |
| 3 | 4 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| 4 | -import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum; | |
| 5 | 5 | import com.baomidou.mybatisplus.annotation.KeySequence; |
| 6 | 6 | import com.baomidou.mybatisplus.annotation.TableId; |
| 7 | 7 | import com.baomidou.mybatisplus.annotation.TableName; |
| ... | ... | @@ -33,10 +33,13 @@ public class DiscountActivityDO extends BaseDO { |
| 33 | 33 | * 活动标题 |
| 34 | 34 | */ |
| 35 | 35 | private String name; |
| 36 | + // TODO 芋艿:状态调整,只有开启和关闭; | |
| 36 | 37 | /** |
| 37 | 38 | * 状态 |
| 38 | 39 | * |
| 39 | - * 枚举 {@link PromotionActivityStatusEnum} | |
| 40 | + * 枚举 {@link CommonStatusEnum} | |
| 41 | + * | |
| 42 | + * 活动被关闭后,不允许再次开启。 | |
| 40 | 43 | */ |
| 41 | 44 | private Integer status; |
| 42 | 45 | /** | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/discount/DiscountProductDO.java
| ... | ... | @@ -24,12 +24,15 @@ public class DiscountProductDO extends BaseDO { |
| 24 | 24 | */ |
| 25 | 25 | @TableId |
| 26 | 26 | private Long id; |
| 27 | + | |
| 28 | + // TODO 芋艿:把 activity 所有的字段冗余过来 | |
| 27 | 29 | /** |
| 28 | 30 | * 限时折扣活动的编号 |
| 29 | 31 | * |
| 30 | 32 | * 关联 {@link DiscountActivityDO#getId()} |
| 31 | 33 | */ |
| 32 | 34 | private Long activityId; |
| 35 | + | |
| 33 | 36 | /** |
| 34 | 37 | * 商品 SPU 编号 |
| 35 | 38 | * | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/reward/RewardActivityDO.java
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityService.java
| ... | ... | @@ -6,12 +6,10 @@ import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountAc |
| 6 | 6 | import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityUpdateReqVO; |
| 7 | 7 | import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO; |
| 8 | 8 | import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; |
| 9 | -import cn.iocoder.yudao.module.promotion.service.discount.bo.DiscountProductDetailBO; | |
| 10 | 9 | |
| 11 | 10 | import javax.validation.Valid; |
| 12 | 11 | import java.util.Collection; |
| 13 | 12 | import java.util.List; |
| 14 | -import java.util.Map; | |
| 15 | 13 | |
| 16 | 14 | /** |
| 17 | 15 | * 限时折扣 Service 接口 |
| ... | ... | @@ -28,7 +26,7 @@ public interface DiscountActivityService { |
| 28 | 26 | * @param skuIds SKU 编号数组 |
| 29 | 27 | * @return 匹配的限时折扣商品 |
| 30 | 28 | */ |
| 31 | - Map<Long, DiscountProductDetailBO> getMatchDiscountProducts(Collection<Long> skuIds); | |
| 29 | + List<DiscountProductDO> getMatchDiscountProductList(Collection<Long> skuIds); | |
| 32 | 30 | |
| 33 | 31 | /** |
| 34 | 32 | * 创建限时折扣活动 | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityServiceImpl.java
| ... | ... | @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.promotion.service.discount; |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | 4 | import cn.hutool.core.collection.CollectionUtil; |
| 5 | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | |
| 7 | 6 | import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityBaseVO; |
| 8 | 7 | import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityCreateReqVO; |
| 9 | 8 | import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityPageReqVO; |
| ... | ... | @@ -14,18 +13,17 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProduct |
| 14 | 13 | import cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountActivityMapper; |
| 15 | 14 | import cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountProductMapper; |
| 16 | 15 | import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum; |
| 17 | -import cn.iocoder.yudao.module.promotion.service.discount.bo.DiscountProductDetailBO; | |
| 18 | 16 | import cn.iocoder.yudao.module.promotion.util.PromotionUtils; |
| 19 | 17 | import org.springframework.stereotype.Service; |
| 20 | 18 | import org.springframework.validation.annotation.Validated; |
| 21 | 19 | |
| 22 | 20 | import javax.annotation.Resource; |
| 23 | -import java.util.*; | |
| 21 | +import java.util.Collection; | |
| 22 | +import java.util.List; | |
| 24 | 23 | |
| 25 | 24 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 26 | -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; | |
| 25 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | |
| 27 | 26 | import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; |
| 28 | -import static java.util.Arrays.asList; | |
| 29 | 27 | |
| 30 | 28 | /** |
| 31 | 29 | * 限时折扣 Service 实现类 |
| ... | ... | @@ -42,9 +40,9 @@ public class DiscountActivityServiceImpl implements DiscountActivityService { |
| 42 | 40 | private DiscountProductMapper discountProductMapper; |
| 43 | 41 | |
| 44 | 42 | @Override |
| 45 | - public Map<Long, DiscountProductDetailBO> getMatchDiscountProducts(Collection<Long> skuIds) { | |
| 46 | - List<DiscountProductDetailBO> discountProducts = getRewardProductListBySkuIds(skuIds, singleton(PromotionActivityStatusEnum.RUN.getStatus())); | |
| 47 | - return convertMap(discountProducts, DiscountProductDetailBO::getSkuId); | |
| 43 | + public List<DiscountProductDO> getMatchDiscountProductList(Collection<Long> skuIds) { | |
| 44 | + // TODO 芋艿:开启、满足 skuId、日期内 | |
| 45 | + return null; | |
| 48 | 46 | } |
| 49 | 47 | |
| 50 | 48 | @Override |
| ... | ... | @@ -101,6 +99,7 @@ public class DiscountActivityServiceImpl implements DiscountActivityService { |
| 101 | 99 | } |
| 102 | 100 | } |
| 103 | 101 | |
| 102 | + // TODO 芋艿:校验逻辑简化,只查询时间冲突的活动,开启状态的。 | |
| 104 | 103 | /** |
| 105 | 104 | * 校验商品是否冲突 |
| 106 | 105 | * |
| ... | ... | @@ -112,9 +111,10 @@ public class DiscountActivityServiceImpl implements DiscountActivityService { |
| 112 | 111 | return; |
| 113 | 112 | } |
| 114 | 113 | // 查询商品参加的活动 |
| 115 | - List<DiscountProductDetailBO> discountActivityProductList = getRewardProductListBySkuIds( | |
| 116 | - convertSet(products, DiscountActivityBaseVO.Product::getSkuId), | |
| 117 | - asList(PromotionActivityStatusEnum.WAIT.getStatus(), PromotionActivityStatusEnum.RUN.getStatus())); | |
| 114 | + List<DiscountProductDO> discountActivityProductList = null; | |
| 115 | +// getRewardProductListBySkuIds( | |
| 116 | +// convertSet(products, DiscountActivityBaseVO.Product::getSkuId), | |
| 117 | +// asList(PromotionActivityStatusEnum.WAIT.getStatus(), PromotionActivityStatusEnum.RUN.getStatus())); | |
| 118 | 118 | if (id != null) { // 排除自己这个活动 |
| 119 | 119 | discountActivityProductList.removeIf(product -> id.equals(product.getActivityId())); |
| 120 | 120 | } |
| ... | ... | @@ -124,24 +124,6 @@ public class DiscountActivityServiceImpl implements DiscountActivityService { |
| 124 | 124 | } |
| 125 | 125 | } |
| 126 | 126 | |
| 127 | - private List<DiscountProductDetailBO> getRewardProductListBySkuIds(Collection<Long> skuIds, | |
| 128 | - Collection<Integer> statuses) { | |
| 129 | - // 查询商品 | |
| 130 | - List<DiscountProductDO> products = discountProductMapper.selectListBySkuId(skuIds); | |
| 131 | - if (CollUtil.isEmpty(products)) { | |
| 132 | - return new ArrayList<>(0); | |
| 133 | - } | |
| 134 | - | |
| 135 | - // 查询活动 | |
| 136 | - List<DiscountActivityDO> activities = discountActivityMapper.selectBatchIds(skuIds); | |
| 137 | - activities.removeIf(activity -> !statuses.contains(activity.getStatus())); // 移除不满足 statuses 状态的 | |
| 138 | - Map<Long, DiscountActivityDO> activityMap = CollectionUtils.convertMap(activities, DiscountActivityDO::getId); | |
| 139 | - | |
| 140 | - // 移除不满足活动的商品 | |
| 141 | - products.removeIf(product -> !activityMap.containsKey(product.getActivityId())); | |
| 142 | - return DiscountActivityConvert.INSTANCE.convertList(products, activityMap); | |
| 143 | - } | |
| 144 | - | |
| 145 | 127 | @Override |
| 146 | 128 | public void closeRewardActivity(Long id) { |
| 147 | 129 | // 校验存在 |
| ... | ... | @@ -153,7 +135,7 @@ public class DiscountActivityServiceImpl implements DiscountActivityService { |
| 153 | 135 | throw exception(DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_END); |
| 154 | 136 | } |
| 155 | 137 | |
| 156 | - // 更新 | |
| 138 | + // 更新为关闭。 | |
| 157 | 139 | DiscountActivityDO updateObj = new DiscountActivityDO().setId(id).setStatus(PromotionActivityStatusEnum.CLOSE.getStatus()); |
| 158 | 140 | discountActivityMapper.updateById(updateObj); |
| 159 | 141 | } | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/price/PriceService.java
| ... | ... | @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.promotion.service.price; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.module.promotion.api.price.dto.CouponMeetRespDTO; |
| 4 | 4 | import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO; |
| 5 | -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO; | |
| 6 | 5 | |
| 7 | 6 | import java.util.List; |
| 8 | 7 | |
| ... | ... | @@ -14,14 +13,6 @@ import java.util.List; |
| 14 | 13 | public interface PriceService { |
| 15 | 14 | |
| 16 | 15 | /** |
| 17 | - * 计算商品的价格 | |
| 18 | - * | |
| 19 | - * @param calculateReqDTO 价格请求 | |
| 20 | - * @return 价格响应 | |
| 21 | - */ | |
| 22 | - PriceCalculateRespDTO calculatePrice(PriceCalculateReqDTO calculateReqDTO); | |
| 23 | - | |
| 24 | - /** | |
| 25 | 16 | * 获得优惠劵的匹配信息列表 |
| 26 | 17 | * |
| 27 | 18 | * @param calculateReqDTO 价格请求 | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/price/PriceServiceImpl.java
| 1 | 1 | package cn.iocoder.yudao.module.promotion.service.price; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | -import cn.hutool.core.lang.Assert; | |
| 5 | -import cn.hutool.core.util.StrUtil; | |
| 6 | 4 | import cn.iocoder.yudao.framework.common.exception.ServiceException; |
| 7 | 5 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; |
| 8 | -import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; | |
| 9 | -import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; | |
| 10 | 6 | import cn.iocoder.yudao.module.promotion.api.price.dto.CouponMeetRespDTO; |
| 11 | 7 | import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO; |
| 12 | 8 | import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO; |
| 13 | 9 | import cn.iocoder.yudao.module.promotion.convert.price.PriceConvert; |
| 14 | 10 | import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; |
| 15 | -import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; | |
| 16 | -import cn.iocoder.yudao.module.promotion.enums.common.*; | |
| 17 | 11 | import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum; |
| 18 | 12 | import cn.iocoder.yudao.module.promotion.service.coupon.CouponService; |
| 19 | -import cn.iocoder.yudao.module.promotion.service.discount.DiscountActivityService; | |
| 20 | -import cn.iocoder.yudao.module.promotion.service.discount.bo.DiscountProductDetailBO; | |
| 21 | -import cn.iocoder.yudao.module.promotion.service.reward.RewardActivityService; | |
| 22 | -import com.google.common.base.Suppliers; | |
| 23 | 13 | import lombok.extern.slf4j.Slf4j; |
| 24 | 14 | import org.springframework.stereotype.Service; |
| 25 | 15 | import org.springframework.validation.annotation.Validated; |
| 26 | 16 | |
| 27 | 17 | import javax.annotation.Resource; |
| 28 | -import java.util.*; | |
| 29 | -import java.util.function.Supplier; | |
| 18 | +import java.util.Collections; | |
| 19 | +import java.util.List; | |
| 30 | 20 | |
| 31 | -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | |
| 32 | -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | |
| 33 | 21 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue; |
| 34 | -import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS; | |
| 35 | -import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; | |
| 36 | -import static java.util.Collections.singletonList; | |
| 22 | +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COUPON_VALID_TIME_NOT_NOW; | |
| 37 | 23 | |
| 38 | 24 | /** |
| 39 | 25 | * 价格计算 Service 实现类 |
| ... | ... | @@ -55,42 +41,13 @@ import static java.util.Collections.singletonList; |
| 55 | 41 | public class PriceServiceImpl implements PriceService { |
| 56 | 42 | |
| 57 | 43 | @Resource |
| 58 | - private DiscountActivityService discountService; | |
| 59 | - @Resource | |
| 60 | - private RewardActivityService rewardActivityService; | |
| 61 | - @Resource | |
| 62 | 44 | private CouponService couponService; |
| 63 | 45 | |
| 64 | - @Resource | |
| 65 | - private ProductSkuApi productSkuApi; | |
| 66 | - | |
| 67 | - @Override | |
| 68 | - public PriceCalculateRespDTO calculatePrice(PriceCalculateReqDTO calculateReqDTO) { | |
| 69 | - // 获得商品 SKU 数组 | |
| 70 | - List<ProductSkuRespDTO> skuList = checkSkus(calculateReqDTO); | |
| 71 | - // 初始化 PriceCalculateRespDTO 对象 | |
| 72 | - PriceCalculateRespDTO priceCalculate = PriceConvert.INSTANCE.convert(calculateReqDTO, skuList); | |
| 73 | - | |
| 74 | - // 计算商品级别的价格 | |
| 75 | - calculatePriceForSkuLevel(calculateReqDTO.getUserId(), priceCalculate); | |
| 76 | - // 计算订单级别的价格 | |
| 77 | - calculatePriceForOrderLevel(calculateReqDTO.getUserId(), priceCalculate); | |
| 78 | - // 计算优惠劵级别的价格 | |
| 79 | - calculatePriceForCouponLevel(calculateReqDTO.getUserId(), calculateReqDTO.getCouponId(), priceCalculate); | |
| 80 | - | |
| 81 | - // 如果最终支付金额小于等于 0,则抛出业务异常 | |
| 82 | - if (priceCalculate.getOrder().getPayPrice() <= 0) { | |
| 83 | - log.error("[calculatePrice][价格计算不正确,请求 calculateReqDTO({}),结果 priceCalculate({})]", | |
| 84 | - calculateReqDTO, priceCalculate); | |
| 85 | - throw exception(PRICE_CALCULATE_PAY_PRICE_ILLEGAL); | |
| 86 | - } | |
| 87 | - return priceCalculate; | |
| 88 | - } | |
| 89 | - | |
| 90 | 46 | @Override |
| 91 | 47 | public List<CouponMeetRespDTO> getMeetCouponList(PriceCalculateReqDTO calculateReqDTO) { |
| 92 | 48 | // 先计算一轮价格 |
| 93 | - PriceCalculateRespDTO priceCalculate = calculatePrice(calculateReqDTO); | |
| 49 | +// PriceCalculateRespDTO priceCalculate = calculatePrice(calculateReqDTO); | |
| 50 | + PriceCalculateRespDTO priceCalculate = null; | |
| 94 | 51 | |
| 95 | 52 | // 获得用户的待使用优惠劵 |
| 96 | 53 | List<CouponDO> couponList = couponService.getCouponList(calculateReqDTO.getUserId(), CouponStatusEnum.UNUSED.getStatus()); |
| ... | ... | @@ -106,7 +63,9 @@ public class PriceServiceImpl implements PriceService { |
| 106 | 63 | couponService.validCoupon(coupon); |
| 107 | 64 | |
| 108 | 65 | // 获得匹配的商品 SKU 数组 |
| 109 | - List<PriceCalculateRespDTO.OrderItem> orderItems = getMatchCouponOrderItems(priceCalculate, coupon); | |
| 66 | + // TODO 芋艿:后续处理 | |
| 67 | +// List<PriceCalculateRespDTO.OrderItem> orderItems = getMatchCouponOrderItems(priceCalculate, coupon); | |
| 68 | + List<PriceCalculateRespDTO.OrderItem> orderItems = null; | |
| 110 | 69 | if (CollUtil.isEmpty(orderItems)) { |
| 111 | 70 | return couponMeetRespDTO.setMeet(false).setMeetTip("所结算商品没有符合条件的商品"); |
| 112 | 71 | } |
| ... | ... | @@ -134,413 +93,4 @@ public class PriceServiceImpl implements PriceService { |
| 134 | 93 | }); |
| 135 | 94 | } |
| 136 | 95 | |
| 137 | - private List<ProductSkuRespDTO> checkSkus(PriceCalculateReqDTO calculateReqDTO) { | |
| 138 | - // 获得商品 SKU 数组 | |
| 139 | - Map<Long, Integer> skuIdCountMap = CollectionUtils.convertMap(calculateReqDTO.getItems(), | |
| 140 | - PriceCalculateReqDTO.Item::getSkuId, PriceCalculateReqDTO.Item::getCount); | |
| 141 | - List<ProductSkuRespDTO> skus = productSkuApi.getSkuList(skuIdCountMap.keySet()); | |
| 142 | - | |
| 143 | - // 校验商品 SKU | |
| 144 | - skus.forEach(sku -> { | |
| 145 | - Integer count = skuIdCountMap.get(sku.getId()); | |
| 146 | - if (count == null) { | |
| 147 | - throw exception(SKU_NOT_EXISTS); | |
| 148 | - } | |
| 149 | - // 不校验库存不足,避免购物车场景,商品无货的情况 | |
| 150 | - }); | |
| 151 | - return skus; | |
| 152 | - } | |
| 153 | - | |
| 154 | - // ========== 计算商品级别的价格 ========== | |
| 155 | - | |
| 156 | - /** | |
| 157 | - * 计算商品级别的价格,例如说: | |
| 158 | - * 1. 会员折扣 | |
| 159 | - * 2. 限时折扣 {@link cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO} | |
| 160 | - * | |
| 161 | - * 其中,会员折扣、限时折扣取最低价 | |
| 162 | - * | |
| 163 | - * @param userId 用户编号 | |
| 164 | - * @param priceCalculate 价格计算的结果 | |
| 165 | - */ | |
| 166 | - private void calculatePriceForSkuLevel(Long userId, PriceCalculateRespDTO priceCalculate) { | |
| 167 | - // 获取 SKU 级别的所有优惠信息 | |
| 168 | - Supplier<Double> memberDiscountPercentSupplier = getMemberDiscountPercentSupplier(userId); | |
| 169 | - Map<Long, DiscountProductDetailBO> discountProducts = discountService.getMatchDiscountProducts( | |
| 170 | - convertSet(priceCalculate.getOrder().getItems(), PriceCalculateRespDTO.OrderItem::getSkuId)); | |
| 171 | - | |
| 172 | - // 处理每个 SKU 的优惠 | |
| 173 | - priceCalculate.getOrder().getItems().forEach(orderItem -> { | |
| 174 | - // 获取该 SKU 的优惠信息 | |
| 175 | - Double memberDiscountPercent = memberDiscountPercentSupplier.get(); | |
| 176 | - DiscountProductDetailBO discountProduct = discountProducts.get(orderItem.getSkuId()); | |
| 177 | - if (memberDiscountPercent == null && discountProduct == null) { | |
| 178 | - return; | |
| 179 | - } | |
| 180 | - // 计算价格,判断选择哪个折扣 | |
| 181 | - Integer memberPrice = memberDiscountPercent != null ? (int) (orderItem.getPayPrice() * memberDiscountPercent / 100) : null; | |
| 182 | - Integer promotionPrice = discountProduct != null ? getDiscountProductPrice(discountProduct, orderItem) : null; | |
| 183 | - if (memberPrice == null) { | |
| 184 | - calculatePriceByDiscountActivity(priceCalculate, orderItem, discountProduct, promotionPrice); | |
| 185 | - } else if (promotionPrice == null) { | |
| 186 | - calculatePriceByMemberDiscount(priceCalculate, orderItem, memberPrice); | |
| 187 | - } else if (memberPrice < promotionPrice) { | |
| 188 | - calculatePriceByDiscountActivity(priceCalculate, orderItem, discountProduct, promotionPrice); | |
| 189 | - } else { | |
| 190 | - calculatePriceByMemberDiscount(priceCalculate, orderItem, memberPrice); | |
| 191 | - } | |
| 192 | - }); | |
| 193 | - } | |
| 194 | - | |
| 195 | - private Integer getDiscountProductPrice(DiscountProductDetailBO discountProduct, | |
| 196 | - PriceCalculateRespDTO.OrderItem orderItem) { | |
| 197 | - Integer price = orderItem.getPayPrice(); | |
| 198 | - if (PromotionDiscountTypeEnum.PRICE.getType().equals(discountProduct.getDiscountType())) { // 减价 | |
| 199 | - price -= discountProduct.getDiscountPrice() * orderItem.getCount(); | |
| 200 | - } else if (PromotionDiscountTypeEnum.PERCENT.getType().equals(discountProduct.getDiscountType())) { // 打折 | |
| 201 | - price = price * discountProduct.getDiscountPercent() / 100; | |
| 202 | - } else { | |
| 203 | - throw new IllegalArgumentException(String.format("优惠活动的商品(%s) 的优惠类型不正确", discountProduct)); | |
| 204 | - } | |
| 205 | - return price; | |
| 206 | - } | |
| 207 | - | |
| 208 | - private void calculatePriceByMemberDiscount(PriceCalculateRespDTO priceCalculate, PriceCalculateRespDTO.OrderItem orderItem, | |
| 209 | - Integer memberPrice) { | |
| 210 | - // 记录优惠明细 | |
| 211 | - addPromotion(priceCalculate, orderItem, null, PromotionTypeEnum.MEMBER.getName(), | |
| 212 | - PromotionTypeEnum.MEMBER.getType(), PromotionLevelEnum.SKU.getLevel(), memberPrice, | |
| 213 | - true, StrUtil.format("会员折扣:省 {} 元", formatPrice(orderItem.getPayPrice() - memberPrice))); | |
| 214 | - // 修改 SKU 的优惠 | |
| 215 | - modifyOrderItemPayPrice(orderItem, memberPrice, priceCalculate); | |
| 216 | - } | |
| 217 | - | |
| 218 | - private void calculatePriceByDiscountActivity(PriceCalculateRespDTO priceCalculate, PriceCalculateRespDTO.OrderItem orderItem, | |
| 219 | - DiscountProductDetailBO discountProduct, Integer promotionPrice) { | |
| 220 | - // 记录优惠明细 | |
| 221 | - addPromotion(priceCalculate, orderItem, discountProduct.getActivityId(), discountProduct.getActivityName(), | |
| 222 | - PromotionTypeEnum.DISCOUNT_ACTIVITY.getType(), PromotionLevelEnum.SKU.getLevel(), promotionPrice, | |
| 223 | - true, StrUtil.format("限时折扣:省 {} 元", formatPrice(orderItem.getPayPrice() - promotionPrice))); | |
| 224 | - // 修改 SKU 的优惠 | |
| 225 | - modifyOrderItemPayPrice(orderItem, promotionPrice, priceCalculate); | |
| 226 | - } | |
| 227 | - | |
| 228 | - // TODO 芋艿:提前实现 | |
| 229 | - private Supplier<Double> getMemberDiscountPercentSupplier(Long userId) { | |
| 230 | - return Suppliers.memoize(() -> { | |
| 231 | - if (userId == 1) { | |
| 232 | - return 90d; | |
| 233 | - } | |
| 234 | - if (userId == 2) { | |
| 235 | - return 80d; | |
| 236 | - } | |
| 237 | - return null; // 无优惠 | |
| 238 | - }); | |
| 239 | - } | |
| 240 | - | |
| 241 | - // ========== 计算商品级别的价格 ========== | |
| 242 | - | |
| 243 | - /** | |
| 244 | - * 计算订单级别的价格,例如说: | |
| 245 | - * 1. 满减送 {@link cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO} | |
| 246 | - * | |
| 247 | - * @param userId 用户编号 | |
| 248 | - * @param priceCalculate 价格计算的结果 | |
| 249 | - */ | |
| 250 | - @SuppressWarnings("unused") | |
| 251 | - private void calculatePriceForOrderLevel(Long userId, PriceCalculateRespDTO priceCalculate) { | |
| 252 | - // 获取 SKU 级别的所有优惠信息 | |
| 253 | - Set<Long> spuIds = convertSet(priceCalculate.getOrder().getItems(), PriceCalculateRespDTO.OrderItem::getSpuId); | |
| 254 | - Map<RewardActivityDO, Set<Long>> rewardActivities = rewardActivityService.getMatchRewardActivities(spuIds); | |
| 255 | - | |
| 256 | - // 处理满减送活动 | |
| 257 | - if (CollUtil.isNotEmpty(rewardActivities)) { | |
| 258 | - rewardActivities.forEach((rewardActivity, activitySpuIds) -> { | |
| 259 | - List<PriceCalculateRespDTO.OrderItem> orderItems = CollectionUtils.filterList(priceCalculate.getOrder().getItems(), | |
| 260 | - orderItem -> CollUtil.contains(activitySpuIds, orderItem.getSpuId())); | |
| 261 | - calculatePriceByRewardActivity(priceCalculate, orderItems, rewardActivity); | |
| 262 | - }); | |
| 263 | - } | |
| 264 | - } | |
| 265 | - | |
| 266 | - private void calculatePriceByRewardActivity(PriceCalculateRespDTO priceCalculate, List<PriceCalculateRespDTO.OrderItem> orderItems, | |
| 267 | - RewardActivityDO rewardActivity) { | |
| 268 | - // 获得最大匹配的满减送活动的规则 | |
| 269 | - RewardActivityDO.Rule rule = getLastMatchRewardActivityRule(rewardActivity, orderItems); | |
| 270 | - if (rule == null) { | |
| 271 | - // 获取不到的情况下,记录不满足的优惠明细 | |
| 272 | - addNotMeetPromotion(priceCalculate, orderItems, rewardActivity.getId(), rewardActivity.getName(), | |
| 273 | - PromotionTypeEnum.REWARD_ACTIVITY.getType(), PromotionLevelEnum.ORDER.getLevel(), | |
| 274 | - getRewardActivityNotMeetTip(rewardActivity)); | |
| 275 | - return; | |
| 276 | - } | |
| 277 | - | |
| 278 | - // 分摊金额 | |
| 279 | - List<Integer> discountPartPrices = dividePrice(orderItems, rule.getDiscountPrice()); | |
| 280 | - // 记录优惠明细 | |
| 281 | - addPromotion(priceCalculate, orderItems, rewardActivity.getId(), rewardActivity.getName(), | |
| 282 | - PromotionTypeEnum.REWARD_ACTIVITY.getType(), PromotionLevelEnum.ORDER.getLevel(), discountPartPrices, | |
| 283 | - true, StrUtil.format("满减送:省 {} 元", formatPrice(rule.getDiscountPrice()))); | |
| 284 | - // 修改 SKU 的分摊 | |
| 285 | - for (int i = 0; i < orderItems.size(); i++) { | |
| 286 | - modifyOrderItemOrderPartPriceFromDiscountPrice(orderItems.get(i), discountPartPrices.get(i), priceCalculate); | |
| 287 | - } | |
| 288 | - } | |
| 289 | - | |
| 290 | - /** | |
| 291 | - * 获得最大匹配的满减送活动的规则 | |
| 292 | - * | |
| 293 | - * @param rewardActivity 满减送活动 | |
| 294 | - * @param orderItems 商品项 | |
| 295 | - * @return 匹配的活动规则 | |
| 296 | - */ | |
| 297 | - private RewardActivityDO.Rule getLastMatchRewardActivityRule(RewardActivityDO rewardActivity, | |
| 298 | - List<PriceCalculateRespDTO.OrderItem> orderItems) { | |
| 299 | - Integer count = getSumValue(orderItems, PriceCalculateRespDTO.OrderItem::getCount, Integer::sum); | |
| 300 | - // price 的计算逻辑,使用 orderDividePrice 的原因,主要考虑分摊后,这个才是该 SKU 当前真实的支付总价 | |
| 301 | - Integer price = getSumValue(orderItems, PriceCalculateRespDTO.OrderItem::getOrderDividePrice, Integer::sum); | |
| 302 | - assert count != null && price != null; | |
| 303 | - for (int i = rewardActivity.getRules().size() - 1; i >= 0; i--) { | |
| 304 | - RewardActivityDO.Rule rule = rewardActivity.getRules().get(i); | |
| 305 | - if (PromotionConditionTypeEnum.PRICE.getType().equals(rewardActivity.getConditionType()) | |
| 306 | - && price >= rule.getLimit()) { | |
| 307 | - return rule; | |
| 308 | - } | |
| 309 | - if (PromotionConditionTypeEnum.COUNT.getType().equals(rewardActivity.getConditionType()) | |
| 310 | - && count >= rule.getLimit()) { | |
| 311 | - return rule; | |
| 312 | - } | |
| 313 | - } | |
| 314 | - return null; | |
| 315 | - } | |
| 316 | - | |
| 317 | - /** | |
| 318 | - * 获得满减送活动部匹配时的提示 | |
| 319 | - * | |
| 320 | - * @param rewardActivity 满减送活动 | |
| 321 | - * @return 提示 | |
| 322 | - */ | |
| 323 | - private String getRewardActivityNotMeetTip(RewardActivityDO rewardActivity) { | |
| 324 | - return "TODO"; // TODO 芋艿:后面再想想 | |
| 325 | - } | |
| 326 | - | |
| 327 | - // ========== 计算优惠劵级别的价格 ========== | |
| 328 | - | |
| 329 | - private void calculatePriceForCouponLevel(Long userId, Long couponId, PriceCalculateRespDTO priceCalculate) { | |
| 330 | - // 校验优惠劵 | |
| 331 | - if (couponId == null) { | |
| 332 | - return; | |
| 333 | - } | |
| 334 | - CouponDO coupon = couponService.validCoupon(couponId, userId); | |
| 335 | - | |
| 336 | - // 获得匹配的商品 SKU 数组 | |
| 337 | - List<PriceCalculateRespDTO.OrderItem> orderItems = getMatchCouponOrderItems(priceCalculate, coupon); | |
| 338 | - if (CollUtil.isEmpty(orderItems)) { | |
| 339 | - throw exception(COUPON_NO_MATCH_SPU); | |
| 340 | - } | |
| 341 | - | |
| 342 | - // 计算是否满足优惠劵的使用金额 | |
| 343 | - Integer originPrice = getSumValue(orderItems, PriceCalculateRespDTO.OrderItem::getOrderDividePrice, Integer::sum); | |
| 344 | - assert originPrice != null; | |
| 345 | - if (originPrice < coupon.getUsePrice()) { | |
| 346 | - throw exception(COUPON_NO_MATCH_MIN_PRICE); | |
| 347 | - } | |
| 348 | - | |
| 349 | - // 计算可以优惠的金额 | |
| 350 | - priceCalculate.getOrder().setCouponId(couponId); | |
| 351 | - Integer couponPrice = getCouponPrice(coupon, originPrice); | |
| 352 | - // 分摊金额 | |
| 353 | - List<Integer> couponPartPrices = dividePrice(orderItems, couponPrice); | |
| 354 | - // 记录优惠明细 | |
| 355 | - addPromotion(priceCalculate, orderItems, coupon.getId(), coupon.getName(), | |
| 356 | - PromotionTypeEnum.COUPON.getType(), PromotionLevelEnum.COUPON.getLevel(), couponPartPrices, | |
| 357 | - true, StrUtil.format("优惠劵:省 {} 元", formatPrice(couponPrice))); | |
| 358 | - // 修改 SKU 的分摊 | |
| 359 | - for (int i = 0; i < orderItems.size(); i++) { | |
| 360 | - modifyOrderItemOrderPartPriceFromCouponPrice(orderItems.get(i), couponPartPrices.get(i), priceCalculate); | |
| 361 | - } | |
| 362 | - } | |
| 363 | - | |
| 364 | - private List<PriceCalculateRespDTO.OrderItem> getMatchCouponOrderItems(PriceCalculateRespDTO priceCalculate, | |
| 365 | - CouponDO coupon) { | |
| 366 | - if (PromotionProductScopeEnum.ALL.getScope().equals(coupon.getProductScope())) { | |
| 367 | - return priceCalculate.getOrder().getItems(); | |
| 368 | - } | |
| 369 | - return CollectionUtils.filterList(priceCalculate.getOrder().getItems(), | |
| 370 | - orderItem -> coupon.getProductSpuIds().contains(orderItem.getSpuId())); | |
| 371 | - } | |
| 372 | - | |
| 373 | - private Integer getCouponPrice(CouponDO coupon, Integer originPrice) { | |
| 374 | - if (PromotionDiscountTypeEnum.PRICE.getType().equals(coupon.getDiscountType())) { // 减价 | |
| 375 | - return coupon.getDiscountPrice(); | |
| 376 | - } else if (PromotionDiscountTypeEnum.PERCENT.getType().equals(coupon.getDiscountType())) { // 打折 | |
| 377 | - int couponPrice = originPrice * coupon.getDiscountPercent() / 100; | |
| 378 | - return coupon.getDiscountLimitPrice() == null ? couponPrice | |
| 379 | - : Math.min(couponPrice, coupon.getDiscountLimitPrice()); // 优惠上限 | |
| 380 | - } | |
| 381 | - throw new IllegalArgumentException(String.format("优惠劵(%s) 的优惠类型不正确", coupon)); | |
| 382 | - } | |
| 383 | - | |
| 384 | - // ========== 其它相对通用的方法 ========== | |
| 385 | - | |
| 386 | - /** | |
| 387 | - * 添加单个 OrderItem 的营销明细 | |
| 388 | - * | |
| 389 | - * @param priceCalculate 价格计算结果 | |
| 390 | - * @param orderItem 单个订单商品 SKU | |
| 391 | - * @param id 营销编号 | |
| 392 | - * @param name 营销名字 | |
| 393 | - * @param type 营销类型 | |
| 394 | - * @param level 营销级别 | |
| 395 | - * @param newPayPrice 新的单实付金额(总) | |
| 396 | - * @param meet 是否满足优惠条件 | |
| 397 | - * @param meetTip 满足条件的提示 | |
| 398 | - */ | |
| 399 | - private void addPromotion(PriceCalculateRespDTO priceCalculate, PriceCalculateRespDTO.OrderItem orderItem, | |
| 400 | - Long id, String name, Integer type, Integer level, | |
| 401 | - Integer newPayPrice, Boolean meet, String meetTip) { | |
| 402 | - // 创建营销明细 Item | |
| 403 | - // TODO 芋艿:orderItem.getPayPrice() 要不要改成 orderDividePrice;同时,newPayPrice 要不要改成直接传递 discountPrice | |
| 404 | - PriceCalculateRespDTO.PromotionItem promotionItem = new PriceCalculateRespDTO.PromotionItem().setSkuId(orderItem.getSkuId()) | |
| 405 | - .setOriginalPrice(orderItem.getPayPrice()).setDiscountPrice(orderItem.getPayPrice() - newPayPrice); | |
| 406 | - // 创建营销明细 | |
| 407 | - PriceCalculateRespDTO.Promotion promotion = new PriceCalculateRespDTO.Promotion() | |
| 408 | - .setId(id).setName(name).setType(type).setLevel(level) | |
| 409 | - .setTotalPrice(promotionItem.getOriginalPrice()).setDiscountPrice(promotionItem.getDiscountPrice()) | |
| 410 | - .setItems(singletonList(promotionItem)).setMeet(meet).setMeetTip(meetTip); | |
| 411 | - priceCalculate.getPromotions().add(promotion); | |
| 412 | - } | |
| 413 | - | |
| 414 | - /** | |
| 415 | - * 添加多个 OrderItem 的营销明细 | |
| 416 | - * | |
| 417 | - * @param priceCalculate 价格计算结果 | |
| 418 | - * @param orderItems 多个订单商品 SKU | |
| 419 | - * @param id 营销编号 | |
| 420 | - * @param name 营销名字 | |
| 421 | - * @param type 营销类型 | |
| 422 | - * @param level 营销级别 | |
| 423 | - * @param discountPrices 多个订单商品 SKU 的优惠价格(总),和 orderItems 一一对应 | |
| 424 | - * @param meet 是否满足优惠条件 | |
| 425 | - * @param meetTip 满足条件的提示 | |
| 426 | - */ | |
| 427 | - private void addPromotion(PriceCalculateRespDTO priceCalculate, List<PriceCalculateRespDTO.OrderItem> orderItems, | |
| 428 | - Long id, String name, Integer type, Integer level, | |
| 429 | - List<Integer> discountPrices, Boolean meet, String meetTip) { | |
| 430 | - // 创建营销明细 Item | |
| 431 | - List<PriceCalculateRespDTO.PromotionItem> promotionItems = new ArrayList<>(discountPrices.size()); | |
| 432 | - for (int i = 0; i < orderItems.size(); i++) { | |
| 433 | - PriceCalculateRespDTO.OrderItem orderItem = orderItems.get(i); | |
| 434 | - promotionItems.add(new PriceCalculateRespDTO.PromotionItem().setSkuId(orderItem.getSkuId()) | |
| 435 | - .setOriginalPrice(orderItem.getPayPrice()).setDiscountPrice(discountPrices.get(i))); | |
| 436 | - } | |
| 437 | - // 创建营销明细 | |
| 438 | - PriceCalculateRespDTO.Promotion promotion = new PriceCalculateRespDTO.Promotion() | |
| 439 | - .setId(id).setName(name).setType(type).setLevel(level) | |
| 440 | - .setTotalPrice(getSumValue(orderItems, PriceCalculateRespDTO.OrderItem::getOrderDividePrice, Integer::sum)) | |
| 441 | - .setDiscountPrice(getSumValue(discountPrices, value -> value, Integer::sum)) | |
| 442 | - .setItems(promotionItems).setMeet(meet).setMeetTip(meetTip); | |
| 443 | - priceCalculate.getPromotions().add(promotion); | |
| 444 | - } | |
| 445 | - | |
| 446 | - private void addNotMeetPromotion(PriceCalculateRespDTO priceCalculate, List<PriceCalculateRespDTO.OrderItem> orderItems, | |
| 447 | - Long id, String name, Integer type, Integer level, String meetTip) { | |
| 448 | - // 创建营销明细 Item | |
| 449 | - List<PriceCalculateRespDTO.PromotionItem> promotionItems = CollectionUtils.convertList(orderItems, | |
| 450 | - orderItem -> new PriceCalculateRespDTO.PromotionItem().setSkuId(orderItem.getSkuId()) | |
| 451 | - .setOriginalPrice(orderItem.getOrderDividePrice()).setDiscountPrice(0)); | |
| 452 | - // 创建营销明细 | |
| 453 | - Integer originalPrice = getSumValue(orderItems, PriceCalculateRespDTO.OrderItem::getOrderDividePrice, Integer::sum); | |
| 454 | - PriceCalculateRespDTO.Promotion promotion = new PriceCalculateRespDTO.Promotion() | |
| 455 | - .setId(id).setName(name).setType(type).setLevel(level) | |
| 456 | - .setTotalPrice(originalPrice).setDiscountPrice(0) | |
| 457 | - .setItems(promotionItems).setMeet(false).setMeetTip(meetTip); | |
| 458 | - priceCalculate.getPromotions().add(promotion); | |
| 459 | - } | |
| 460 | - | |
| 461 | - /** | |
| 462 | - * 修改 OrderItem 的 payPrice 价格,同时会修改 Order 的 payPrice 价格 | |
| 463 | - * | |
| 464 | - * @param orderItem 订单商品 SKU | |
| 465 | - * @param newPayPrice 新的 payPrice 价格 | |
| 466 | - * @param priceCalculate 价格计算结果 | |
| 467 | - */ | |
| 468 | - private void modifyOrderItemPayPrice(PriceCalculateRespDTO.OrderItem orderItem, Integer newPayPrice, | |
| 469 | - PriceCalculateRespDTO priceCalculate) { | |
| 470 | - // diffPayPrice 等于额外增加的商品级的优惠 | |
| 471 | - int diffPayPrice = orderItem.getPayPrice() - newPayPrice; | |
| 472 | - // 设置 OrderItem 价格相关字段 | |
| 473 | - orderItem.setDiscountPrice(orderItem.getDiscountPrice() + diffPayPrice); | |
| 474 | - orderItem.setPayPrice(newPayPrice); | |
| 475 | - orderItem.setOrderDividePrice(orderItem.getPayPrice() - orderItem.getOrderPartPrice()); | |
| 476 | - // 设置 Order 相关相关字段 | |
| 477 | - PriceCalculateRespDTO.Order order = priceCalculate.getOrder(); | |
| 478 | - order.setPayPrice(order.getPayPrice() - diffPayPrice); | |
| 479 | - } | |
| 480 | - | |
| 481 | - /** | |
| 482 | - * 修改 OrderItem 的 orderPartPrice 价格,同时会修改 Order 的 discountPrice 价格 | |
| 483 | - * | |
| 484 | - * 本质:分摊 Order 的 discountPrice 价格,到对应的 OrderItem 的 orderPartPrice 价格中 | |
| 485 | - * | |
| 486 | - * @param orderItem 订单商品 SKU | |
| 487 | - * @param addOrderPartPrice 新增的 discountPrice 价格 | |
| 488 | - * @param priceCalculate 价格计算结果 | |
| 489 | - */ | |
| 490 | - private void modifyOrderItemOrderPartPriceFromDiscountPrice(PriceCalculateRespDTO.OrderItem orderItem, Integer addOrderPartPrice, | |
| 491 | - PriceCalculateRespDTO priceCalculate) { | |
| 492 | - // 设置 OrderItem 价格相关字段 | |
| 493 | - orderItem.setOrderPartPrice(orderItem.getOrderPartPrice() + addOrderPartPrice); | |
| 494 | - orderItem.setOrderDividePrice(orderItem.getPayPrice() - orderItem.getOrderPartPrice()); | |
| 495 | - // 设置 Order 相关相关字段 | |
| 496 | - PriceCalculateRespDTO.Order order = priceCalculate.getOrder(); | |
| 497 | - order.setDiscountPrice(order.getDiscountPrice() + addOrderPartPrice); | |
| 498 | - order.setPayPrice(order.getPayPrice() - addOrderPartPrice); | |
| 499 | - } | |
| 500 | - | |
| 501 | - /** | |
| 502 | - * 修改 OrderItem 的 orderPartPrice 价格,同时会修改 Order 的 couponPrice 价格 | |
| 503 | - * | |
| 504 | - * 本质:分摊 Order 的 couponPrice 价格,到对应的 OrderItem 的 orderPartPrice 价格中 | |
| 505 | - * | |
| 506 | - * @param orderItem 订单商品 SKU | |
| 507 | - * @param addOrderPartPrice 新增的 couponPrice 价格 | |
| 508 | - * @param priceCalculate 价格计算结果 | |
| 509 | - */ | |
| 510 | - private void modifyOrderItemOrderPartPriceFromCouponPrice(PriceCalculateRespDTO.OrderItem orderItem, Integer addOrderPartPrice, | |
| 511 | - PriceCalculateRespDTO priceCalculate) { | |
| 512 | - // 设置 OrderItem 价格相关字段 | |
| 513 | - orderItem.setOrderPartPrice(orderItem.getOrderPartPrice() + addOrderPartPrice); | |
| 514 | - orderItem.setOrderDividePrice(orderItem.getPayPrice() - orderItem.getOrderPartPrice()); | |
| 515 | - // 设置 Order 相关相关字段 | |
| 516 | - PriceCalculateRespDTO.Order order = priceCalculate.getOrder(); | |
| 517 | - order.setCouponPrice(order.getCouponPrice() + addOrderPartPrice); | |
| 518 | - order.setPayPrice(order.getPayPrice() - addOrderPartPrice); | |
| 519 | - } | |
| 520 | - | |
| 521 | - private List<Integer> dividePrice(List<PriceCalculateRespDTO.OrderItem> orderItems, Integer price) { | |
| 522 | - List<Integer> prices = new ArrayList<>(orderItems.size()); | |
| 523 | - Integer total = getSumValue(orderItems, PriceCalculateRespDTO.OrderItem::getOrderDividePrice, Integer::sum); | |
| 524 | - assert total != null; | |
| 525 | - int remainPrice = price; | |
| 526 | - // 遍历每一个,进行分摊 | |
| 527 | - for (int i = 0; i < orderItems.size(); i++) { | |
| 528 | - PriceCalculateRespDTO.OrderItem orderItem = orderItems.get(i); | |
| 529 | - int partPrice; | |
| 530 | - if (i < orderItems.size() - 1) { // 减一的原因,是因为拆分时,如果按照比例,可能会出现.所以最后一个,使用反减 | |
| 531 | - partPrice = (int) (price * (1.0D * orderItem.getOrderDividePrice() / total)); | |
| 532 | - remainPrice -= partPrice; | |
| 533 | - } else { | |
| 534 | - partPrice = remainPrice; | |
| 535 | - } | |
| 536 | - Assert.isTrue(partPrice > 0, "分摊金额必须大于 0"); | |
| 537 | - prices.add(partPrice); | |
| 538 | - } | |
| 539 | - return prices; | |
| 540 | - } | |
| 541 | - | |
| 542 | - private String formatPrice(Integer price) { | |
| 543 | - return String.format("%.2f", price / 100d); | |
| 544 | - } | |
| 545 | - | |
| 546 | 96 | } | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityService.java
| 1 | 1 | package cn.iocoder.yudao.module.promotion.service.reward; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | +import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO; | |
| 4 | 5 | import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityCreateReqVO; |
| 5 | 6 | import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO; |
| 6 | 7 | import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityUpdateReqVO; |
| 7 | 8 | import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; |
| 8 | 9 | |
| 9 | 10 | import javax.validation.Valid; |
| 10 | -import java.util.Map; | |
| 11 | -import java.util.Set; | |
| 11 | +import java.util.Collection; | |
| 12 | +import java.util.List; | |
| 12 | 13 | |
| 13 | 14 | /** |
| 14 | 15 | * 满减送活动 Service 接口 |
| ... | ... | @@ -66,8 +67,8 @@ public interface RewardActivityService { |
| 66 | 67 | * 基于指定的 SPU 编号数组,获得它们匹配的满减送活动 |
| 67 | 68 | * |
| 68 | 69 | * @param spuIds SPU 编号数组 |
| 69 | - * @return 满减送活动,与对应的 SPU 编号的映射。即,value 就是 SPU 编号的集合 | |
| 70 | + * @return 满减送活动列表 | |
| 70 | 71 | */ |
| 71 | - Map<RewardActivityDO, Set<Long>> getMatchRewardActivities(Set<Long> spuIds); | |
| 72 | + List<RewardActivityMatchRespDTO> getMatchRewardActivityList(Collection<Long> spuIds); | |
| 72 | 73 | |
| 73 | 74 | } | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityServiceImpl.java
| 1 | 1 | package cn.iocoder.yudao.module.promotion.service.reward; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | -import cn.hutool.core.map.MapUtil; | |
| 5 | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | +import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO; | |
| 6 | 6 | import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityCreateReqVO; |
| 7 | 7 | import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO; |
| 8 | 8 | import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityUpdateReqVO; |
| ... | ... | @@ -10,7 +10,6 @@ import cn.iocoder.yudao.module.promotion.convert.reward.RewardActivityConvert; |
| 10 | 10 | import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; |
| 11 | 11 | import cn.iocoder.yudao.module.promotion.dal.mysql.reward.RewardActivityMapper; |
| 12 | 12 | import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum; |
| 13 | -import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; | |
| 14 | 13 | import cn.iocoder.yudao.module.promotion.util.PromotionUtils; |
| 15 | 14 | import org.springframework.stereotype.Service; |
| 16 | 15 | import org.springframework.validation.annotation.Validated; |
| ... | ... | @@ -18,15 +17,10 @@ import org.springframework.validation.annotation.Validated; |
| 18 | 17 | import javax.annotation.Resource; |
| 19 | 18 | import java.util.Collection; |
| 20 | 19 | import java.util.List; |
| 21 | -import java.util.Map; | |
| 22 | -import java.util.Set; | |
| 23 | 20 | |
| 24 | -import static cn.hutool.core.collection.CollUtil.intersectionDistinct; | |
| 25 | 21 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 26 | -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; | |
| 27 | 22 | import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; |
| 28 | 23 | import static java.util.Arrays.asList; |
| 29 | -import static java.util.Collections.singleton; | |
| 30 | 24 | |
| 31 | 25 | /** |
| 32 | 26 | * 满减送活动 Service 实现类 |
| ... | ... | @@ -105,6 +99,7 @@ public class RewardActivityServiceImpl implements RewardActivityService { |
| 105 | 99 | return activity; |
| 106 | 100 | } |
| 107 | 101 | |
| 102 | + // TODO @芋艿:逻辑有问题,需要优化;要分成全场、和指定来校验; | |
| 108 | 103 | /** |
| 109 | 104 | * 校验商品参加的活动是否冲突 |
| 110 | 105 | * |
| ... | ... | @@ -151,19 +146,21 @@ public class RewardActivityServiceImpl implements RewardActivityService { |
| 151 | 146 | } |
| 152 | 147 | |
| 153 | 148 | @Override |
| 154 | - public Map<RewardActivityDO, Set<Long>> getMatchRewardActivities(Set<Long> spuIds) { | |
| 155 | - // 如果有全局活动,则直接选择它 | |
| 156 | - List<RewardActivityDO> allActivities = rewardActivityMapper.selectListByProductScopeAndStatus( | |
| 157 | - PromotionProductScopeEnum.ALL.getScope(), PromotionActivityStatusEnum.RUN.getStatus()); | |
| 158 | - if (CollUtil.isNotEmpty(allActivities)) { | |
| 159 | - return MapUtil.builder(allActivities.get(0), spuIds).build(); | |
| 160 | - } | |
| 161 | - | |
| 162 | - // 查询某个活动参加的活动 | |
| 163 | - List<RewardActivityDO> productActivityList = getRewardActivityListBySpuIds(spuIds, | |
| 164 | - singleton(PromotionActivityStatusEnum.RUN.getStatus())); | |
| 165 | - return convertMap(productActivityList, activity -> activity, | |
| 166 | - rewardActivityDO -> intersectionDistinct(rewardActivityDO.getProductSpuIds(), spuIds)); // 求交集返回 | |
| 149 | + public List<RewardActivityMatchRespDTO> getMatchRewardActivityList(Collection<Long> spuIds) { | |
| 150 | + // TODO 芋艿:待实现;先指定,然后再全局的; | |
| 151 | +// // 如果有全局活动,则直接选择它 | |
| 152 | +// List<RewardActivityDO> allActivities = rewardActivityMapper.selectListByProductScopeAndStatus( | |
| 153 | +// PromotionProductScopeEnum.ALL.getScope(), PromotionActivityStatusEnum.RUN.getStatus()); | |
| 154 | +// if (CollUtil.isNotEmpty(allActivities)) { | |
| 155 | +// return MapUtil.builder(allActivities.get(0), spuIds).build(); | |
| 156 | +// } | |
| 157 | +// | |
| 158 | +// // 查询某个活动参加的活动 | |
| 159 | +// List<RewardActivityDO> productActivityList = getRewardActivityListBySpuIds(spuIds, | |
| 160 | +// singleton(PromotionActivityStatusEnum.RUN.getStatus())); | |
| 161 | +// return convertMap(productActivityList, activity -> activity, | |
| 162 | +// rewardActivityDO -> intersectionDistinct(rewardActivityDO.getProductSpuIds(), spuIds)); // 求交集返回 | |
| 163 | + return null; | |
| 167 | 164 | } |
| 168 | 165 | |
| 169 | 166 | } | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/price/PriceServiceTest.java
| ... | ... | @@ -96,8 +96,8 @@ public class PriceServiceTest extends BaseMockitoUnitTest { |
| 96 | 96 | assertEquals(promotion.getLevel(), PromotionLevelEnum.SKU.getLevel()); |
| 97 | 97 | assertEquals(promotion.getTotalPrice(), 200); |
| 98 | 98 | assertEquals(promotion.getDiscountPrice(), 20); |
| 99 | - assertTrue(promotion.getMeet()); | |
| 100 | - assertEquals(promotion.getMeetTip(), "会员折扣:省 0.20 元"); | |
| 99 | + assertTrue(promotion.getMatch()); | |
| 100 | + assertEquals(promotion.getDescription(), "会员折扣:省 0.20 元"); | |
| 101 | 101 | PriceCalculateRespDTO.PromotionItem promotionItem = promotion.getItems().get(0); |
| 102 | 102 | assertEquals(promotion.getItems().size(), 1); |
| 103 | 103 | assertEquals(promotionItem.getSkuId(), 10L); |
| ... | ... | @@ -122,7 +122,7 @@ public class PriceServiceTest extends BaseMockitoUnitTest { |
| 122 | 122 | DiscountProductDetailBO discountProduct02 = randomPojo(DiscountProductDetailBO.class, o -> o.setActivityId(2000L) |
| 123 | 123 | .setActivityName("活动 2000 号").setSkuId(20L) |
| 124 | 124 | .setDiscountType(PromotionDiscountTypeEnum.PERCENT.getType()).setDiscountPercent(60)); |
| 125 | - when(discountService.getMatchDiscountProducts(eq(asSet(10L, 20L)))).thenReturn( | |
| 125 | + when(discountService.getMatchDiscountProductList(eq(asSet(10L, 20L)))).thenReturn( | |
| 126 | 126 | MapUtil.builder(10L, discountProduct01).put(20L, discountProduct02).map()); |
| 127 | 127 | |
| 128 | 128 | // 10L: 100 * 2 - 40 * 2 = 120 |
| ... | ... | @@ -167,8 +167,8 @@ public class PriceServiceTest extends BaseMockitoUnitTest { |
| 167 | 167 | assertEquals(promotion01.getLevel(), PromotionLevelEnum.SKU.getLevel()); |
| 168 | 168 | assertEquals(promotion01.getTotalPrice(), 200); |
| 169 | 169 | assertEquals(promotion01.getDiscountPrice(), 80); |
| 170 | - assertTrue(promotion01.getMeet()); | |
| 171 | - assertEquals(promotion01.getMeetTip(), "限时折扣:省 0.80 元"); | |
| 170 | + assertTrue(promotion01.getMatch()); | |
| 171 | + assertEquals(promotion01.getDescription(), "限时折扣:省 0.80 元"); | |
| 172 | 172 | PriceCalculateRespDTO.PromotionItem promotionItem01 = promotion01.getItems().get(0); |
| 173 | 173 | assertEquals(promotion01.getItems().size(), 1); |
| 174 | 174 | assertEquals(promotionItem01.getSkuId(), 10L); |
| ... | ... | @@ -181,8 +181,8 @@ public class PriceServiceTest extends BaseMockitoUnitTest { |
| 181 | 181 | assertEquals(promotion02.getLevel(), PromotionLevelEnum.SKU.getLevel()); |
| 182 | 182 | assertEquals(promotion02.getTotalPrice(), 150); |
| 183 | 183 | assertEquals(promotion02.getDiscountPrice(), 60); |
| 184 | - assertTrue(promotion02.getMeet()); | |
| 185 | - assertEquals(promotion02.getMeetTip(), "限时折扣:省 0.60 元"); | |
| 184 | + assertTrue(promotion02.getMatch()); | |
| 185 | + assertEquals(promotion02.getDescription(), "限时折扣:省 0.60 元"); | |
| 186 | 186 | PriceCalculateRespDTO.PromotionItem promotionItem02 = promotion02.getItems().get(0); |
| 187 | 187 | assertEquals(promotion02.getItems().size(), 1); |
| 188 | 188 | assertEquals(promotionItem02.getSkuId(), 20L); |
| ... | ... | @@ -267,8 +267,8 @@ public class PriceServiceTest extends BaseMockitoUnitTest { |
| 267 | 267 | assertEquals(promotion01.getLevel(), PromotionLevelEnum.ORDER.getLevel()); |
| 268 | 268 | assertEquals(promotion01.getTotalPrice(), 350); |
| 269 | 269 | assertEquals(promotion01.getDiscountPrice(), 70); |
| 270 | - assertTrue(promotion01.getMeet()); | |
| 271 | - assertEquals(promotion01.getMeetTip(), "满减送:省 0.70 元"); | |
| 270 | + assertTrue(promotion01.getMatch()); | |
| 271 | + assertEquals(promotion01.getDescription(), "满减送:省 0.70 元"); | |
| 272 | 272 | assertEquals(promotion01.getItems().size(), 2); |
| 273 | 273 | PriceCalculateRespDTO.PromotionItem promotionItem011 = promotion01.getItems().get(0); |
| 274 | 274 | assertEquals(promotionItem011.getSkuId(), 10L); |
| ... | ... | @@ -286,8 +286,8 @@ public class PriceServiceTest extends BaseMockitoUnitTest { |
| 286 | 286 | assertEquals(promotion02.getLevel(), PromotionLevelEnum.ORDER.getLevel()); |
| 287 | 287 | assertEquals(promotion02.getTotalPrice(), 120); |
| 288 | 288 | assertEquals(promotion02.getDiscountPrice(), 60); |
| 289 | - assertTrue(promotion02.getMeet()); | |
| 290 | - assertEquals(promotion02.getMeetTip(), "满减送:省 0.60 元"); | |
| 289 | + assertTrue(promotion02.getMatch()); | |
| 290 | + assertEquals(promotion02.getDescription(), "满减送:省 0.60 元"); | |
| 291 | 291 | PriceCalculateRespDTO.PromotionItem promotionItem02 = promotion02.getItems().get(0); |
| 292 | 292 | assertEquals(promotion02.getItems().size(), 1); |
| 293 | 293 | assertEquals(promotionItem02.getSkuId(), 30L); |
| ... | ... | @@ -355,8 +355,8 @@ public class PriceServiceTest extends BaseMockitoUnitTest { |
| 355 | 355 | assertEquals(promotion01.getLevel(), PromotionLevelEnum.ORDER.getLevel()); |
| 356 | 356 | assertEquals(promotion01.getTotalPrice(), 350); |
| 357 | 357 | assertEquals(promotion01.getDiscountPrice(), 0); |
| 358 | - assertFalse(promotion01.getMeet()); | |
| 359 | - assertEquals(promotion01.getMeetTip(), "TODO"); // TODO 芋艿:后面再想想 | |
| 358 | + assertFalse(promotion01.getMatch()); | |
| 359 | + assertEquals(promotion01.getDescription(), "TODO"); // TODO 芋艿:后面再想想 | |
| 360 | 360 | assertEquals(promotion01.getItems().size(), 2); |
| 361 | 361 | PriceCalculateRespDTO.PromotionItem promotionItem011 = promotion01.getItems().get(0); |
| 362 | 362 | assertEquals(promotionItem011.getSkuId(), 10L); |
| ... | ... | @@ -437,8 +437,8 @@ public class PriceServiceTest extends BaseMockitoUnitTest { |
| 437 | 437 | assertEquals(promotion01.getLevel(), PromotionLevelEnum.COUPON.getLevel()); |
| 438 | 438 | assertEquals(promotion01.getTotalPrice(), 350); |
| 439 | 439 | assertEquals(promotion01.getDiscountPrice(), 70); |
| 440 | - assertTrue(promotion01.getMeet()); | |
| 441 | - assertEquals(promotion01.getMeetTip(), "优惠劵:省 0.70 元"); | |
| 440 | + assertTrue(promotion01.getMatch()); | |
| 441 | + assertEquals(promotion01.getDescription(), "优惠劵:省 0.70 元"); | |
| 442 | 442 | assertEquals(promotion01.getItems().size(), 2); |
| 443 | 443 | PriceCalculateRespDTO.PromotionItem promotionItem011 = promotion01.getItems().get(0); |
| 444 | 444 | assertEquals(promotionItem011.getSkuId(), 10L); | ... | ... |
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java
| ... | ... | @@ -50,4 +50,8 @@ public interface ErrorCodeConstants { |
| 50 | 50 | ErrorCode EXPRESS_CODE_DUPLICATE = new ErrorCode(1011003001, "已经存在该编码的快递公司"); |
| 51 | 51 | ErrorCode EXPRESS_TEMPLATE_NOT_EXISTS = new ErrorCode(1011003002, "运费模板不存在"); |
| 52 | 52 | ErrorCode EXPRESS_TEMPLATE_NAME_DUPLICATE = new ErrorCode(1011003002, "已经存在该运费模板名"); |
| 53 | + | |
| 54 | + // ========== Price 相关 1011004000 ============ | |
| 55 | + ErrorCode PRICE_CALCULATE_PAY_PRICE_ILLEGAL = new ErrorCode(1011004000, "支付价格计算异常,原因:价格小于等于 0"); | |
| 56 | + | |
| 53 | 57 | } | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/DeliveryExpressController.java
| ... | ... | @@ -4,7 +4,8 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | 5 | import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; |
| 6 | 6 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; |
| 7 | -import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.*; | |
| 7 | +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express.*; | |
| 8 | +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express.DeliveryExpressUpdateReqVO; | |
| 8 | 9 | import cn.iocoder.yudao.module.trade.convert.delivery.DeliveryExpressConvert; |
| 9 | 10 | import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO; |
| 10 | 11 | import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService; | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/DeliveryExpressTemplateController.java
| 1 | 1 | package cn.iocoder.yudao.module.trade.controller.admin.delivery; |
| 2 | 2 | |
| 3 | -import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.*; | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | |
| 4 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 5 | +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.*; | |
| 4 | 6 | import cn.iocoder.yudao.module.trade.convert.delivery.DeliveryExpressTemplateConvert; |
| 5 | 7 | import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateDO; |
| 6 | 8 | import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressTemplateService; |
| 7 | -import org.springframework.web.bind.annotation.*; | |
| 8 | -import javax.annotation.Resource; | |
| 9 | -import org.springframework.validation.annotation.Validated; | |
| 10 | -import org.springframework.security.access.prepost.PreAuthorize; | |
| 11 | -import io.swagger.v3.oas.annotations.tags.Tag; | |
| 12 | -import io.swagger.v3.oas.annotations.Parameter; | |
| 13 | 9 | import io.swagger.v3.oas.annotations.Operation; |
| 10 | +import io.swagger.v3.oas.annotations.Parameter; | |
| 11 | +import io.swagger.v3.oas.annotations.tags.Tag; | |
| 12 | +import org.springframework.security.access.prepost.PreAuthorize; | |
| 13 | +import org.springframework.validation.annotation.Validated; | |
| 14 | +import org.springframework.web.bind.annotation.*; | |
| 14 | 15 | |
| 15 | -import javax.validation.*; | |
| 16 | -import javax.servlet.http.*; | |
| 17 | -import java.util.*; | |
| 18 | -import java.io.IOException; | |
| 16 | +import javax.annotation.Resource; | |
| 17 | +import javax.validation.Valid; | |
| 18 | +import java.util.Collection; | |
| 19 | +import java.util.List; | |
| 19 | 20 | |
| 20 | -import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 21 | -import cn.iocoder.yudao.framework.common.pojo.CommonResult; | |
| 22 | 21 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 23 | 22 | |
| 24 | -import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; | |
| 25 | - | |
| 26 | -import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; | |
| 27 | -import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*; | |
| 28 | - | |
| 29 | 23 | |
| 30 | 24 | @Tag(name = "管理后台 - 快递运费模板") |
| 31 | 25 | @RestController |
| ... | ... | @@ -84,4 +78,5 @@ public class DeliveryExpressTemplateController { |
| 84 | 78 | PageResult<DeliveryExpressTemplateDO> pageResult = deliveryExpressTemplateService.getDeliveryExpressTemplatePage(pageVO); |
| 85 | 79 | return success(DeliveryExpressTemplateConvert.INSTANCE.convertPage(pageResult)); |
| 86 | 80 | } |
| 81 | + | |
| 87 | 82 | } | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/DeliveryExpressBaseVO.java renamed to yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressBaseVO.java
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/DeliveryExpressCreateReqVO.java renamed to yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressCreateReqVO.java
| 1 | -package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo; | |
| 1 | +package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express; | |
| 2 | 2 | |
| 3 | 3 | import lombok.*; |
| 4 | -import java.util.*; | |
| 5 | 4 | import io.swagger.v3.oas.annotations.media.Schema; |
| 6 | -import javax.validation.constraints.*; | |
| 7 | 5 | |
| 8 | 6 | @Schema(description = "管理后台 - 快递公司创建 Request VO") |
| 9 | 7 | @Data | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/DeliveryExpressExcelVO.java renamed to yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressExcelVO.java
| 1 | -package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo; | |
| 1 | +package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express; | |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; |
| 4 | 4 | import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/DeliveryExpressExportReqVO.java renamed to yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressExportReqVO.java
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/DeliveryExpressPageReqVO.java renamed to yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressPageReqVO.java
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/DeliveryExpressRespVO.java renamed to yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressRespVO.java
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/DeliveryExpressUpdateReqVO.java renamed to yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressUpdateReqVO.java
| 1 | -package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo; | |
| 1 | +package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express; | |
| 2 | 2 | |
| 3 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | -import lombok.*; | |
| 5 | -import java.util.*; | |
| 6 | -import javax.validation.constraints.*; | |
| 4 | +import lombok.Data; | |
| 5 | +import lombok.EqualsAndHashCode; | |
| 6 | +import lombok.ToString; | |
| 7 | + | |
| 8 | +import javax.validation.constraints.NotNull; | |
| 7 | 9 | |
| 8 | 10 | @Schema(description = "管理后台 - 快递公司更新 Request VO") |
| 9 | 11 | @Data | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/DeliveryExpressTemplateBaseVO.java renamed to yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateBaseVO.java
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/DeliveryExpressTemplateCreateReqVO.java renamed to yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateCreateReqVO.java
| 1 | -package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo; | |
| 1 | +package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate; | |
| 2 | 2 | |
| 3 | -import lombok.*; | |
| 4 | -import java.util.*; | |
| 5 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | +import lombok.Data; | |
| 5 | +import lombok.EqualsAndHashCode; | |
| 6 | +import lombok.ToString; | |
| 6 | 7 | |
| 7 | 8 | import javax.validation.Valid; |
| 9 | +import java.util.Collections; | |
| 10 | +import java.util.List; | |
| 8 | 11 | |
| 9 | 12 | @Schema(description = "管理后台 - 快递运费模板创建 Request VO") |
| 10 | 13 | @Data |
| ... | ... | @@ -12,6 +15,8 @@ import javax.validation.Valid; |
| 12 | 15 | @ToString(callSuper = true) |
| 13 | 16 | public class DeliveryExpressTemplateCreateReqVO extends DeliveryExpressTemplateBaseVO { |
| 14 | 17 | |
| 18 | + // TODO @jason:不用给默认值哈 | |
| 19 | + | |
| 15 | 20 | @Schema(description = "区域运费列表") |
| 16 | 21 | @Valid |
| 17 | 22 | private List<ExpressTemplateChargeBaseVO> templateCharge = Collections.emptyList(); | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/DeliveryExpressTemplatePageReqVO.java renamed to yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplatePageReqVO.java
| 1 | -package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo; | |
| 1 | +package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate; | |
| 2 | 2 | |
| 3 | -import lombok.*; | |
| 4 | -import java.util.*; | |
| 5 | -import io.swagger.v3.oas.annotations.media.Schema; | |
| 6 | 3 | import cn.iocoder.yudao.framework.common.pojo.PageParam; |
| 4 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 5 | +import lombok.Data; | |
| 6 | +import lombok.EqualsAndHashCode; | |
| 7 | +import lombok.ToString; | |
| 7 | 8 | import org.springframework.format.annotation.DateTimeFormat; |
| 9 | + | |
| 8 | 10 | import java.time.LocalDateTime; |
| 9 | 11 | |
| 10 | 12 | import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/DeliveryExpressTemplateRespVO.java renamed to yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateRespVO.java
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/DeliveryExpressTemplateSimpleRespVO.java renamed to yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateSimpleRespVO.java
| 1 | -package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo; | |
| 1 | +package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate; | |
| 2 | 2 | |
| 3 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | 4 | import lombok.*; |
| 5 | 5 | import java.time.LocalDateTime; |
| 6 | 6 | |
| 7 | +// TODO @jason:simplae 是不是不用继承 DeliveryExpressTemplateBaseVO,直接 id name 属性就够了。 | |
| 7 | 8 | @Schema(description = "管理后台 - 快递运费模板 精简 Response VO") |
| 8 | 9 | @Data |
| 9 | 10 | @EqualsAndHashCode(callSuper = true) | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/DeliveryExpressTemplateUpdateReqVO.java renamed to yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateUpdateReqVO.java
| 1 | -package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo; | |
| 1 | +package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate; | |
| 2 | 2 | |
| 3 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | -import lombok.*; | |
| 5 | -import java.util.*; | |
| 4 | +import lombok.Data; | |
| 5 | +import lombok.EqualsAndHashCode; | |
| 6 | +import lombok.ToString; | |
| 7 | + | |
| 6 | 8 | import javax.validation.Valid; |
| 7 | -import javax.validation.constraints.*; | |
| 9 | +import javax.validation.constraints.NotNull; | |
| 10 | +import java.util.Collections; | |
| 11 | +import java.util.List; | |
| 8 | 12 | |
| 9 | 13 | @Schema(description = "管理后台 - 快递运费模板更新 Request VO") |
| 10 | 14 | @Data |
| ... | ... | @@ -16,6 +20,8 @@ public class DeliveryExpressTemplateUpdateReqVO extends DeliveryExpressTemplateB |
| 16 | 20 | @NotNull(message = "编号不能为空") |
| 17 | 21 | private Long id; |
| 18 | 22 | |
| 23 | + // TODO @jason:pojo 不给默认值哈 | |
| 24 | + | |
| 19 | 25 | @Schema(description = "区域运费列表") |
| 20 | 26 | @Valid |
| 21 | 27 | private List<ExpressTemplateChargeUpdateVO> templateCharge = Collections.emptyList(); | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/ExpressTemplateChargeBaseVO.java renamed to yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/ExpressTemplateChargeBaseVO.java
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/ExpressTemplateChargeUpdateVO.java renamed to yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/ExpressTemplateChargeUpdateVO.java
| 1 | -package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo; | |
| 1 | +package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate; | |
| 2 | 2 | |
| 3 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | 4 | import lombok.Data; |
| 5 | 5 | |
| 6 | - | |
| 6 | +// TODO @jason:这个 vo 可以内嵌到 DeliveryExpressTemplateUpdateReqVO,避免 vo 过多,不好分辨 | |
| 7 | +@Schema(description = "管理后台 - 快递公司创建 Request VO") | |
| 7 | 8 | @Data |
| 8 | 9 | public class ExpressTemplateChargeUpdateVO extends ExpressTemplateChargeBaseVO { |
| 9 | 10 | |
| 10 | 11 | @Schema(description = "编号", example = "6592") |
| 11 | 12 | private Long id; |
| 12 | 13 | |
| 14 | + // TODO @jason:这几个字段,应该不通过前端传递,而是后端查询后去赋值的 | |
| 15 | + | |
| 13 | 16 | @Schema(description = "配送模板编号", example = "1") |
| 14 | 17 | private Long templateId; |
| 15 | 18 | |
| 16 | 19 | @Schema(description = "配送计费方式", example = "1") |
| 17 | 20 | private Integer chargeMode; |
| 21 | + | |
| 18 | 22 | } | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/ExpressTemplateFreeBaseVO.java renamed to yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/ExpressTemplateFreeBaseVO.java
| 1 | -package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo; | |
| 1 | +package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate; | |
| 2 | 2 | |
| 3 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | 4 | import lombok.Data; |
| ... | ... | @@ -24,4 +24,5 @@ public class ExpressTemplateFreeBaseVO { |
| 24 | 24 | @Schema(description = "包邮件数", requiredMode = Schema.RequiredMode.REQUIRED, example = "5") |
| 25 | 25 | @NotNull(message = "包邮件数不能为空") |
| 26 | 26 | private Integer freeCount; |
| 27 | + | |
| 27 | 28 | } | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/ExpressTemplateFreeUpdateVO.java renamed to yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/ExpressTemplateFreeUpdateVO.java
| 1 | -package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo; | |
| 1 | +package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate; | |
| 2 | 2 | |
| 3 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | 4 | import lombok.Data; |
| 5 | 5 | |
| 6 | +// TODO @jason:这个 vo 可以内嵌到 DeliveryExpressTemplateUpdateReqVO,避免 vo 过多,不好分辨 | |
| 7 | +// TODO @jason:swagger 缺失 | |
| 6 | 8 | /** |
| 7 | 9 | * 快递运费模板包邮 更新 VO |
| 8 | 10 | */ | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/delivery/DeliveryExpressConvert.java
| ... | ... | @@ -4,10 +4,10 @@ import java.util.*; |
| 4 | 4 | |
| 5 | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | 6 | |
| 7 | -import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.DeliveryExpressCreateReqVO; | |
| 8 | -import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.DeliveryExpressExcelVO; | |
| 9 | -import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.DeliveryExpressRespVO; | |
| 10 | -import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.DeliveryExpressUpdateReqVO; | |
| 7 | +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express.DeliveryExpressCreateReqVO; | |
| 8 | +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express.DeliveryExpressExcelVO; | |
| 9 | +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express.DeliveryExpressRespVO; | |
| 10 | +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express.DeliveryExpressUpdateReqVO; | |
| 11 | 11 | import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO; |
| 12 | 12 | import org.mapstruct.Mapper; |
| 13 | 13 | import org.mapstruct.factory.Mappers; | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/delivery/DeliveryExpressTemplateConvert.java
| 1 | 1 | package cn.iocoder.yudao.module.trade.convert.delivery; |
| 2 | 2 | |
| 3 | -import cn.hutool.core.collection.CollUtil; | |
| 4 | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | 4 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; |
| 6 | -import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.*; | |
| 5 | +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.*; | |
| 7 | 6 | import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateChargeDO; |
| 8 | 7 | import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateDO; |
| 9 | 8 | import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateFreeDO; |
| 10 | 9 | import org.mapstruct.Mapper; |
| 11 | 10 | import org.mapstruct.factory.Mappers; |
| 12 | 11 | |
| 13 | -import java.util.ArrayList; | |
| 14 | -import java.util.Collections; | |
| 15 | 12 | import java.util.List; |
| 16 | 13 | |
| 17 | 14 | /** | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/delivery/DeliveryExpressMapper.java
| ... | ... | @@ -3,8 +3,8 @@ package cn.iocoder.yudao.module.trade.dal.mysql.delivery; |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | 4 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| 5 | 5 | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| 6 | -import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.DeliveryExpressExportReqVO; | |
| 7 | -import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.DeliveryExpressPageReqVO; | |
| 6 | +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express.DeliveryExpressExportReqVO; | |
| 7 | +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express.DeliveryExpressPageReqVO; | |
| 8 | 8 | import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO; |
| 9 | 9 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| 10 | 10 | import org.apache.ibatis.annotations.Mapper; | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/delivery/DeliveryExpressTemplateMapper.java
| ... | ... | @@ -4,7 +4,7 @@ package cn.iocoder.yudao.module.trade.dal.mysql.delivery; |
| 4 | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | 5 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| 6 | 6 | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| 7 | -import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.DeliveryExpressTemplatePageReqVO; | |
| 7 | +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplatePageReqVO; | |
| 8 | 8 | import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateDO; |
| 9 | 9 | import org.apache.ibatis.annotations.Mapper; |
| 10 | 10 | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressService.java
| ... | ... | @@ -4,10 +4,10 @@ import java.util.*; |
| 4 | 4 | import javax.validation.*; |
| 5 | 5 | |
| 6 | 6 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 7 | -import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.DeliveryExpressCreateReqVO; | |
| 8 | -import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.DeliveryExpressExportReqVO; | |
| 9 | -import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.DeliveryExpressPageReqVO; | |
| 10 | -import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.DeliveryExpressUpdateReqVO; | |
| 7 | +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express.DeliveryExpressCreateReqVO; | |
| 8 | +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express.DeliveryExpressExportReqVO; | |
| 9 | +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express.DeliveryExpressPageReqVO; | |
| 10 | +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express.DeliveryExpressUpdateReqVO; | |
| 11 | 11 | import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO; |
| 12 | 12 | |
| 13 | 13 | /** | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressServiceImpl.java
| 1 | 1 | package cn.iocoder.yudao.module.trade.service.delivery; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | -import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.DeliveryExpressCreateReqVO; | |
| 5 | -import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.DeliveryExpressExportReqVO; | |
| 6 | -import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.DeliveryExpressPageReqVO; | |
| 7 | -import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.DeliveryExpressUpdateReqVO; | |
| 4 | +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express.DeliveryExpressCreateReqVO; | |
| 5 | +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express.DeliveryExpressExportReqVO; | |
| 6 | +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express.DeliveryExpressPageReqVO; | |
| 7 | +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express.DeliveryExpressUpdateReqVO; | |
| 8 | 8 | import cn.iocoder.yudao.module.trade.convert.delivery.DeliveryExpressConvert; |
| 9 | 9 | import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO; |
| 10 | 10 | import cn.iocoder.yudao.module.trade.dal.mysql.delivery.DeliveryExpressMapper; | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressTemplateService.java
| 1 | 1 | package cn.iocoder.yudao.module.trade.service.delivery; |
| 2 | 2 | |
| 3 | -import java.util.*; | |
| 4 | -import javax.validation.*; | |
| 5 | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | -import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.*; | |
| 4 | +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplateCreateReqVO; | |
| 5 | +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplatePageReqVO; | |
| 6 | +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplateRespVO; | |
| 7 | +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplateUpdateReqVO; | |
| 7 | 8 | import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateDO; |
| 8 | 9 | |
| 10 | +import javax.validation.Valid; | |
| 11 | +import java.util.Collection; | |
| 12 | +import java.util.List; | |
| 13 | + | |
| 9 | 14 | /** |
| 10 | 15 | * 快递运费模板 Service 接口 |
| 11 | 16 | * | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressTemplateServiceImpl.java
| ... | ... | @@ -2,8 +2,7 @@ package cn.iocoder.yudao.module.trade.service.delivery; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | |
| 6 | -import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.*; | |
| 5 | +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.*; | |
| 7 | 6 | import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateChargeDO; |
| 8 | 7 | import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateDO; |
| 9 | 8 | import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateFreeDO; |
| ... | ... | @@ -18,8 +17,10 @@ import javax.annotation.Resource; |
| 18 | 17 | import java.util.*; |
| 19 | 18 | |
| 20 | 19 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 20 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | |
| 21 | 21 | import static cn.iocoder.yudao.module.trade.convert.delivery.DeliveryExpressTemplateConvert.INSTANCE; |
| 22 | -import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; | |
| 22 | +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.EXPRESS_TEMPLATE_NAME_DUPLICATE; | |
| 23 | +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.EXPRESS_TEMPLATE_NOT_EXISTS; | |
| 23 | 24 | |
| 24 | 25 | /** |
| 25 | 26 | * 快递运费模板 Service 实现类 |
| ... | ... | @@ -42,6 +43,7 @@ public class DeliveryExpressTemplateServiceImpl implements DeliveryExpressTempla |
| 42 | 43 | public Long createDeliveryExpressTemplate(DeliveryExpressTemplateCreateReqVO createReqVO) { |
| 43 | 44 | // 校验模板名是否唯一 |
| 44 | 45 | validateTemplateNameUnique(createReqVO.getName(), null); |
| 46 | + | |
| 45 | 47 | // 插入 |
| 46 | 48 | DeliveryExpressTemplateDO deliveryExpressTemplate = INSTANCE.convert(createReqVO); |
| 47 | 49 | expressTemplateMapper.insert(deliveryExpressTemplate); |
| ... | ... | @@ -67,6 +69,7 @@ public class DeliveryExpressTemplateServiceImpl implements DeliveryExpressTempla |
| 67 | 69 | validateDeliveryExpressTemplateExists(updateReqVO.getId()); |
| 68 | 70 | // 校验模板名是否唯一 |
| 69 | 71 | validateTemplateNameUnique(updateReqVO.getName(), updateReqVO.getId()); |
| 72 | + | |
| 70 | 73 | // 更新运费从表 |
| 71 | 74 | updateExpressTemplateCharge(updateReqVO); |
| 72 | 75 | // 更新包邮从表 |
| ... | ... | @@ -77,12 +80,11 @@ public class DeliveryExpressTemplateServiceImpl implements DeliveryExpressTempla |
| 77 | 80 | } |
| 78 | 81 | |
| 79 | 82 | private void updateExpressTemplateFree(DeliveryExpressTemplateUpdateReqVO updateReqVO) { |
| 83 | + // 1.1 获得新增/修改的区域列表 | |
| 80 | 84 | List<DeliveryExpressTemplateFreeDO> oldFreeList = expressTemplateFreeMapper.selectListByTemplateId(updateReqVO.getId()); |
| 81 | 85 | List<ExpressTemplateFreeUpdateVO> newFreeList = updateReqVO.getTemplateFree(); |
| 82 | - // 新增包邮区域列表 | |
| 83 | - List<DeliveryExpressTemplateFreeDO> addFreeList = new ArrayList<>(newFreeList.size()); | |
| 84 | - // 更新包邮区域列表 | |
| 85 | - List<DeliveryExpressTemplateFreeDO> updateFreeList = new ArrayList<>(newFreeList.size()); | |
| 86 | + List<DeliveryExpressTemplateFreeDO> addFreeList = new ArrayList<>(newFreeList.size()); // 新增包邮区域列表 | |
| 87 | + List<DeliveryExpressTemplateFreeDO> updateFreeList = new ArrayList<>(newFreeList.size()); // 更新包邮区域列表 | |
| 86 | 88 | for (ExpressTemplateFreeUpdateVO item : newFreeList) { |
| 87 | 89 | if (Objects.nonNull(item.getId())) { |
| 88 | 90 | updateFreeList.add(INSTANCE.convertTemplateFree(item)); |
| ... | ... | @@ -91,30 +93,29 @@ public class DeliveryExpressTemplateServiceImpl implements DeliveryExpressTempla |
| 91 | 93 | addFreeList.add(INSTANCE.convertTemplateFree(item)); |
| 92 | 94 | } |
| 93 | 95 | } |
| 94 | - // 新增 | |
| 96 | + // 1.2 新增 | |
| 95 | 97 | if (CollUtil.isNotEmpty(addFreeList)) { |
| 96 | 98 | expressTemplateFreeMapper.insertBatch(addFreeList); |
| 97 | 99 | } |
| 98 | - // 修改 | |
| 100 | + // 1.3 修改 | |
| 99 | 101 | if (CollUtil.isNotEmpty(updateFreeList)) { |
| 100 | 102 | expressTemplateFreeMapper.updateBatch(updateFreeList); |
| 101 | 103 | } |
| 102 | - // 得到删除ids | |
| 103 | - Set<Long> deleteFreeIds = CollectionUtils.convertSet(oldFreeList, DeliveryExpressTemplateFreeDO::getId); | |
| 104 | - deleteFreeIds.removeAll(CollectionUtils.convertSet(updateFreeList, DeliveryExpressTemplateFreeDO::getId)); | |
| 105 | - //删除 | |
| 104 | + | |
| 105 | + // 2. 删除 | |
| 106 | + Set<Long> deleteFreeIds = convertSet(oldFreeList, DeliveryExpressTemplateFreeDO::getId); | |
| 107 | + deleteFreeIds.removeAll(convertSet(updateFreeList, DeliveryExpressTemplateFreeDO::getId)); | |
| 106 | 108 | if (CollUtil.isNotEmpty(deleteFreeIds)) { |
| 107 | 109 | expressTemplateFreeMapper.deleteBatchIds(deleteFreeIds); |
| 108 | 110 | } |
| 109 | 111 | } |
| 110 | 112 | |
| 111 | 113 | private void updateExpressTemplateCharge(DeliveryExpressTemplateUpdateReqVO updateReqVO) { |
| 114 | + // 1.1 获得新增/修改的区域列表 | |
| 112 | 115 | List<DeliveryExpressTemplateChargeDO> oldChargeList = expressTemplateChargeMapper.selectListByTemplateId(updateReqVO.getId()); |
| 113 | 116 | List<ExpressTemplateChargeUpdateVO> newChargeList = updateReqVO.getTemplateCharge(); |
| 114 | - // 新增运费区域列表 | |
| 115 | - List<DeliveryExpressTemplateChargeDO> addList = new ArrayList<>(newChargeList.size()); | |
| 116 | - // 更新运费区域列表 | |
| 117 | - List<DeliveryExpressTemplateChargeDO> updateList = new ArrayList<>(newChargeList.size()); | |
| 117 | + List<DeliveryExpressTemplateChargeDO> addList = new ArrayList<>(newChargeList.size()); // 新增运费区域列表 | |
| 118 | + List<DeliveryExpressTemplateChargeDO> updateList = new ArrayList<>(newChargeList.size()); // 更新运费区域列表 | |
| 118 | 119 | for (ExpressTemplateChargeUpdateVO item : newChargeList) { |
| 119 | 120 | if (item.getId() != null) { |
| 120 | 121 | // 计费模式以主表为准 |
| ... | ... | @@ -126,18 +127,18 @@ public class DeliveryExpressTemplateServiceImpl implements DeliveryExpressTempla |
| 126 | 127 | addList.add(INSTANCE.convertTemplateCharge(item)); |
| 127 | 128 | } |
| 128 | 129 | } |
| 129 | - // 新增 | |
| 130 | + // 1.2 新增 | |
| 130 | 131 | if (CollUtil.isNotEmpty(addList)) { |
| 131 | 132 | expressTemplateChargeMapper.insertBatch(addList); |
| 132 | 133 | } |
| 133 | - // 修改 | |
| 134 | + // 1.3 修改 | |
| 134 | 135 | if (CollUtil.isNotEmpty(updateList)) { |
| 135 | 136 | expressTemplateChargeMapper.updateBatch(updateList); |
| 136 | 137 | } |
| 137 | - // 得到删除的ids | |
| 138 | - Set<Long> deleteChargeIds = CollectionUtils.convertSet(oldChargeList, DeliveryExpressTemplateChargeDO::getId); | |
| 139 | - deleteChargeIds.removeAll(CollectionUtils.convertSet(updateList, DeliveryExpressTemplateChargeDO::getId)); | |
| 140 | - // 删除 | |
| 138 | + | |
| 139 | + // 2. 删除 | |
| 140 | + Set<Long> deleteChargeIds = convertSet(oldChargeList, DeliveryExpressTemplateChargeDO::getId); | |
| 141 | + deleteChargeIds.removeAll(convertSet(updateList, DeliveryExpressTemplateChargeDO::getId)); | |
| 141 | 142 | if (CollUtil.isNotEmpty(deleteChargeIds)) { |
| 142 | 143 | expressTemplateChargeMapper.deleteBatchIds(deleteChargeIds); |
| 143 | 144 | } |
| ... | ... | @@ -148,6 +149,7 @@ public class DeliveryExpressTemplateServiceImpl implements DeliveryExpressTempla |
| 148 | 149 | public void deleteDeliveryExpressTemplate(Long id) { |
| 149 | 150 | // 校验存在 |
| 150 | 151 | validateDeliveryExpressTemplateExists(id); |
| 152 | + | |
| 151 | 153 | // 删除主表 |
| 152 | 154 | expressTemplateMapper.deleteById(id); |
| 153 | 155 | // 删除运费从表 |
| ... | ... | @@ -199,4 +201,5 @@ public class DeliveryExpressTemplateServiceImpl implements DeliveryExpressTempla |
| 199 | 201 | public PageResult<DeliveryExpressTemplateDO> getDeliveryExpressTemplatePage(DeliveryExpressTemplatePageReqVO pageReqVO) { |
| 200 | 202 | return expressTemplateMapper.selectPage(pageReqVO); |
| 201 | 203 | } |
| 204 | + | |
| 202 | 205 | } | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/TradePriceService.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.service.price; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; | |
| 4 | +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; | |
| 5 | + | |
| 6 | +/** | |
| 7 | + * 价格计算 Service 接口 | |
| 8 | + * | |
| 9 | + * @author 芋道源码 | |
| 10 | + */ | |
| 11 | +public interface TradePriceService { | |
| 12 | + | |
| 13 | + /** | |
| 14 | + * 价格计算 | |
| 15 | + * | |
| 16 | + * @param calculateReqDTO 计算信息 | |
| 17 | + * @return 计算结果 | |
| 18 | + */ | |
| 19 | + TradePriceCalculateRespBO calculatePrice(TradePriceCalculateReqBO calculateReqDTO); | |
| 20 | + | |
| 21 | +} | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/TradePriceServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.service.price; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; | |
| 4 | +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; | |
| 5 | +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; | |
| 6 | +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; | |
| 7 | +import cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculator; | |
| 8 | +import cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculatorHelper; | |
| 9 | +import lombok.extern.slf4j.Slf4j; | |
| 10 | +import org.springframework.stereotype.Service; | |
| 11 | + | |
| 12 | +import javax.annotation.Resource; | |
| 13 | +import java.util.List; | |
| 14 | +import java.util.Map; | |
| 15 | + | |
| 16 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | |
| 17 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; | |
| 18 | +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS; | |
| 19 | +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_STOCK_NOT_ENOUGH; | |
| 20 | +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.PRICE_CALCULATE_PAY_PRICE_ILLEGAL; | |
| 21 | + | |
| 22 | +/** | |
| 23 | + * 价格计算 Service 实现类 | |
| 24 | + * | |
| 25 | + * @author 芋道源码 | |
| 26 | + */ | |
| 27 | +@Service | |
| 28 | +@Slf4j | |
| 29 | +public class TradePriceServiceImpl implements TradePriceService { | |
| 30 | + | |
| 31 | + @Resource | |
| 32 | + private ProductSkuApi productSkuApi; | |
| 33 | + @Resource | |
| 34 | + private List<TradePriceCalculator> priceCalculators; | |
| 35 | + | |
| 36 | + @Override | |
| 37 | + public TradePriceCalculateRespBO calculatePrice(TradePriceCalculateReqBO calculateReqBO) { | |
| 38 | + // 1. 获得商品 SKU 数组 | |
| 39 | + List<ProductSkuRespDTO> skuList = checkSkus(calculateReqBO); | |
| 40 | + | |
| 41 | + // 2.1 计算价格 | |
| 42 | + TradePriceCalculateRespBO calculateRespBO = TradePriceCalculatorHelper | |
| 43 | + .buildCalculateResp(calculateReqBO, skuList); | |
| 44 | + priceCalculators.forEach(calculator -> calculator.calculate(calculateReqBO, calculateRespBO)); | |
| 45 | + // 2.2 如果最终支付金额小于等于 0,则抛出业务异常 | |
| 46 | + if (calculateRespBO.getPrice().getPayPrice() <= 0) { | |
| 47 | + log.error("[calculatePrice][价格计算不正确,请求 calculateReqDTO({}),结果 priceCalculate({})]", | |
| 48 | + calculateReqBO, calculateRespBO); | |
| 49 | + throw exception(PRICE_CALCULATE_PAY_PRICE_ILLEGAL); | |
| 50 | + } | |
| 51 | + return calculateRespBO; | |
| 52 | + } | |
| 53 | + | |
| 54 | + private List<ProductSkuRespDTO> checkSkus(TradePriceCalculateReqBO reqBO) { | |
| 55 | + // 获得商品 SKU 数组 | |
| 56 | + Map<Long, Integer> skuIdCountMap = convertMap(reqBO.getItems(), | |
| 57 | + TradePriceCalculateReqBO.Item::getSkuId, TradePriceCalculateReqBO.Item::getCount); | |
| 58 | + List<ProductSkuRespDTO> skus = productSkuApi.getSkuList(skuIdCountMap.keySet()); | |
| 59 | + | |
| 60 | + // 校验商品 SKU | |
| 61 | + skus.forEach(sku -> { | |
| 62 | + Integer count = skuIdCountMap.get(sku.getId()); | |
| 63 | + if (count == null) { | |
| 64 | + throw exception(SKU_NOT_EXISTS); | |
| 65 | + } | |
| 66 | + if (count > sku.getStock()) { | |
| 67 | + throw exception(SKU_STOCK_NOT_ENOUGH); | |
| 68 | + } | |
| 69 | + }); | |
| 70 | + return skus; | |
| 71 | + } | |
| 72 | + | |
| 73 | +} | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateReqBO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.service.price.bo; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; | |
| 4 | +import lombok.Data; | |
| 5 | + | |
| 6 | +import javax.validation.Valid; | |
| 7 | +import javax.validation.constraints.Min; | |
| 8 | +import javax.validation.constraints.NotNull; | |
| 9 | +import java.util.List; | |
| 10 | + | |
| 11 | +/** | |
| 12 | + * 价格计算 Request BO | |
| 13 | + * | |
| 14 | + * @author yudao源码 | |
| 15 | + */ | |
| 16 | +@Data | |
| 17 | +public class TradePriceCalculateReqBO { | |
| 18 | + | |
| 19 | + /** | |
| 20 | + * 订单类型 | |
| 21 | + * | |
| 22 | + * 枚举 {@link TradeOrderTypeEnum} | |
| 23 | + */ | |
| 24 | + private Integer orderType; | |
| 25 | + | |
| 26 | + /** | |
| 27 | + * 用户编号 | |
| 28 | + * | |
| 29 | + * 对应 MemberUserDO 的 id 编号 | |
| 30 | + */ | |
| 31 | + private Long userId; | |
| 32 | + | |
| 33 | + /** | |
| 34 | + * 优惠劵编号 | |
| 35 | + * | |
| 36 | + * 对应 CouponDO 的 id 编号 | |
| 37 | + */ | |
| 38 | + private Long couponId; | |
| 39 | + | |
| 40 | + /** | |
| 41 | + * 收货地址编号 | |
| 42 | + * | |
| 43 | + * 对应 MemberAddressDO 的 id 编号 | |
| 44 | + */ | |
| 45 | + private Long addressId; | |
| 46 | + | |
| 47 | + /** | |
| 48 | + * 商品 SKU 数组 | |
| 49 | + */ | |
| 50 | + @NotNull(message = "商品数组不能为空") | |
| 51 | + private List<Item> items; | |
| 52 | + | |
| 53 | + /** | |
| 54 | + * 商品 SKU | |
| 55 | + */ | |
| 56 | + @Data | |
| 57 | + @Valid | |
| 58 | + public static class Item { | |
| 59 | + | |
| 60 | + /** | |
| 61 | + * SKU 编号 | |
| 62 | + */ | |
| 63 | + @NotNull(message = "商品 SKU 编号不能为空") | |
| 64 | + private Long skuId; | |
| 65 | + | |
| 66 | + /** | |
| 67 | + * SKU 数量 | |
| 68 | + */ | |
| 69 | + @NotNull(message = "商品 SKU 数量不能为空") | |
| 70 | + @Min(value = 0L, message = "商品 SKU 数量必须大于等于 0") | |
| 71 | + private Integer count; | |
| 72 | + | |
| 73 | + /** | |
| 74 | + * 购物车项的编号 | |
| 75 | + */ | |
| 76 | + private Long cartId; | |
| 77 | + | |
| 78 | + /** | |
| 79 | + * 是否选中 | |
| 80 | + */ | |
| 81 | + @NotNull(message = "是否选中不能为空") | |
| 82 | + private Boolean selected; | |
| 83 | + | |
| 84 | + } | |
| 85 | + | |
| 86 | +} | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateRespBO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.service.price.bo; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.promotion.enums.common.PromotionLevelEnum; | |
| 4 | +import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; | |
| 5 | +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; | |
| 6 | +import lombok.Data; | |
| 7 | + | |
| 8 | +import java.util.List; | |
| 9 | + | |
| 10 | +/** | |
| 11 | + * 价格计算 Response BO | |
| 12 | + * | |
| 13 | + * 整体设计,参考 taobao 的技术文档: | |
| 14 | + * 1. <a href="https://developer.alibaba.com/docs/doc.htm?treeId=1&articleId=1029&docType=1">订单管理</a> | |
| 15 | + * 2. <a href="https://open.taobao.com/docV3.htm?docId=108471&docType=1">常用订单金额说明</a> | |
| 16 | + * | |
| 17 | + * @author 芋道源码 | |
| 18 | + */ | |
| 19 | +@Data | |
| 20 | +public class TradePriceCalculateRespBO { | |
| 21 | + | |
| 22 | + /** | |
| 23 | + * 订单类型 | |
| 24 | + * | |
| 25 | + * 枚举 {@link TradeOrderTypeEnum} | |
| 26 | + */ | |
| 27 | + private Integer orderType; | |
| 28 | + | |
| 29 | + /** | |
| 30 | + * 订单价格 | |
| 31 | + */ | |
| 32 | + private Price price; | |
| 33 | + | |
| 34 | + /** | |
| 35 | + * 订单项数组 | |
| 36 | + */ | |
| 37 | + private List<OrderItem> items; | |
| 38 | + | |
| 39 | + /** | |
| 40 | + * 营销活动数组 | |
| 41 | + * | |
| 42 | + * 只对应 {@link Price#items} 商品匹配的活动 | |
| 43 | + */ | |
| 44 | + private List<Promotion> promotions; | |
| 45 | + | |
| 46 | + /** | |
| 47 | + * 优惠劵编号 | |
| 48 | + */ | |
| 49 | + private Long couponId; | |
| 50 | + | |
| 51 | + /** | |
| 52 | + * 订单价格 | |
| 53 | + */ | |
| 54 | + @Data | |
| 55 | + public static class Price { | |
| 56 | + | |
| 57 | + /** | |
| 58 | + * 商品原价(总),单位:分 | |
| 59 | + * | |
| 60 | + * 基于 {@link OrderItem#getPrice()} * {@link OrderItem#getCount()} 求和 | |
| 61 | + * | |
| 62 | + * 对应 taobao 的 trade.total_fee 字段 | |
| 63 | + */ | |
| 64 | + private Integer totalPrice; | |
| 65 | + /** | |
| 66 | + * 订单优惠(总),单位:分 | |
| 67 | + * | |
| 68 | + * 对应 taobao 的 order.discount_fee 字段 | |
| 69 | + */ | |
| 70 | + private Integer discountPrice; | |
| 71 | + /** | |
| 72 | + * 运费金额,单位:分 | |
| 73 | + */ | |
| 74 | + private Integer deliveryPrice; | |
| 75 | + /** | |
| 76 | + * 优惠劵减免金额(总),单位:分 | |
| 77 | + * | |
| 78 | + * 对应 taobao 的 trade.coupon_fee 字段 | |
| 79 | + */ | |
| 80 | + private Integer couponPrice; | |
| 81 | + /** | |
| 82 | + * 积分抵扣的金额,单位:分 | |
| 83 | + * | |
| 84 | + * 对应 taobao 的 trade.point_fee 字段 | |
| 85 | + */ | |
| 86 | + private Integer pointPrice; | |
| 87 | + /** | |
| 88 | + * 最终购买金额(总),单位:分 | |
| 89 | + * | |
| 90 | + * = {@link #totalPrice} | |
| 91 | + * - {@link #couponPrice} | |
| 92 | + * - {@link #pointPrice} | |
| 93 | + * - {@link #discountPrice} | |
| 94 | + * + {@link #deliveryPrice} | |
| 95 | + */ | |
| 96 | + private Integer payPrice; | |
| 97 | + | |
| 98 | + } | |
| 99 | + | |
| 100 | + /** | |
| 101 | + * 订单商品 SKU | |
| 102 | + */ | |
| 103 | + @Data | |
| 104 | + public static class OrderItem { | |
| 105 | + | |
| 106 | + /** | |
| 107 | + * SPU 编号 | |
| 108 | + */ | |
| 109 | + private Long spuId; | |
| 110 | + /** | |
| 111 | + * SKU 编号 | |
| 112 | + */ | |
| 113 | + private Long skuId; | |
| 114 | + /** | |
| 115 | + * 购买数量 | |
| 116 | + */ | |
| 117 | + private Integer count; | |
| 118 | + /** | |
| 119 | + * 购物车项的编号 | |
| 120 | + */ | |
| 121 | + private Long cartId; | |
| 122 | + /** | |
| 123 | + * 是否选中 | |
| 124 | + */ | |
| 125 | + private Boolean selected; | |
| 126 | + | |
| 127 | + /** | |
| 128 | + * 商品原价(单),单位:分 | |
| 129 | + * | |
| 130 | + * 对应 ProductSkuDO 的 price 字段 | |
| 131 | + * 对应 taobao 的 order.price 字段 | |
| 132 | + */ | |
| 133 | + private Integer price; | |
| 134 | + /** | |
| 135 | + * 优惠金额(总),单位:分 | |
| 136 | + * | |
| 137 | + * 对应 taobao 的 order.discount_fee 字段 | |
| 138 | + */ | |
| 139 | + private Integer discountPrice; | |
| 140 | + /** | |
| 141 | + * 运费金额(总),单位:分 | |
| 142 | + */ | |
| 143 | + private Integer deliveryPrice; | |
| 144 | + /** | |
| 145 | + * 优惠劵减免金额,单位:分 | |
| 146 | + * | |
| 147 | + * 对应 taobao 的 trade.coupon_fee 字段 | |
| 148 | + */ | |
| 149 | + private Integer couponPrice; | |
| 150 | + /** | |
| 151 | + * 积分抵扣的金额,单位:分 | |
| 152 | + * | |
| 153 | + * 对应 taobao 的 trade.point_fee 字段 | |
| 154 | + */ | |
| 155 | + private Integer pointPrice; | |
| 156 | + /** | |
| 157 | + * 应付金额(总),单位:分 | |
| 158 | + * | |
| 159 | + * = {@link #price} * {@link #count} | |
| 160 | + * - {@link #couponPrice} | |
| 161 | + * - {@link #pointPrice} | |
| 162 | + * - {@link #discountPrice} | |
| 163 | + * + {@link #deliveryPrice} | |
| 164 | + */ | |
| 165 | + private Integer payPrice; | |
| 166 | + | |
| 167 | + // TODO 芋艿:这里补充下基本信息,简单一点。 | |
| 168 | + | |
| 169 | + } | |
| 170 | + | |
| 171 | + /** | |
| 172 | + * 营销明细 | |
| 173 | + */ | |
| 174 | + @Data | |
| 175 | + public static class Promotion { | |
| 176 | + | |
| 177 | + /** | |
| 178 | + * 营销编号 | |
| 179 | + * | |
| 180 | + * 例如说:营销活动的编号、优惠劵的编号 | |
| 181 | + */ | |
| 182 | + private Long id; | |
| 183 | + /** | |
| 184 | + * 营销名字 | |
| 185 | + */ | |
| 186 | + private String name; | |
| 187 | + /** | |
| 188 | + * 营销类型 | |
| 189 | + * | |
| 190 | + * 枚举 {@link PromotionTypeEnum} | |
| 191 | + */ | |
| 192 | + private Integer type; | |
| 193 | + /** | |
| 194 | + * 营销级别 | |
| 195 | + * | |
| 196 | + * 枚举 {@link PromotionLevelEnum} | |
| 197 | + */ | |
| 198 | + private Integer level; | |
| 199 | + /** | |
| 200 | + * 计算时的原价(总),单位:分 | |
| 201 | + */ | |
| 202 | + private Integer totalPrice; | |
| 203 | + /** | |
| 204 | + * 计算时的优惠(总),单位:分 | |
| 205 | + */ | |
| 206 | + private Integer discountPrice; | |
| 207 | + /** | |
| 208 | + * 匹配的商品 SKU 数组 | |
| 209 | + */ | |
| 210 | + private List<PromotionItem> items; | |
| 211 | + | |
| 212 | + // ========== 匹配情况 ========== | |
| 213 | + | |
| 214 | + /** | |
| 215 | + * 是否满足优惠条件 | |
| 216 | + */ | |
| 217 | + private Boolean match; | |
| 218 | + /** | |
| 219 | + * 满足条件的提示 | |
| 220 | + * | |
| 221 | + * 如果 {@link #match} = true 满足,则提示“圣诞价:省 150.00 元” | |
| 222 | + * 如果 {@link #match} = false 不满足,则提示“购满 85 元,可减 40 元” | |
| 223 | + */ | |
| 224 | + private String description; | |
| 225 | + | |
| 226 | + } | |
| 227 | + | |
| 228 | + /** | |
| 229 | + * 营销匹配的商品 SKU | |
| 230 | + */ | |
| 231 | + @Data | |
| 232 | + public static class PromotionItem { | |
| 233 | + | |
| 234 | + /** | |
| 235 | + * 商品 SKU 编号 | |
| 236 | + */ | |
| 237 | + private Long skuId; | |
| 238 | + /** | |
| 239 | + * 计算时的原价(总),单位:分 | |
| 240 | + */ | |
| 241 | + private Integer totalPrice; | |
| 242 | + /** | |
| 243 | + * 计算时的优惠(总),单位:分 | |
| 244 | + */ | |
| 245 | + private Integer discountPrice; | |
| 246 | + | |
| 247 | + } | |
| 248 | + | |
| 249 | +} | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeCouponPriceCalculator.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.service.price.calculator; | |
| 2 | + | |
| 3 | +import cn.hutool.core.collection.CollUtil; | |
| 4 | +import cn.hutool.core.lang.Assert; | |
| 5 | +import cn.hutool.core.util.StrUtil; | |
| 6 | +import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi; | |
| 7 | +import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponRespDTO; | |
| 8 | +import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponValidReqDTO; | |
| 9 | +import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; | |
| 10 | +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; | |
| 11 | +import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; | |
| 12 | +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; | |
| 13 | +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; | |
| 14 | +import org.springframework.core.annotation.Order; | |
| 15 | +import org.springframework.stereotype.Component; | |
| 16 | + | |
| 17 | +import javax.annotation.Resource; | |
| 18 | +import java.util.List; | |
| 19 | +import java.util.function.Predicate; | |
| 20 | + | |
| 21 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | |
| 22 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; | |
| 23 | +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COUPON_NO_MATCH_MIN_PRICE; | |
| 24 | +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COUPON_NO_MATCH_SPU; | |
| 25 | + | |
| 26 | +/** | |
| 27 | + * 优惠劵的 {@link TradePriceCalculator} 实现类 | |
| 28 | + * | |
| 29 | + * @author 芋道源码 | |
| 30 | + */ | |
| 31 | +@Component | |
| 32 | +@Order(TradePriceCalculator.ORDER_COUPON) | |
| 33 | +public class TradeCouponPriceCalculator implements TradePriceCalculator { | |
| 34 | + | |
| 35 | + @Resource | |
| 36 | + private CouponApi couponApi; | |
| 37 | + | |
| 38 | + @Override | |
| 39 | + public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { | |
| 40 | + // 1.1 校验优惠劵 | |
| 41 | + if (param.getCouponId() == null) { | |
| 42 | + return; | |
| 43 | + } | |
| 44 | + CouponRespDTO coupon = couponApi.validateCoupon(new CouponValidReqDTO() | |
| 45 | + .setId(param.getCouponId()).setUserId(param.getUserId())); | |
| 46 | + Assert.notNull(coupon, "校验通过的优惠劵({}),不能为空", param.getCouponId()); | |
| 47 | + | |
| 48 | + // 2.1 获得匹配的商品 SKU 数组 | |
| 49 | + List<TradePriceCalculateRespBO.OrderItem> orderItems = filterMatchCouponOrderItems(result, coupon); | |
| 50 | + if (CollUtil.isEmpty(orderItems)) { | |
| 51 | + throw exception(COUPON_NO_MATCH_SPU); | |
| 52 | + } | |
| 53 | + // 2.2 计算是否满足优惠劵的使用金额 | |
| 54 | + Integer totalPayPrice = TradePriceCalculatorHelper.calculateTotalPayPrice(orderItems); | |
| 55 | + if (totalPayPrice < coupon.getUsePrice()) { | |
| 56 | + throw exception(COUPON_NO_MATCH_MIN_PRICE); | |
| 57 | + } | |
| 58 | + | |
| 59 | + // 3.1 计算可以优惠的金额 | |
| 60 | + Integer couponPrice = getCouponPrice(coupon, totalPayPrice); | |
| 61 | + Assert.isTrue(couponPrice < totalPayPrice, | |
| 62 | + "优惠劵({}) 的优惠金额({}),不能大于订单总金额({})", coupon.getId(), couponPrice, totalPayPrice); | |
| 63 | + // 3.2 计算分摊的优惠金额 | |
| 64 | + List<Integer> divideCouponPrices = TradePriceCalculatorHelper.dividePrice(orderItems, couponPrice); | |
| 65 | + | |
| 66 | + // 4.1 记录使用的优惠劵 | |
| 67 | + result.setCouponId(param.getCouponId()); | |
| 68 | + // 4.2 记录优惠明细 | |
| 69 | + TradePriceCalculatorHelper.addPromotion(result, orderItems, | |
| 70 | + param.getCouponId(), coupon.getName(), PromotionTypeEnum.COUPON.getType(), | |
| 71 | + StrUtil.format("优惠劵:省 {} 元", TradePriceCalculatorHelper.formatPrice(couponPrice)), | |
| 72 | + divideCouponPrices); | |
| 73 | + // 4.3 更新 SKU 优惠金额 | |
| 74 | + for (int i = 0; i < orderItems.size(); i++) { | |
| 75 | + TradePriceCalculateRespBO.OrderItem orderItem = orderItems.get(i); | |
| 76 | + orderItem.setCouponPrice(divideCouponPrices.get(i)); | |
| 77 | + TradePriceCalculatorHelper.recountPayPrice(orderItem); | |
| 78 | + } | |
| 79 | + TradePriceCalculatorHelper.recountAllPrice(result); | |
| 80 | + } | |
| 81 | + | |
| 82 | + private Integer getCouponPrice(CouponRespDTO coupon, Integer totalPayPrice) { | |
| 83 | + if (PromotionDiscountTypeEnum.PRICE.getType().equals(coupon.getDiscountType())) { // 减价 | |
| 84 | + return coupon.getDiscountPrice(); | |
| 85 | + } else if (PromotionDiscountTypeEnum.PERCENT.getType().equals(coupon.getDiscountType())) { // 打折 | |
| 86 | + int couponPrice = totalPayPrice * coupon.getDiscountPercent() / 100; | |
| 87 | + return coupon.getDiscountLimitPrice() == null ? couponPrice | |
| 88 | + : Math.min(couponPrice, coupon.getDiscountLimitPrice()); // 优惠上限 | |
| 89 | + } | |
| 90 | + throw new IllegalArgumentException(String.format("优惠劵(%s) 的优惠类型不正确", coupon)); | |
| 91 | + } | |
| 92 | + | |
| 93 | + /** | |
| 94 | + * 获得优惠劵可使用的订单项(商品)列表 | |
| 95 | + * | |
| 96 | + * @param result 计算结果 | |
| 97 | + * @param coupon 优惠劵 | |
| 98 | + * @return 订单项(商品)列表 | |
| 99 | + */ | |
| 100 | + private List<TradePriceCalculateRespBO.OrderItem> filterMatchCouponOrderItems(TradePriceCalculateRespBO result, | |
| 101 | + CouponRespDTO coupon) { | |
| 102 | + Predicate<TradePriceCalculateRespBO.OrderItem> matchPredicate = TradePriceCalculateRespBO.OrderItem::getSelected; | |
| 103 | + if (PromotionProductScopeEnum.SPU.getScope().equals(coupon.getProductScope())) { | |
| 104 | + matchPredicate = orderItem -> coupon.getProductSpuIds().contains(orderItem.getSpuId()); | |
| 105 | + } | |
| 106 | + return filterList(result.getItems(), matchPredicate); | |
| 107 | + } | |
| 108 | + | |
| 109 | +} | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDiscountActivityPriceCalculator.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.service.price.calculator; | |
| 2 | + | |
| 3 | +import cn.hutool.core.collection.CollUtil; | |
| 4 | +import cn.hutool.core.util.StrUtil; | |
| 5 | +import cn.iocoder.yudao.module.promotion.api.discount.DiscountActivityApi; | |
| 6 | +import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO; | |
| 7 | +import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; | |
| 8 | +import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; | |
| 9 | +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; | |
| 10 | +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; | |
| 11 | +import org.springframework.core.annotation.Order; | |
| 12 | +import org.springframework.stereotype.Component; | |
| 13 | + | |
| 14 | +import javax.annotation.Resource; | |
| 15 | +import java.util.List; | |
| 16 | +import java.util.Map; | |
| 17 | + | |
| 18 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; | |
| 19 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | |
| 20 | +import static cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculatorHelper.formatPrice; | |
| 21 | + | |
| 22 | +/** | |
| 23 | + * 限时折扣的 {@link TradePriceCalculator} 实现类 | |
| 24 | + * | |
| 25 | + * @author 芋道源码 | |
| 26 | + */ | |
| 27 | +@Component | |
| 28 | +@Order(TradePriceCalculator.ORDER_DISCOUNT_ACTIVITY) | |
| 29 | +public class TradeDiscountActivityPriceCalculator implements TradePriceCalculator { | |
| 30 | + | |
| 31 | + @Resource | |
| 32 | + private DiscountActivityApi discountActivityApi; | |
| 33 | + | |
| 34 | + @Override | |
| 35 | + public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { | |
| 36 | + // 获得 SKU 对应的限时折扣活动 | |
| 37 | + List<DiscountProductRespDTO> discountProducts = discountActivityApi.getMatchDiscountProductList( | |
| 38 | + convertSet(result.getItems(), TradePriceCalculateRespBO.OrderItem::getSkuId)); | |
| 39 | + if (CollUtil.isEmpty(discountProducts)) { | |
| 40 | + return; | |
| 41 | + } | |
| 42 | + Map<Long, DiscountProductRespDTO> discountProductMap = convertMap(discountProducts, DiscountProductRespDTO::getSkuId); | |
| 43 | + | |
| 44 | + // 处理每个 SKU 的限时折扣 | |
| 45 | + result.getItems().forEach(orderItem -> { | |
| 46 | + // 1. 获取该 SKU 的优惠信息 | |
| 47 | + DiscountProductRespDTO discountProduct = discountProductMap.get(orderItem.getSkuId()); | |
| 48 | + if (discountProduct == null) { | |
| 49 | + return; | |
| 50 | + } | |
| 51 | + // 2. 计算优惠金额 | |
| 52 | + Integer newPayPrice = calculatePayPrice(discountProduct, orderItem); | |
| 53 | + Integer newDiscountPrice = orderItem.getPayPrice() - newPayPrice; | |
| 54 | + | |
| 55 | + // 3.1 记录优惠明细 | |
| 56 | + TradePriceCalculatorHelper.addPromotion(result, orderItem, | |
| 57 | + discountProduct.getActivityId(), discountProduct.getActivityName(), PromotionTypeEnum.DISCOUNT_ACTIVITY.getType(), | |
| 58 | + StrUtil.format("限时折扣:省 {} 元", formatPrice(newDiscountPrice)), | |
| 59 | + newDiscountPrice); | |
| 60 | + // 3.2 更新 SKU 优惠金额 | |
| 61 | + orderItem.setDiscountPrice(orderItem.getDiscountPrice() + newDiscountPrice); | |
| 62 | + TradePriceCalculatorHelper.recountPayPrice(orderItem); | |
| 63 | + }); | |
| 64 | + TradePriceCalculatorHelper.recountAllPrice(result); | |
| 65 | + } | |
| 66 | + | |
| 67 | + private Integer calculatePayPrice(DiscountProductRespDTO discountProduct, | |
| 68 | + TradePriceCalculateRespBO.OrderItem orderItem) { | |
| 69 | + Integer price = orderItem.getPayPrice(); | |
| 70 | + if (PromotionDiscountTypeEnum.PRICE.getType().equals(discountProduct.getDiscountType())) { // 减价 | |
| 71 | + price -= discountProduct.getDiscountPrice() * orderItem.getCount(); | |
| 72 | + } else if (PromotionDiscountTypeEnum.PERCENT.getType().equals(discountProduct.getDiscountType())) { // 打折 | |
| 73 | + price = price * discountProduct.getDiscountPercent() / 100; | |
| 74 | + } else { | |
| 75 | + throw new IllegalArgumentException(String.format("优惠活动的商品(%s) 的优惠类型不正确", discountProduct)); | |
| 76 | + } | |
| 77 | + return price; | |
| 78 | + } | |
| 79 | + | |
| 80 | +} | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculator.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.service.price.calculator; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; | |
| 4 | +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; | |
| 5 | + | |
| 6 | +/** | |
| 7 | + * 价格计算的计算器接口 | |
| 8 | + * | |
| 9 | + * @author 芋道源码 | |
| 10 | + */ | |
| 11 | +public interface TradePriceCalculator { | |
| 12 | + | |
| 13 | + int ORDER_DISCOUNT_ACTIVITY = 10; | |
| 14 | + int ORDER_REWARD_ACTIVITY = 20; | |
| 15 | + int ORDER_COUPON = 30; | |
| 16 | + | |
| 17 | + void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result); | |
| 18 | + | |
| 19 | +} | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.service.price.calculator; | |
| 2 | + | |
| 3 | +import cn.hutool.core.lang.Assert; | |
| 4 | +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | |
| 5 | +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; | |
| 6 | +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; | |
| 7 | +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; | |
| 8 | + | |
| 9 | +import java.util.ArrayList; | |
| 10 | +import java.util.List; | |
| 11 | +import java.util.Map; | |
| 12 | + | |
| 13 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; | |
| 14 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue; | |
| 15 | +import static java.util.Collections.singletonList; | |
| 16 | + | |
| 17 | +/** | |
| 18 | + * {@link TradePriceCalculator} 的工具类 | |
| 19 | + * | |
| 20 | + * 主要实现对 {@link TradePriceCalculateRespBO} 计算结果的操作 | |
| 21 | + * | |
| 22 | + * @author 芋道源码 | |
| 23 | + */ | |
| 24 | +public class TradePriceCalculatorHelper { | |
| 25 | + | |
| 26 | + public static TradePriceCalculateRespBO buildCalculateResp(TradePriceCalculateReqBO param, | |
| 27 | + List<ProductSkuRespDTO> skuList) { | |
| 28 | + // 创建 PriceCalculateRespDTO 对象 | |
| 29 | + TradePriceCalculateRespBO result = new TradePriceCalculateRespBO(); | |
| 30 | + result.setOrderType(param.getOrderType()); | |
| 31 | + // 创建它的 OrderItem 属性 | |
| 32 | + Map<Long, TradePriceCalculateReqBO.Item> skuItemMap = convertMap(param.getItems(), | |
| 33 | + TradePriceCalculateReqBO.Item::getSkuId); | |
| 34 | + result.setItems(new ArrayList<>(skuItemMap.size())); | |
| 35 | + skuList.forEach(sku -> { | |
| 36 | + TradePriceCalculateReqBO.Item skuItem = skuItemMap.get(sku.getId()); | |
| 37 | + TradePriceCalculateRespBO.OrderItem orderItem = new TradePriceCalculateRespBO.OrderItem() | |
| 38 | + // SKU 字段 | |
| 39 | + .setSpuId(sku.getSpuId()).setSkuId(sku.getId()) | |
| 40 | + .setCount(skuItem.getCount()).setCartId(skuItem.getCartId()).setSelected(skuItem.getSelected()) | |
| 41 | + // 价格字段 | |
| 42 | + .setPrice(sku.getPrice()).setPayPrice(sku.getPrice() * skuItem.getCount()) | |
| 43 | + .setDiscountPrice(0).setDeliveryPrice(0).setCouponPrice(0).setPointPrice(0); | |
| 44 | + result.getItems().add(orderItem); | |
| 45 | + }); | |
| 46 | + // 创建它的 Price 属性 | |
| 47 | + result.setPrice(new TradePriceCalculateRespBO.Price()); | |
| 48 | + recountAllPrice(result); | |
| 49 | + return result; | |
| 50 | + } | |
| 51 | + | |
| 52 | + /** | |
| 53 | + * 基于订单项,重新计算 price 总价 | |
| 54 | + * | |
| 55 | + * @param result 计算结果 | |
| 56 | + */ | |
| 57 | + public static void recountAllPrice(TradePriceCalculateRespBO result) { | |
| 58 | + // 先重置 | |
| 59 | + TradePriceCalculateRespBO.Price price = result.getPrice(); | |
| 60 | + price.setTotalPrice(0).setDiscountPrice(0).setDeliveryPrice(0) | |
| 61 | + .setCouponPrice(0).setPointPrice(0).setPayPrice(0); | |
| 62 | + // 再合计 item | |
| 63 | + result.getItems().forEach(item -> { | |
| 64 | + if (!item.getSelected()) { | |
| 65 | + return; | |
| 66 | + } | |
| 67 | + price.setTotalPrice(price.getTotalPrice() + item.getPrice() * item.getCount()); | |
| 68 | + price.setDiscountPrice(price.getDiscountPrice() + item.getDiscountPrice()); | |
| 69 | + price.setDeliveryPrice(price.getDeliveryPrice() + item.getDeliveryPrice()); | |
| 70 | + price.setCouponPrice(price.getCouponPrice() + item.getCouponPrice()); | |
| 71 | + price.setPointPrice(price.getPointPrice() + item.getPointPrice()); | |
| 72 | + price.setPayPrice(price.getPayPrice() + item.getPayPrice()); | |
| 73 | + }); | |
| 74 | + } | |
| 75 | + | |
| 76 | + /** | |
| 77 | + * 重新计算单个订单项的支付金额 | |
| 78 | + * | |
| 79 | + * @param orderItem 订单项 | |
| 80 | + */ | |
| 81 | + public static void recountPayPrice(TradePriceCalculateRespBO.OrderItem orderItem) { | |
| 82 | + orderItem.setPayPrice(orderItem.getPrice()* orderItem.getCount() | |
| 83 | + - orderItem.getDiscountPrice() | |
| 84 | + + orderItem.getDeliveryPrice() | |
| 85 | + - orderItem.getCouponPrice() | |
| 86 | + - orderItem.getPointPrice()); | |
| 87 | + } | |
| 88 | + | |
| 89 | + /** | |
| 90 | + * 计算已选中的订单项,总支付金额 | |
| 91 | + * | |
| 92 | + * @param orderItems 订单项数组 | |
| 93 | + * @return 总支付金额 | |
| 94 | + */ | |
| 95 | + public static Integer calculateTotalPayPrice(List<TradePriceCalculateRespBO.OrderItem> orderItems) { | |
| 96 | + return getSumValue(orderItems, | |
| 97 | + orderItem -> orderItem.getSelected() ? orderItem.getPayPrice() : 0, // 未选中的情况下,不计算支付金额 | |
| 98 | + Integer::sum); | |
| 99 | + } | |
| 100 | + | |
| 101 | + /** | |
| 102 | + * 计算已选中的订单项,总商品数 | |
| 103 | + * | |
| 104 | + * @param orderItems 订单项数组 | |
| 105 | + * @return 总商品数 | |
| 106 | + */ | |
| 107 | + public static Integer calculateTotalCount(List<TradePriceCalculateRespBO.OrderItem> orderItems) { | |
| 108 | + return getSumValue(orderItems, | |
| 109 | + orderItem -> orderItem.getSelected() ? orderItem.getCount() : 0, // 未选中的情况下,不计算数量 | |
| 110 | + Integer::sum); | |
| 111 | + } | |
| 112 | + | |
| 113 | + /** | |
| 114 | + * 按照支付金额,返回每个订单项的分摊金额数组 | |
| 115 | + * | |
| 116 | + * @param orderItems 订单项数组 | |
| 117 | + * @param price 金额 | |
| 118 | + * @return 分摊金额数组,和传入的 orderItems 一一对应 | |
| 119 | + */ | |
| 120 | + public static List<Integer> dividePrice(List<TradePriceCalculateRespBO.OrderItem> orderItems, Integer price) { | |
| 121 | + Integer total = calculateTotalPayPrice(orderItems); | |
| 122 | + assert total != null; | |
| 123 | + // 遍历每一个,进行分摊 | |
| 124 | + List<Integer> prices = new ArrayList<>(orderItems.size()); | |
| 125 | + int remainPrice = price; | |
| 126 | + for (int i = 0; i < orderItems.size(); i++) { | |
| 127 | + TradePriceCalculateRespBO.OrderItem orderItem = orderItems.get(i); | |
| 128 | + // 1. 如果是未选中,则分摊为 0 | |
| 129 | + if (!orderItem.getSelected()) { | |
| 130 | + prices.add(0); | |
| 131 | + continue; | |
| 132 | + } | |
| 133 | + // 2. 如果选中,则按照百分比,进行分摊 | |
| 134 | + int partPrice; | |
| 135 | + if (i < orderItems.size() - 1) { // 减一的原因,是因为拆分时,如果按照比例,可能会出现.所以最后一个,使用反减 | |
| 136 | + partPrice = (int) (price * (1.0D * orderItem.getPayPrice() / total)); | |
| 137 | + remainPrice -= partPrice; | |
| 138 | + } else { | |
| 139 | + partPrice = remainPrice; | |
| 140 | + } | |
| 141 | + Assert.isTrue(partPrice >= 0, "分摊金额必须大于等于 0"); | |
| 142 | + prices.add(partPrice); | |
| 143 | + } | |
| 144 | + return prices; | |
| 145 | + } | |
| 146 | + | |
| 147 | + /** | |
| 148 | + * 添加【匹配】单个 OrderItem 的营销明细 | |
| 149 | + * | |
| 150 | + * @param result 价格计算结果 | |
| 151 | + * @param orderItem 单个订单商品 SKU | |
| 152 | + * @param id 营销编号 | |
| 153 | + * @param name 营销名字 | |
| 154 | + * @param description 满足条件的提示 | |
| 155 | + * @param type 营销类型 | |
| 156 | + * @param discountPrice 单个订单商品 SKU 的优惠价格(总) | |
| 157 | + */ | |
| 158 | + public static void addPromotion(TradePriceCalculateRespBO result, TradePriceCalculateRespBO.OrderItem orderItem, | |
| 159 | + Long id, String name, Integer type, String description, Integer discountPrice) { | |
| 160 | + addPromotion(result, singletonList(orderItem), id, name, type, description, singletonList(discountPrice)); | |
| 161 | + } | |
| 162 | + | |
| 163 | + /** | |
| 164 | + * 添加【匹配】多个 OrderItem 的营销明细 | |
| 165 | + * | |
| 166 | + * @param result 价格计算结果 | |
| 167 | + * @param orderItems 多个订单商品 SKU | |
| 168 | + * @param id 营销编号 | |
| 169 | + * @param name 营销名字 | |
| 170 | + * @param description 满足条件的提示 | |
| 171 | + * @param type 营销类型 | |
| 172 | + * @param discountPrices 多个订单商品 SKU 的优惠价格(总),和 orderItems 一一对应 | |
| 173 | + */ | |
| 174 | + public static void addPromotion(TradePriceCalculateRespBO result, List<TradePriceCalculateRespBO.OrderItem> orderItems, | |
| 175 | + Long id, String name, Integer type, String description, List<Integer> discountPrices) { | |
| 176 | + // 创建营销明细 Item | |
| 177 | + List<TradePriceCalculateRespBO.PromotionItem> promotionItems = new ArrayList<>(discountPrices.size()); | |
| 178 | + for (int i = 0; i < orderItems.size(); i++) { | |
| 179 | + TradePriceCalculateRespBO.OrderItem orderItem = orderItems.get(i); | |
| 180 | + promotionItems.add(new TradePriceCalculateRespBO.PromotionItem().setSkuId(orderItem.getSkuId()) | |
| 181 | + .setTotalPrice(orderItem.getPayPrice()).setDiscountPrice(discountPrices.get(i))); | |
| 182 | + } | |
| 183 | + // 创建营销明细 | |
| 184 | + TradePriceCalculateRespBO.Promotion promotion = new TradePriceCalculateRespBO.Promotion() | |
| 185 | + .setId(id).setName(name).setType(type) | |
| 186 | + .setTotalPrice(calculateTotalPayPrice(orderItems)) | |
| 187 | + .setDiscountPrice(getSumValue(discountPrices, value -> value, Integer::sum)) | |
| 188 | + .setItems(promotionItems).setMatch(true).setDescription(description); | |
| 189 | + result.getPromotions().add(promotion); | |
| 190 | + } | |
| 191 | + | |
| 192 | + /** | |
| 193 | + * 添加【不匹配】多个 OrderItem 的营销明细 | |
| 194 | + * | |
| 195 | + * @param result 价格计算结果 | |
| 196 | + * @param orderItems 多个订单商品 SKU | |
| 197 | + * @param id 营销编号 | |
| 198 | + * @param name 营销名字 | |
| 199 | + * @param description 满足条件的提示 | |
| 200 | + * @param type 营销类型 | |
| 201 | + */ | |
| 202 | + public static void addNotMatchPromotion(TradePriceCalculateRespBO result, List<TradePriceCalculateRespBO.OrderItem> orderItems, | |
| 203 | + Long id, String name, Integer type, String description) { | |
| 204 | + // 创建营销明细 Item | |
| 205 | + List<TradePriceCalculateRespBO.PromotionItem> promotionItems = CollectionUtils.convertList(orderItems, | |
| 206 | + orderItem -> new TradePriceCalculateRespBO.PromotionItem().setSkuId(orderItem.getSkuId()) | |
| 207 | + .setTotalPrice(orderItem.getPayPrice()).setDiscountPrice(0)); | |
| 208 | + // 创建营销明细 | |
| 209 | + TradePriceCalculateRespBO.Promotion promotion = new TradePriceCalculateRespBO.Promotion() | |
| 210 | + .setId(id).setName(name).setType(type) | |
| 211 | + .setTotalPrice(calculateTotalPayPrice(orderItems)) | |
| 212 | + .setDiscountPrice(0) | |
| 213 | + .setItems(promotionItems).setMatch(false).setDescription(description); | |
| 214 | + result.getPromotions().add(promotion); | |
| 215 | + } | |
| 216 | + | |
| 217 | + public static String formatPrice(Integer price) { | |
| 218 | + return String.format("%.2f", price / 100d); | |
| 219 | + } | |
| 220 | + | |
| 221 | +} | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeRewardActivityPriceCalculator.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.service.price.calculator; | |
| 2 | + | |
| 3 | +import cn.hutool.core.collection.CollUtil; | |
| 4 | +import cn.hutool.core.util.StrUtil; | |
| 5 | +import cn.iocoder.yudao.module.promotion.api.reward.RewardActivityApi; | |
| 6 | +import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO; | |
| 7 | +import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum; | |
| 8 | +import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; | |
| 9 | +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; | |
| 10 | +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; | |
| 11 | +import org.springframework.core.annotation.Order; | |
| 12 | +import org.springframework.stereotype.Component; | |
| 13 | + | |
| 14 | +import javax.annotation.Resource; | |
| 15 | +import java.util.List; | |
| 16 | + | |
| 17 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | |
| 18 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; | |
| 19 | +import static cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculatorHelper.formatPrice; | |
| 20 | + | |
| 21 | +/** | |
| 22 | + * 满减送活动的 {@link TradePriceCalculator} 实现类 | |
| 23 | + * | |
| 24 | + * @author 芋道源码 | |
| 25 | + */ | |
| 26 | +@Component | |
| 27 | +@Order(TradePriceCalculator.ORDER_REWARD_ACTIVITY) | |
| 28 | +public class TradeRewardActivityPriceCalculator implements TradePriceCalculator { | |
| 29 | + | |
| 30 | + @Resource | |
| 31 | + private RewardActivityApi rewardActivityApi; | |
| 32 | + | |
| 33 | + @Override | |
| 34 | + public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { | |
| 35 | + // 获得 SKU 对应的满减送活动 | |
| 36 | + List<RewardActivityMatchRespDTO> rewardActivities = rewardActivityApi.getMatchRewardActivityList( | |
| 37 | + convertSet(result.getItems(), TradePriceCalculateRespBO.OrderItem::getSpuId)); | |
| 38 | + if (CollUtil.isEmpty(rewardActivities)) { | |
| 39 | + return; | |
| 40 | + } | |
| 41 | + | |
| 42 | + // 处理每个满减送活动 | |
| 43 | + rewardActivities.forEach(rewardActivity -> calculate(param, result, rewardActivity)); | |
| 44 | + } | |
| 45 | + | |
| 46 | + private void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result, | |
| 47 | + RewardActivityMatchRespDTO rewardActivity) { | |
| 48 | + // 1.1 获得满减送的订单项(商品)列表 | |
| 49 | + List<TradePriceCalculateRespBO.OrderItem> orderItems = filterMatchCouponOrderItems(result, rewardActivity); | |
| 50 | + if (CollUtil.isEmpty(orderItems)) { | |
| 51 | + return; | |
| 52 | + } | |
| 53 | + // 1.2 获得最大匹配的满减送活动的规则 | |
| 54 | + RewardActivityMatchRespDTO.Rule rule = getMaxMatchRewardActivityRule(rewardActivity, orderItems); | |
| 55 | + if (rule == null) { | |
| 56 | + return; | |
| 57 | + } | |
| 58 | + | |
| 59 | + // 2.1 计算可以优惠的金额 | |
| 60 | + Integer newDiscountPrice = rule.getDiscountPrice(); | |
| 61 | + // 2.2 计算分摊的优惠金额 | |
| 62 | + List<Integer> divideDiscountPrices = TradePriceCalculatorHelper.dividePrice(orderItems, newDiscountPrice); | |
| 63 | + | |
| 64 | + // 3.1 记录使用的优惠劵 | |
| 65 | + result.setCouponId(param.getCouponId()); | |
| 66 | + // 3.2 记录优惠明细 | |
| 67 | + TradePriceCalculatorHelper.addPromotion(result, orderItems, | |
| 68 | + rewardActivity.getId(), rewardActivity.getName(), PromotionTypeEnum.REWARD_ACTIVITY.getType(), | |
| 69 | + StrUtil.format("满减送:省 {} 元", formatPrice(rule.getDiscountPrice())), | |
| 70 | + divideDiscountPrices); | |
| 71 | + // 3.3 更新 SKU 优惠金额 | |
| 72 | + for (int i = 0; i < orderItems.size(); i++) { | |
| 73 | + TradePriceCalculateRespBO.OrderItem orderItem = orderItems.get(i); | |
| 74 | + orderItem.setDiscountPrice(orderItem.getDiscountPrice() + divideDiscountPrices.get(i)); | |
| 75 | + TradePriceCalculatorHelper.recountPayPrice(orderItem); | |
| 76 | + } | |
| 77 | + TradePriceCalculatorHelper.recountAllPrice(result); | |
| 78 | + } | |
| 79 | + | |
| 80 | + /** | |
| 81 | + * 获得满减送的订单项(商品)列表 | |
| 82 | + * | |
| 83 | + * @param result 计算结果 | |
| 84 | + * @param rewardActivity 满减送活动 | |
| 85 | + * @return 订单项(商品)列表 | |
| 86 | + */ | |
| 87 | + private List<TradePriceCalculateRespBO.OrderItem> filterMatchCouponOrderItems(TradePriceCalculateRespBO result, | |
| 88 | + RewardActivityMatchRespDTO rewardActivity) { | |
| 89 | + return filterList(result.getItems(), | |
| 90 | + orderItem -> CollUtil.contains(rewardActivity.getSpuIds(), orderItem.getSpuId())); | |
| 91 | + } | |
| 92 | + | |
| 93 | + /** | |
| 94 | + * 获得最大匹配的满减送活动的规则 | |
| 95 | + * | |
| 96 | + * @param rewardActivity 满减送活动 | |
| 97 | + * @param orderItems 商品项 | |
| 98 | + * @return 匹配的活动规则 | |
| 99 | + */ | |
| 100 | + private RewardActivityMatchRespDTO.Rule getMaxMatchRewardActivityRule(RewardActivityMatchRespDTO rewardActivity, | |
| 101 | + List<TradePriceCalculateRespBO.OrderItem> orderItems) { | |
| 102 | + // 1. 计算数量和价格 | |
| 103 | + Integer count = TradePriceCalculatorHelper.calculateTotalCount(orderItems); | |
| 104 | + Integer price = TradePriceCalculatorHelper.calculateTotalPayPrice(orderItems); | |
| 105 | + assert count != null && price != null; | |
| 106 | + | |
| 107 | + // 2. 倒序找一个最大优惠的规则 | |
| 108 | + for (int i = rewardActivity.getRules().size() - 1; i >= 0; i--) { | |
| 109 | + RewardActivityMatchRespDTO.Rule rule = rewardActivity.getRules().get(i); | |
| 110 | + if (PromotionConditionTypeEnum.PRICE.getType().equals(rewardActivity.getConditionType()) | |
| 111 | + && price >= rule.getLimit()) { | |
| 112 | + return rule; | |
| 113 | + } | |
| 114 | + if (PromotionConditionTypeEnum.COUNT.getType().equals(rewardActivity.getConditionType()) | |
| 115 | + && count >= rule.getLimit()) { | |
| 116 | + return rule; | |
| 117 | + } | |
| 118 | + } | |
| 119 | + return null; | |
| 120 | + } | |
| 121 | + | |
| 122 | + /** | |
| 123 | + * 获得满减送活动部匹配时的提示 | |
| 124 | + * | |
| 125 | + * @param rewardActivity 满减送活动 | |
| 126 | + * @return 提示 | |
| 127 | + */ | |
| 128 | + private String getRewardActivityNotMeetTip(RewardActivityMatchRespDTO rewardActivity) { | |
| 129 | + // TODO 芋艿:后面再想想;应该找第一个规则,算下还差多少即可。 | |
| 130 | + return "TODO"; | |
| 131 | + } | |
| 132 | + | |
| 133 | +} | ... | ... |
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/address/AppAddressController.java
| ... | ... | @@ -5,7 +5,7 @@ import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressCreate |
| 5 | 5 | import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressRespVO; |
| 6 | 6 | import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressUpdateReqVO; |
| 7 | 7 | import cn.iocoder.yudao.module.member.convert.address.AddressConvert; |
| 8 | -import cn.iocoder.yudao.module.member.dal.dataobject.address.AddressDO; | |
| 8 | +import cn.iocoder.yudao.module.member.dal.dataobject.address.MemberAddressDO; | |
| 9 | 9 | import cn.iocoder.yudao.module.member.service.address.AddressService; |
| 10 | 10 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 11 | 11 | import io.swagger.v3.oas.annotations.Parameter; |
| ... | ... | @@ -54,21 +54,21 @@ public class AppAddressController { |
| 54 | 54 | @Operation(summary = "获得用户收件地址") |
| 55 | 55 | @Parameter(name = "id", description = "编号", required = true, example = "1024") |
| 56 | 56 | public CommonResult<AppAddressRespVO> getAddress(@RequestParam("id") Long id) { |
| 57 | - AddressDO address = addressService.getAddress(getLoginUserId(), id); | |
| 57 | + MemberAddressDO address = addressService.getAddress(getLoginUserId(), id); | |
| 58 | 58 | return success(AddressConvert.INSTANCE.convert(address)); |
| 59 | 59 | } |
| 60 | 60 | |
| 61 | 61 | @GetMapping("/get-default") |
| 62 | 62 | @Operation(summary = "获得默认的用户收件地址") |
| 63 | 63 | public CommonResult<AppAddressRespVO> getDefaultUserAddress() { |
| 64 | - AddressDO address = addressService.getDefaultUserAddress(getLoginUserId()); | |
| 64 | + MemberAddressDO address = addressService.getDefaultUserAddress(getLoginUserId()); | |
| 65 | 65 | return success(AddressConvert.INSTANCE.convert(address)); |
| 66 | 66 | } |
| 67 | 67 | |
| 68 | 68 | @GetMapping("/list") |
| 69 | 69 | @Operation(summary = "获得用户收件地址列表") |
| 70 | 70 | public CommonResult<List<AppAddressRespVO>> getAddressList() { |
| 71 | - List<AddressDO> list = addressService.getAddressList(getLoginUserId()); | |
| 71 | + List<MemberAddressDO> list = addressService.getAddressList(getLoginUserId()); | |
| 72 | 72 | return success(AddressConvert.INSTANCE.convertList(list)); |
| 73 | 73 | } |
| 74 | 74 | ... | ... |
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/address/AddressConvert.java
| ... | ... | @@ -5,7 +5,7 @@ import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; |
| 5 | 5 | import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressCreateReqVO; |
| 6 | 6 | import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressRespVO; |
| 7 | 7 | import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressUpdateReqVO; |
| 8 | -import cn.iocoder.yudao.module.member.dal.dataobject.address.AddressDO; | |
| 8 | +import cn.iocoder.yudao.module.member.dal.dataobject.address.MemberAddressDO; | |
| 9 | 9 | import org.mapstruct.Mapper; |
| 10 | 10 | import org.mapstruct.factory.Mappers; |
| 11 | 11 | |
| ... | ... | @@ -21,16 +21,16 @@ public interface AddressConvert { |
| 21 | 21 | |
| 22 | 22 | AddressConvert INSTANCE = Mappers.getMapper(AddressConvert.class); |
| 23 | 23 | |
| 24 | - AddressDO convert(AppAddressCreateReqVO bean); | |
| 24 | + MemberAddressDO convert(AppAddressCreateReqVO bean); | |
| 25 | 25 | |
| 26 | - AddressDO convert(AppAddressUpdateReqVO bean); | |
| 26 | + MemberAddressDO convert(AppAddressUpdateReqVO bean); | |
| 27 | 27 | |
| 28 | - AppAddressRespVO convert(AddressDO bean); | |
| 28 | + AppAddressRespVO convert(MemberAddressDO bean); | |
| 29 | 29 | |
| 30 | - List<AppAddressRespVO> convertList(List<AddressDO> list); | |
| 30 | + List<AppAddressRespVO> convertList(List<MemberAddressDO> list); | |
| 31 | 31 | |
| 32 | - PageResult<AppAddressRespVO> convertPage(PageResult<AddressDO> page); | |
| 32 | + PageResult<AppAddressRespVO> convertPage(PageResult<MemberAddressDO> page); | |
| 33 | 33 | |
| 34 | - AddressRespDTO convert02(AddressDO bean); | |
| 34 | + AddressRespDTO convert02(MemberAddressDO bean); | |
| 35 | 35 | |
| 36 | 36 | } | ... | ... |
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/address/AddressDO.java renamed to yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/address/MemberAddressDO.java
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/address/AddressMapper.java
| ... | ... | @@ -2,21 +2,21 @@ package cn.iocoder.yudao.module.member.dal.mysql.address; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| 4 | 4 | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| 5 | -import cn.iocoder.yudao.module.member.dal.dataobject.address.AddressDO; | |
| 5 | +import cn.iocoder.yudao.module.member.dal.dataobject.address.MemberAddressDO; | |
| 6 | 6 | import org.apache.ibatis.annotations.Mapper; |
| 7 | 7 | |
| 8 | 8 | import java.util.List; |
| 9 | 9 | |
| 10 | 10 | @Mapper |
| 11 | -public interface AddressMapper extends BaseMapperX<AddressDO> { | |
| 11 | +public interface AddressMapper extends BaseMapperX<MemberAddressDO> { | |
| 12 | 12 | |
| 13 | - default AddressDO selectByIdAndUserId(Long id, Long userId) { | |
| 14 | - return selectOne(AddressDO::getId, id, AddressDO::getUserId, userId); | |
| 13 | + default MemberAddressDO selectByIdAndUserId(Long id, Long userId) { | |
| 14 | + return selectOne(MemberAddressDO::getId, id, MemberAddressDO::getUserId, userId); | |
| 15 | 15 | } |
| 16 | 16 | |
| 17 | - default List<AddressDO> selectListByUserIdAndDefaulted(Long userId, Boolean defaulted) { | |
| 18 | - return selectList(new LambdaQueryWrapperX<AddressDO>().eq(AddressDO::getUserId, userId) | |
| 19 | - .eqIfPresent(AddressDO::getDefaulted, defaulted)); | |
| 17 | + default List<MemberAddressDO> selectListByUserIdAndDefaulted(Long userId, Boolean defaulted) { | |
| 18 | + return selectList(new LambdaQueryWrapperX<MemberAddressDO>().eq(MemberAddressDO::getUserId, userId) | |
| 19 | + .eqIfPresent(MemberAddressDO::getDefaulted, defaulted)); | |
| 20 | 20 | } |
| 21 | 21 | |
| 22 | 22 | } | ... | ... |
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/address/AddressService.java
| ... | ... | @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.member.service.address; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressCreateReqVO; |
| 4 | 4 | import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressUpdateReqVO; |
| 5 | -import cn.iocoder.yudao.module.member.dal.dataobject.address.AddressDO; | |
| 5 | +import cn.iocoder.yudao.module.member.dal.dataobject.address.MemberAddressDO; | |
| 6 | 6 | |
| 7 | 7 | import javax.validation.Valid; |
| 8 | 8 | import java.util.List; |
| ... | ... | @@ -46,7 +46,7 @@ public interface AddressService { |
| 46 | 46 | * @param id 编号 |
| 47 | 47 | * @return 用户收件地址 |
| 48 | 48 | */ |
| 49 | - AddressDO getAddress(Long userId, Long id); | |
| 49 | + MemberAddressDO getAddress(Long userId, Long id); | |
| 50 | 50 | |
| 51 | 51 | /** |
| 52 | 52 | * 获得用户收件地址列表 |
| ... | ... | @@ -54,7 +54,7 @@ public interface AddressService { |
| 54 | 54 | * @param userId 用户编号 |
| 55 | 55 | * @return 用户收件地址列表 |
| 56 | 56 | */ |
| 57 | - List<AddressDO> getAddressList(Long userId); | |
| 57 | + List<MemberAddressDO> getAddressList(Long userId); | |
| 58 | 58 | |
| 59 | 59 | /** |
| 60 | 60 | * 获得用户默认的收件地址 |
| ... | ... | @@ -62,6 +62,6 @@ public interface AddressService { |
| 62 | 62 | * @param userId 用户编号 |
| 63 | 63 | * @return 用户收件地址 |
| 64 | 64 | */ |
| 65 | - AddressDO getDefaultUserAddress(Long userId); | |
| 65 | + MemberAddressDO getDefaultUserAddress(Long userId); | |
| 66 | 66 | |
| 67 | 67 | } | ... | ... |
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/address/AddressServiceImpl.java
| ... | ... | @@ -4,7 +4,7 @@ import cn.hutool.core.collection.CollUtil; |
| 4 | 4 | import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressCreateReqVO; |
| 5 | 5 | import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressUpdateReqVO; |
| 6 | 6 | import cn.iocoder.yudao.module.member.convert.address.AddressConvert; |
| 7 | -import cn.iocoder.yudao.module.member.dal.dataobject.address.AddressDO; | |
| 7 | +import cn.iocoder.yudao.module.member.dal.dataobject.address.MemberAddressDO; | |
| 8 | 8 | import cn.iocoder.yudao.module.member.dal.mysql.address.AddressMapper; |
| 9 | 9 | import org.springframework.stereotype.Service; |
| 10 | 10 | import org.springframework.transaction.annotation.Transactional; |
| ... | ... | @@ -33,12 +33,12 @@ public class AddressServiceImpl implements AddressService { |
| 33 | 33 | public Long createAddress(Long userId, AppAddressCreateReqVO createReqVO) { |
| 34 | 34 | // 如果添加的是默认收件地址,则将原默认地址修改为非默认 |
| 35 | 35 | if (Boolean.TRUE.equals(createReqVO.getDefaulted())) { |
| 36 | - List<AddressDO> addresses = addressMapper.selectListByUserIdAndDefaulted(userId, true); | |
| 37 | - addresses.forEach(address -> addressMapper.updateById(new AddressDO().setId(address.getId()).setDefaulted(false))); | |
| 36 | + List<MemberAddressDO> addresses = addressMapper.selectListByUserIdAndDefaulted(userId, true); | |
| 37 | + addresses.forEach(address -> addressMapper.updateById(new MemberAddressDO().setId(address.getId()).setDefaulted(false))); | |
| 38 | 38 | } |
| 39 | 39 | |
| 40 | 40 | // 插入 |
| 41 | - AddressDO address = AddressConvert.INSTANCE.convert(createReqVO); | |
| 41 | + MemberAddressDO address = AddressConvert.INSTANCE.convert(createReqVO); | |
| 42 | 42 | address.setUserId(userId); |
| 43 | 43 | addressMapper.insert(address); |
| 44 | 44 | // 返回 |
| ... | ... | @@ -53,13 +53,13 @@ public class AddressServiceImpl implements AddressService { |
| 53 | 53 | |
| 54 | 54 | // 如果修改的是默认收件地址,则将原默认地址修改为非默认 |
| 55 | 55 | if (Boolean.TRUE.equals(updateReqVO.getDefaulted())) { |
| 56 | - List<AddressDO> addresses = addressMapper.selectListByUserIdAndDefaulted(userId, true); | |
| 56 | + List<MemberAddressDO> addresses = addressMapper.selectListByUserIdAndDefaulted(userId, true); | |
| 57 | 57 | addresses.stream().filter(u -> !u.getId().equals(updateReqVO.getId())) // 排除自己 |
| 58 | - .forEach(address -> addressMapper.updateById(new AddressDO().setId(address.getId()).setDefaulted(false))); | |
| 58 | + .forEach(address -> addressMapper.updateById(new MemberAddressDO().setId(address.getId()).setDefaulted(false))); | |
| 59 | 59 | } |
| 60 | 60 | |
| 61 | 61 | // 更新 |
| 62 | - AddressDO updateObj = AddressConvert.INSTANCE.convert(updateReqVO); | |
| 62 | + MemberAddressDO updateObj = AddressConvert.INSTANCE.convert(updateReqVO); | |
| 63 | 63 | addressMapper.updateById(updateObj); |
| 64 | 64 | } |
| 65 | 65 | |
| ... | ... | @@ -72,25 +72,25 @@ public class AddressServiceImpl implements AddressService { |
| 72 | 72 | } |
| 73 | 73 | |
| 74 | 74 | private void validAddressExists(Long userId, Long id) { |
| 75 | - AddressDO addressDO = getAddress(userId, id); | |
| 75 | + MemberAddressDO addressDO = getAddress(userId, id); | |
| 76 | 76 | if (addressDO == null) { |
| 77 | 77 | throw exception(ADDRESS_NOT_EXISTS); |
| 78 | 78 | } |
| 79 | 79 | } |
| 80 | 80 | |
| 81 | 81 | @Override |
| 82 | - public AddressDO getAddress(Long userId, Long id) { | |
| 82 | + public MemberAddressDO getAddress(Long userId, Long id) { | |
| 83 | 83 | return addressMapper.selectByIdAndUserId(id, userId); |
| 84 | 84 | } |
| 85 | 85 | |
| 86 | 86 | @Override |
| 87 | - public List<AddressDO> getAddressList(Long userId) { | |
| 87 | + public List<MemberAddressDO> getAddressList(Long userId) { | |
| 88 | 88 | return addressMapper.selectListByUserIdAndDefaulted(userId, null); |
| 89 | 89 | } |
| 90 | 90 | |
| 91 | 91 | @Override |
| 92 | - public AddressDO getDefaultUserAddress(Long userId) { | |
| 93 | - List<AddressDO> addresses = addressMapper.selectListByUserIdAndDefaulted(userId, true); | |
| 92 | + public MemberAddressDO getDefaultUserAddress(Long userId) { | |
| 93 | + List<MemberAddressDO> addresses = addressMapper.selectListByUserIdAndDefaulted(userId, true); | |
| 94 | 94 | return CollUtil.getFirst(addresses); |
| 95 | 95 | } |
| 96 | 96 | ... | ... |
yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/address/AddressServiceImplTest.java
| ... | ... | @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.member.service.address; |
| 3 | 3 | import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; |
| 4 | 4 | import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressCreateReqVO; |
| 5 | 5 | import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressUpdateReqVO; |
| 6 | -import cn.iocoder.yudao.module.member.dal.dataobject.address.AddressDO; | |
| 6 | +import cn.iocoder.yudao.module.member.dal.dataobject.address.MemberAddressDO; | |
| 7 | 7 | import cn.iocoder.yudao.module.member.dal.mysql.address.AddressMapper; |
| 8 | 8 | import org.junit.jupiter.api.Test; |
| 9 | 9 | import org.springframework.context.annotation.Import; |
| ... | ... | @@ -42,14 +42,14 @@ public class AddressServiceImplTest extends BaseDbUnitTest { |
| 42 | 42 | // 断言 |
| 43 | 43 | assertNotNull(addressId); |
| 44 | 44 | // 校验记录的属性是否正确 |
| 45 | - AddressDO address = addressMapper.selectById(addressId); | |
| 45 | + MemberAddressDO address = addressMapper.selectById(addressId); | |
| 46 | 46 | assertPojoEquals(reqVO, address); |
| 47 | 47 | } |
| 48 | 48 | |
| 49 | 49 | @Test |
| 50 | 50 | public void testUpdateAddress_success() { |
| 51 | 51 | // mock 数据 |
| 52 | - AddressDO dbAddress = randomPojo(AddressDO.class); | |
| 52 | + MemberAddressDO dbAddress = randomPojo(MemberAddressDO.class); | |
| 53 | 53 | addressMapper.insert(dbAddress);// @Sql: 先插入出一条存在的数据 |
| 54 | 54 | // 准备参数 |
| 55 | 55 | AppAddressUpdateReqVO reqVO = randomPojo(AppAddressUpdateReqVO.class, o -> { |
| ... | ... | @@ -59,7 +59,7 @@ public class AddressServiceImplTest extends BaseDbUnitTest { |
| 59 | 59 | // 调用 |
| 60 | 60 | addressService.updateAddress(dbAddress.getUserId(), reqVO); |
| 61 | 61 | // 校验是否更新正确 |
| 62 | - AddressDO address = addressMapper.selectById(reqVO.getId()); // 获取最新的 | |
| 62 | + MemberAddressDO address = addressMapper.selectById(reqVO.getId()); // 获取最新的 | |
| 63 | 63 | assertPojoEquals(reqVO, address); |
| 64 | 64 | } |
| 65 | 65 | |
| ... | ... | @@ -75,7 +75,7 @@ public class AddressServiceImplTest extends BaseDbUnitTest { |
| 75 | 75 | @Test |
| 76 | 76 | public void testDeleteAddress_success() { |
| 77 | 77 | // mock 数据 |
| 78 | - AddressDO dbAddress = randomPojo(AddressDO.class); | |
| 78 | + MemberAddressDO dbAddress = randomPojo(MemberAddressDO.class); | |
| 79 | 79 | addressMapper.insert(dbAddress);// @Sql: 先插入出一条存在的数据 |
| 80 | 80 | // 准备参数 |
| 81 | 81 | Long id = dbAddress.getId(); | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/ip/AreaConvert.java
| ... | ... | @@ -23,7 +23,8 @@ public interface AreaConvert { |
| 23 | 23 | @Mapping(source = "type", target = "leaf") |
| 24 | 24 | AreaNodeSimpleRespVO convert(Area area); |
| 25 | 25 | |
| 26 | - default Boolean convertAreaType(Integer type){ | |
| 27 | - return Objects.equals(AreaTypeEnum.DISTRICT.getType(),type); | |
| 26 | + default Boolean convertAreaType(Integer type) { | |
| 27 | + return Objects.equals(AreaTypeEnum.DISTRICT.getType(), type); | |
| 28 | 28 | } |
| 29 | + | |
| 29 | 30 | } | ... | ... |