Commit 241957507c57c6a3300093c1419c9689d458f086
Committed by
Gitee
!1084 批量优化或修改BUG
Merge pull request !1084 from 痴货/develop-mall
Showing
42 changed files
with
746 additions
and
165 deletions
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.java
| @@ -69,8 +69,8 @@ public class AppProductSpuController { | @@ -69,8 +69,8 @@ public class AppProductSpuController { | ||
| 69 | list.forEach(spu -> spu.setSalesCount(spu.getSalesCount() + spu.getVirtualSalesCount())); | 69 | list.forEach(spu -> spu.setSalesCount(spu.getSalesCount() + spu.getVirtualSalesCount())); |
| 70 | List<AppProductSpuRespVO> voList = BeanUtils.toBean(list, AppProductSpuRespVO.class); | 70 | List<AppProductSpuRespVO> voList = BeanUtils.toBean(list, AppProductSpuRespVO.class); |
| 71 | // 处理 vip 价格 | 71 | // 处理 vip 价格 |
| 72 | - MemberLevelRespDTO memberLevel = getMemberLevel(); | ||
| 73 | - voList.forEach(vo -> vo.setVipPrice(calculateVipPrice(vo.getPrice(), memberLevel))); | 72 | +// MemberLevelRespDTO memberLevel = getMemberLevel(); |
| 73 | +// voList.forEach(vo -> vo.setVipPrice(calculateVipPrice(vo.getPrice(), memberLevel))); | ||
| 74 | return success(voList); | 74 | return success(voList); |
| 75 | } | 75 | } |
| 76 | 76 | ||
| @@ -86,8 +86,8 @@ public class AppProductSpuController { | @@ -86,8 +86,8 @@ public class AppProductSpuController { | ||
| 86 | pageResult.getList().forEach(spu -> spu.setSalesCount(spu.getSalesCount() + spu.getVirtualSalesCount())); | 86 | pageResult.getList().forEach(spu -> spu.setSalesCount(spu.getSalesCount() + spu.getVirtualSalesCount())); |
| 87 | PageResult<AppProductSpuRespVO> voPageResult = BeanUtils.toBean(pageResult, AppProductSpuRespVO.class); | 87 | PageResult<AppProductSpuRespVO> voPageResult = BeanUtils.toBean(pageResult, AppProductSpuRespVO.class); |
| 88 | // 处理 vip 价格 | 88 | // 处理 vip 价格 |
| 89 | - MemberLevelRespDTO memberLevel = getMemberLevel(); | ||
| 90 | - voPageResult.getList().forEach(vo -> vo.setVipPrice(calculateVipPrice(vo.getPrice(), memberLevel))); | 89 | +// MemberLevelRespDTO memberLevel = getMemberLevel(); |
| 90 | +// voPageResult.getList().forEach(vo -> vo.setVipPrice(calculateVipPrice(vo.getPrice(), memberLevel))); | ||
| 91 | return success(voPageResult); | 91 | return success(voPageResult); |
| 92 | } | 92 | } |
| 93 | 93 | ||
| @@ -142,7 +142,7 @@ public class AppProductSpuController { | @@ -142,7 +142,7 @@ public class AppProductSpuController { | ||
| 142 | */ | 142 | */ |
| 143 | public Integer calculateVipPrice(Integer price, MemberLevelRespDTO memberLevel) { | 143 | public Integer calculateVipPrice(Integer price, MemberLevelRespDTO memberLevel) { |
| 144 | if (memberLevel == null || memberLevel.getDiscountPercent() == null) { | 144 | if (memberLevel == null || memberLevel.getDiscountPercent() == null) { |
| 145 | - return 0; | 145 | + return null; |
| 146 | } | 146 | } |
| 147 | Integer newPrice = price * memberLevel.getDiscountPercent() / 100; | 147 | Integer newPrice = price * memberLevel.getDiscountPercent() / 100; |
| 148 | return price - newPrice; | 148 | return price - newPrice; |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuRespVO.java
| @@ -38,8 +38,8 @@ public class AppProductSpuRespVO { | @@ -38,8 +38,8 @@ public class AppProductSpuRespVO { | ||
| 38 | @Schema(description = "市场价,单位使用:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | 38 | @Schema(description = "市场价,单位使用:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") |
| 39 | private Integer marketPrice; | 39 | private Integer marketPrice; |
| 40 | 40 | ||
| 41 | - @Schema(description = "VIP 价格,单位使用:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "968") // 通过会员等级,计算出折扣后价格 | ||
| 42 | - private Integer vipPrice; | 41 | +// @Schema(description = "VIP 价格,单位使用:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "968") // 通过会员等级,计算出折扣后价格 |
| 42 | +// private Integer vipPrice; | ||
| 43 | 43 | ||
| 44 | @Schema(description = "库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "666") | 44 | @Schema(description = "库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "666") |
| 45 | private Integer stock; | 45 | private Integer stock; |
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/discount/dto/DiscountProductRespDTO.java
| @@ -2,6 +2,8 @@ package cn.iocoder.yudao.module.promotion.api.discount.dto; | @@ -2,6 +2,8 @@ package cn.iocoder.yudao.module.promotion.api.discount.dto; | ||
| 2 | 2 | ||
| 3 | import lombok.Data; | 3 | import lombok.Data; |
| 4 | 4 | ||
| 5 | +import java.time.LocalDateTime; | ||
| 6 | + | ||
| 5 | /** | 7 | /** |
| 6 | * 限时折扣活动商品 Response DTO | 8 | * 限时折扣活动商品 Response DTO |
| 7 | * | 9 | * |
| @@ -44,5 +46,12 @@ public class DiscountProductRespDTO { | @@ -44,5 +46,12 @@ public class DiscountProductRespDTO { | ||
| 44 | * 活动标题 | 46 | * 活动标题 |
| 45 | */ | 47 | */ |
| 46 | private String activityName; | 48 | private String activityName; |
| 49 | + /** | ||
| 50 | + * 活动结束时间点 | ||
| 51 | + * | ||
| 52 | + * 冗余 {@link DiscountActivityDO#getEndTime()} | ||
| 53 | + */ | ||
| 54 | + private LocalDateTime activityEndTime; | ||
| 55 | + | ||
| 47 | 56 | ||
| 48 | } | 57 | } |
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/reward/RewardActivityApi.java
| @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.promotion.api.reward; | @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.promotion.api.reward; | ||
| 3 | import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO; | 3 | import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO; |
| 4 | 4 | ||
| 5 | import java.time.LocalDateTime; | 5 | import java.time.LocalDateTime; |
| 6 | +import java.util.Collection; | ||
| 6 | import java.util.List; | 7 | import java.util.List; |
| 7 | 8 | ||
| 8 | /** | 9 | /** |
| @@ -21,4 +22,13 @@ public interface RewardActivityApi { | @@ -21,4 +22,13 @@ public interface RewardActivityApi { | ||
| 21 | */ | 22 | */ |
| 22 | List<RewardActivityMatchRespDTO> getRewardActivityListByStatusAndNow(Integer status, LocalDateTime dateTime); | 23 | List<RewardActivityMatchRespDTO> getRewardActivityListByStatusAndNow(Integer status, LocalDateTime dateTime); |
| 23 | 24 | ||
| 25 | + /** | ||
| 26 | + * 获取指定 spu 编号最近参加的活动,每个 spuId 只返回一条记录 | ||
| 27 | + * | ||
| 28 | + * @param spuIds spu 编号 | ||
| 29 | + * @param status 状态 | ||
| 30 | + * @param dateTime 当前日期时间 | ||
| 31 | + * @return 满减送活动列表 | ||
| 32 | + */ | ||
| 33 | + List<RewardActivityMatchRespDTO> getRewardActivityBySpuIdsAndStatusAndDateTimeLt(Collection<Long> spuIds, Integer status, LocalDateTime dateTime); | ||
| 24 | } | 34 | } |
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
| @@ -15,6 +15,7 @@ public interface ErrorCodeConstants { | @@ -15,6 +15,7 @@ public interface ErrorCodeConstants { | ||
| 15 | ErrorCode DISCOUNT_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_001_002, "限时折扣活动已关闭,不能修改"); | 15 | ErrorCode DISCOUNT_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_001_002, "限时折扣活动已关闭,不能修改"); |
| 16 | ErrorCode DISCOUNT_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED = new ErrorCode(1_013_001_003, "限时折扣活动未关闭,不能删除"); | 16 | ErrorCode DISCOUNT_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED = new ErrorCode(1_013_001_003, "限时折扣活动未关闭,不能删除"); |
| 17 | ErrorCode DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_001_004, "限时折扣活动已关闭,不能重复关闭"); | 17 | ErrorCode DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_001_004, "限时折扣活动已关闭,不能重复关闭"); |
| 18 | + ErrorCode DISCOUNT_ACTIVITY_TYPE_NOT_EXISTS = new ErrorCode(1_013_001_005, "限时折扣活动类型不存在"); | ||
| 18 | 19 | ||
| 19 | // ========== Banner 相关 1-013-002-000 ============ | 20 | // ========== Banner 相关 1-013-002-000 ============ |
| 20 | ErrorCode BANNER_NOT_EXISTS = new ErrorCode(1_013_002_000, "Banner 不存在"); | 21 | ErrorCode BANNER_NOT_EXISTS = new ErrorCode(1_013_002_000, "Banner 不存在"); |
| @@ -45,6 +46,7 @@ public interface ErrorCodeConstants { | @@ -45,6 +46,7 @@ public interface ErrorCodeConstants { | ||
| 45 | ErrorCode REWARD_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED = new ErrorCode(1_013_006_003, "满减送活动未关闭,不能删除"); | 46 | ErrorCode REWARD_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED = new ErrorCode(1_013_006_003, "满减送活动未关闭,不能删除"); |
| 46 | ErrorCode REWARD_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_006_004, "满减送活动已关闭,不能重复关闭"); | 47 | ErrorCode REWARD_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_006_004, "满减送活动已关闭,不能重复关闭"); |
| 47 | ErrorCode REWARD_ACTIVITY_SCOPE_EXISTS = new ErrorCode(1_013_006_005, "与该时间段已存在的满减送活动商品范围冲突"); | 48 | ErrorCode REWARD_ACTIVITY_SCOPE_EXISTS = new ErrorCode(1_013_006_005, "与该时间段已存在的满减送活动商品范围冲突"); |
| 49 | + ErrorCode REWARD_ACTIVITY_TYPE_NOT_EXISTS = new ErrorCode(1_013_006_006, "满减送活动类型不存在"); | ||
| 48 | 50 | ||
| 49 | // ========== TODO 空着 1-013-007-000 ============ | 51 | // ========== TODO 空着 1-013-007-000 ============ |
| 50 | 52 |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/discount/DiscountActivityApiImpl.java
| @@ -24,7 +24,7 @@ public class DiscountActivityApiImpl implements DiscountActivityApi { | @@ -24,7 +24,7 @@ public class DiscountActivityApiImpl implements DiscountActivityApi { | ||
| 24 | 24 | ||
| 25 | @Override | 25 | @Override |
| 26 | public List<DiscountProductRespDTO> getMatchDiscountProductList(Collection<Long> skuIds) { | 26 | public List<DiscountProductRespDTO> getMatchDiscountProductList(Collection<Long> skuIds) { |
| 27 | - return DiscountActivityConvert.INSTANCE.convertList02(discountActivityService.getMatchDiscountProductList(skuIds)); | 27 | + return discountActivityService.getMatchDiscountProductList(skuIds); |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | } | 30 | } |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/reward/RewardActivityApiImpl.java
| @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.promotion.api.reward; | @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.promotion.api.reward; | ||
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | 3 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 4 | import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO; | 4 | import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO; |
| 5 | +import cn.iocoder.yudao.module.promotion.convert.reward.RewardActivityConvert; | ||
| 5 | import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; | 6 | import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; |
| 6 | import cn.iocoder.yudao.module.promotion.service.reward.RewardActivityService; | 7 | import cn.iocoder.yudao.module.promotion.service.reward.RewardActivityService; |
| 7 | import jakarta.annotation.Resource; | 8 | import jakarta.annotation.Resource; |
| @@ -9,6 +10,7 @@ import org.springframework.stereotype.Service; | @@ -9,6 +10,7 @@ import org.springframework.stereotype.Service; | ||
| 9 | import org.springframework.validation.annotation.Validated; | 10 | import org.springframework.validation.annotation.Validated; |
| 10 | 11 | ||
| 11 | import java.time.LocalDateTime; | 12 | import java.time.LocalDateTime; |
| 13 | +import java.util.Collection; | ||
| 12 | import java.util.List; | 14 | import java.util.List; |
| 13 | 15 | ||
| 14 | /** | 16 | /** |
| @@ -29,4 +31,10 @@ public class RewardActivityApiImpl implements RewardActivityApi { | @@ -29,4 +31,10 @@ public class RewardActivityApiImpl implements RewardActivityApi { | ||
| 29 | return BeanUtils.toBean(list, RewardActivityMatchRespDTO.class); | 31 | return BeanUtils.toBean(list, RewardActivityMatchRespDTO.class); |
| 30 | } | 32 | } |
| 31 | 33 | ||
| 34 | + @Override | ||
| 35 | + public List<RewardActivityMatchRespDTO> getRewardActivityBySpuIdsAndStatusAndDateTimeLt(Collection<Long> spuIds, Integer status, LocalDateTime dateTime) { | ||
| 36 | + List<RewardActivityDO> rewardActivityBySpuIdsAndStatusAndDateTimeLt = rewardActivityService.getRewardActivityBySpuIdsAndStatusAndDateTimeLt(spuIds, status, dateTime); | ||
| 37 | + return RewardActivityConvert.INSTANCE.convertList(rewardActivityBySpuIdsAndStatusAndDateTimeLt); | ||
| 38 | + } | ||
| 39 | + | ||
| 32 | } | 40 | } |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateBaseVO.java
| @@ -2,9 +2,11 @@ package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template; | @@ -2,9 +2,11 @@ package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template; | ||
| 2 | 2 | ||
| 3 | import cn.hutool.core.collection.CollUtil; | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | import cn.hutool.core.util.ObjectUtil; | 4 | import cn.hutool.core.util.ObjectUtil; |
| 5 | +import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; | ||
| 5 | import cn.iocoder.yudao.framework.common.validation.InEnum; | 6 | import cn.iocoder.yudao.framework.common.validation.InEnum; |
| 6 | import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; | 7 | import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; |
| 7 | import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; | 8 | import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; |
| 9 | +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum; | ||
| 8 | import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTemplateValidityTypeEnum; | 10 | import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTemplateValidityTypeEnum; |
| 9 | import com.fasterxml.jackson.annotation.JsonFormat; | 11 | import com.fasterxml.jackson.annotation.JsonFormat; |
| 10 | import com.fasterxml.jackson.annotation.JsonIgnore; | 12 | import com.fasterxml.jackson.annotation.JsonIgnore; |
| @@ -12,6 +14,7 @@ import io.swagger.v3.oas.annotations.media.Schema; | @@ -12,6 +14,7 @@ import io.swagger.v3.oas.annotations.media.Schema; | ||
| 12 | import lombok.Data; | 14 | import lombok.Data; |
| 13 | import org.springframework.format.annotation.DateTimeFormat; | 15 | import org.springframework.format.annotation.DateTimeFormat; |
| 14 | 16 | ||
| 17 | +import jakarta.validation.Validator; | ||
| 15 | import jakarta.validation.constraints.AssertTrue; | 18 | import jakarta.validation.constraints.AssertTrue; |
| 16 | import jakarta.validation.constraints.Min; | 19 | import jakarta.validation.constraints.Min; |
| 17 | import jakarta.validation.constraints.NotNull; | 20 | import jakarta.validation.constraints.NotNull; |
| @@ -37,11 +40,11 @@ public class CouponTemplateBaseVO { | @@ -37,11 +40,11 @@ public class CouponTemplateBaseVO { | ||
| 37 | private String description; | 40 | private String description; |
| 38 | 41 | ||
| 39 | @Schema(description = "发行总量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") // -1 - 则表示不限制发放数量 | 42 | @Schema(description = "发行总量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") // -1 - 则表示不限制发放数量 |
| 40 | - @NotNull(message = "发行总量不能为空") | 43 | + @NotNull(message = "发行总量不能为空", groups = {User.class}) |
| 41 | private Integer totalCount; | 44 | private Integer totalCount; |
| 42 | 45 | ||
| 43 | @Schema(description = "每人限领个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "66") // -1 - 则表示不限制 | 46 | @Schema(description = "每人限领个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "66") // -1 - 则表示不限制 |
| 44 | - @NotNull(message = "每人限领个数不能为空") | 47 | + @NotNull(message = "每人限领个数不能为空", groups = {User.class}) |
| 45 | private Integer takeLimitCount; | 48 | private Integer takeLimitCount; |
| 46 | 49 | ||
| 47 | @Schema(description = "领取方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | 50 | @Schema(description = "领取方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| @@ -89,13 +92,16 @@ public class CouponTemplateBaseVO { | @@ -89,13 +92,16 @@ public class CouponTemplateBaseVO { | ||
| 89 | private Integer discountType; | 92 | private Integer discountType; |
| 90 | 93 | ||
| 91 | @Schema(description = "折扣百分比", example = "80") // 例如说,80% 为 80 | 94 | @Schema(description = "折扣百分比", example = "80") // 例如说,80% 为 80 |
| 95 | + @NotNull(message = "折扣百分比不能为空", groups = {Percent.class}) | ||
| 92 | private Integer discountPercent; | 96 | private Integer discountPercent; |
| 93 | 97 | ||
| 94 | @Schema(description = "优惠金额", example = "10") | 98 | @Schema(description = "优惠金额", example = "10") |
| 95 | @Min(value = 0, message = "优惠金额需要大于等于 0") | 99 | @Min(value = 0, message = "优惠金额需要大于等于 0") |
| 100 | + @NotNull(message = "优惠金额不能为空", groups = {Price.class}) | ||
| 96 | private Integer discountPrice; | 101 | private Integer discountPrice; |
| 97 | 102 | ||
| 98 | @Schema(description = "折扣上限", example = "100") // 单位:分,仅在 discountType 为 PERCENT 使用 | 103 | @Schema(description = "折扣上限", example = "100") // 单位:分,仅在 discountType 为 PERCENT 使用 |
| 104 | + @NotNull(message = "折扣上限不能为空", groups = {Percent.class}) | ||
| 99 | private Integer discountLimitPrice; | 105 | private Integer discountLimitPrice; |
| 100 | 106 | ||
| 101 | @AssertTrue(message = "商品范围编号的数组不能为空") | 107 | @AssertTrue(message = "商品范围编号的数组不能为空") |
| @@ -154,4 +160,54 @@ public class CouponTemplateBaseVO { | @@ -154,4 +160,54 @@ public class CouponTemplateBaseVO { | ||
| 154 | || discountLimitPrice != null; | 160 | || discountLimitPrice != null; |
| 155 | } | 161 | } |
| 156 | 162 | ||
| 163 | + //-------------------------领取方式校验start---------------------------- | ||
| 164 | + | ||
| 165 | + /** | ||
| 166 | + * 直接领取 | ||
| 167 | + */ | ||
| 168 | + public interface User { | ||
| 169 | + } | ||
| 170 | + | ||
| 171 | + /** | ||
| 172 | + * 指定发放 | ||
| 173 | + */ | ||
| 174 | + public interface Admin { | ||
| 175 | + } | ||
| 176 | + | ||
| 177 | + //-------------------------领取方式校验end------------------------------ | ||
| 178 | + | ||
| 179 | + //-------------------------优惠类型校验start---------------------------- | ||
| 180 | + | ||
| 181 | + /** | ||
| 182 | + * 满减 | ||
| 183 | + */ | ||
| 184 | + public interface Price { | ||
| 185 | + } | ||
| 186 | + | ||
| 187 | + /** | ||
| 188 | + * 折扣 | ||
| 189 | + */ | ||
| 190 | + public interface Percent { | ||
| 191 | + } | ||
| 192 | + | ||
| 193 | + //-------------------------优惠类型校验end------------------------------ | ||
| 194 | + | ||
| 195 | + public void validate(Validator validator) { | ||
| 196 | + | ||
| 197 | + //领取方式校验 | ||
| 198 | + if (CouponTakeTypeEnum.USER.getType().equals(takeType)) { | ||
| 199 | + ValidationUtils.validate(validator, this, User.class); | ||
| 200 | + } else if (CouponTakeTypeEnum.ADMIN.getType().equals(takeType)) { | ||
| 201 | + ValidationUtils.validate(validator, this, Admin.class); | ||
| 202 | + } | ||
| 203 | + | ||
| 204 | + //优惠类型校验 | ||
| 205 | + if (PromotionDiscountTypeEnum.PRICE.getType().equals(discountType)){ | ||
| 206 | + ValidationUtils.validate(validator, this, Price.class); | ||
| 207 | + } else if (PromotionDiscountTypeEnum.PERCENT.getType().equals(discountType)) { | ||
| 208 | + ValidationUtils.validate(validator, this, Percent.class); | ||
| 209 | + } | ||
| 210 | + | ||
| 211 | + } | ||
| 212 | + | ||
| 157 | } | 213 | } |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/activity/AppActivityController.java
| @@ -33,6 +33,7 @@ import org.springframework.web.bind.annotation.RestController; | @@ -33,6 +33,7 @@ import org.springframework.web.bind.annotation.RestController; | ||
| 33 | 33 | ||
| 34 | import java.time.LocalDateTime; | 34 | import java.time.LocalDateTime; |
| 35 | import java.util.*; | 35 | import java.util.*; |
| 36 | +import java.util.stream.Collectors; | ||
| 36 | 37 | ||
| 37 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 38 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 38 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; | 39 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; |
| @@ -150,36 +151,32 @@ public class AppActivityController { | @@ -150,36 +151,32 @@ public class AppActivityController { | ||
| 150 | } | 151 | } |
| 151 | 152 | ||
| 152 | private void getRewardActivityList(Collection<Long> spuIds, LocalDateTime now, List<AppActivityRespVO> activityList) { | 153 | private void getRewardActivityList(Collection<Long> spuIds, LocalDateTime now, List<AppActivityRespVO> activityList) { |
| 153 | - // 1.1 获得所有的活动 | ||
| 154 | - List<RewardActivityDO> rewardActivityList = rewardActivityService.getRewardActivityListByStatusAndDateTimeLt( | ||
| 155 | - CommonStatusEnum.ENABLE.getStatus(), now); | 154 | + // TODO @puhui999:有 3 范围,不只 spuId,还有 categoryId,全部,下次 fix |
| 155 | + List<RewardActivityDO> rewardActivityList = rewardActivityService.getRewardActivityBySpuIdsAndStatusAndDateTimeLt( | ||
| 156 | + spuIds, CommonStatusEnum.ENABLE.getStatus(), now); | ||
| 156 | if (CollUtil.isEmpty(rewardActivityList)) { | 157 | if (CollUtil.isEmpty(rewardActivityList)) { |
| 157 | return; | 158 | return; |
| 158 | } | 159 | } |
| 159 | - // 1.2 获得所有的商品信息 | ||
| 160 | - List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(spuIds); | ||
| 161 | - if (CollUtil.isEmpty(spuList)) { | ||
| 162 | - return; | ||
| 163 | - } | ||
| 164 | 160 | ||
| 165 | - // 2. 构建活动 | ||
| 166 | - for (RewardActivityDO rewardActivity : rewardActivityList) { | ||
| 167 | - // 情况一:所有商品都能参加 | ||
| 168 | - if (PromotionProductScopeEnum.isAll(rewardActivity.getProductScope())) { | ||
| 169 | - buildAppActivityRespVO(rewardActivity, spuIds, activityList); | ||
| 170 | - } | ||
| 171 | - // 情况二:指定商品参加 | ||
| 172 | - if (PromotionProductScopeEnum.isSpu(rewardActivity.getProductScope())) { | ||
| 173 | - List<Long> fSpuIds = spuList.stream().map(ProductSpuRespDTO::getId).filter(id -> | ||
| 174 | - rewardActivity.getProductScopeValues().contains(id)).toList(); | ||
| 175 | - buildAppActivityRespVO(rewardActivity, fSpuIds, activityList); | ||
| 176 | - } | ||
| 177 | - // 情况三:指定商品类型参加 | ||
| 178 | - if (PromotionProductScopeEnum.isCategory(rewardActivity.getProductScope())) { | ||
| 179 | - List<Long> fSpuIds = spuList.stream().filter(spuItem -> rewardActivity.getProductScopeValues() | ||
| 180 | - .contains(spuItem.getCategoryId())).map(ProductSpuRespDTO::getId).toList(); | ||
| 181 | - buildAppActivityRespVO(rewardActivity, fSpuIds, activityList); | 161 | + Map<Long, Optional<RewardActivityDO>> spuIdAndActivityMap = spuIds.stream() |
| 162 | + .collect(Collectors.toMap( | ||
| 163 | + spuId -> spuId, | ||
| 164 | + spuId -> rewardActivityList.stream() | ||
| 165 | + .filter(activity -> | ||
| 166 | + ( activity.getProductScopeValues()!=null && | ||
| 167 | + (activity.getProductScopeValues().contains(spuId) || | ||
| 168 | + activity.getProductScopeValues().contains(productSpuApi.getSpu(spuId).getCategoryId()))) || | ||
| 169 | + activity.getProductScope()==1 | ||
| 170 | + ) | ||
| 171 | + .max(Comparator.comparing(RewardActivityDO::getCreateTime)))); | ||
| 172 | + for (Long supId : spuIdAndActivityMap.keySet()) { | ||
| 173 | + if (spuIdAndActivityMap.get(supId).isEmpty()) { | ||
| 174 | + continue; | ||
| 182 | } | 175 | } |
| 176 | + | ||
| 177 | + RewardActivityDO rewardActivityDO = spuIdAndActivityMap.get(supId).get(); | ||
| 178 | + activityList.add(new AppActivityRespVO(rewardActivityDO.getId(), PromotionTypeEnum.REWARD_ACTIVITY.getType(), | ||
| 179 | + rewardActivityDO.getName(), supId, rewardActivityDO.getStartTime(), rewardActivityDO.getEndTime())); | ||
| 183 | } | 180 | } |
| 184 | } | 181 | } |
| 185 | 182 |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/AppCouponController.java
| @@ -60,8 +60,8 @@ public class AppCouponController { | @@ -60,8 +60,8 @@ public class AppCouponController { | ||
| 60 | @Operation(summary = "获得匹配指定商品的优惠劵列表", description = "用于下单页,展示优惠劵列表") | 60 | @Operation(summary = "获得匹配指定商品的优惠劵列表", description = "用于下单页,展示优惠劵列表") |
| 61 | public CommonResult<List<AppCouponMatchRespVO>> getMatchCouponList(AppCouponMatchReqVO matchReqVO) { | 61 | public CommonResult<List<AppCouponMatchRespVO>> getMatchCouponList(AppCouponMatchReqVO matchReqVO) { |
| 62 | // todo: 优化:优惠金额倒序 | 62 | // todo: 优化:优惠金额倒序 |
| 63 | - List<CouponDO> list = couponService.getMatchCouponList(getLoginUserId(), matchReqVO); | ||
| 64 | - return success(BeanUtils.toBean(list, AppCouponMatchRespVO.class)); | 63 | + List<AppCouponMatchRespVO> list = couponService.getMatchCouponList(getLoginUserId(), matchReqVO); |
| 64 | + return success(list); | ||
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | @GetMapping("/page") | 67 | @GetMapping("/page") |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/reward/vo/AppRewardActivityRespVO.java
| @@ -4,6 +4,7 @@ import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivi | @@ -4,6 +4,7 @@ import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivi | ||
| 4 | import io.swagger.v3.oas.annotations.media.Schema; | 4 | import io.swagger.v3.oas.annotations.media.Schema; |
| 5 | import lombok.Data; | 5 | import lombok.Data; |
| 6 | 6 | ||
| 7 | +import java.time.LocalDateTime; | ||
| 7 | import java.util.List; | 8 | import java.util.List; |
| 8 | 9 | ||
| 9 | @Schema(description = "用户 App - 满减送活动 Response VO") | 10 | @Schema(description = "用户 App - 满减送活动 Response VO") |
| @@ -26,9 +27,15 @@ public class AppRewardActivityRespVO { | @@ -26,9 +27,15 @@ public class AppRewardActivityRespVO { | ||
| 26 | private Integer productScope; | 27 | private Integer productScope; |
| 27 | 28 | ||
| 28 | @Schema(description = "商品 SPU 编号的数组", example = "1,2,3") | 29 | @Schema(description = "商品 SPU 编号的数组", example = "1,2,3") |
| 29 | - private List<Long> productSpuIds; | 30 | + private List<Long> productScopeValues; |
| 30 | 31 | ||
| 31 | @Schema(description = "优惠规则的数组") | 32 | @Schema(description = "优惠规则的数组") |
| 32 | private List<RewardActivityBaseVO.Rule> rules; | 33 | private List<RewardActivityBaseVO.Rule> rules; |
| 33 | 34 | ||
| 35 | + @Schema(description = "开始时间") | ||
| 36 | + private LocalDateTime startTime; | ||
| 37 | + | ||
| 38 | + @Schema(description = "结束时间") | ||
| 39 | + private LocalDateTime endTime; | ||
| 40 | + | ||
| 34 | } | 41 | } |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponConvert.java
| @@ -32,6 +32,8 @@ public interface CouponConvert { | @@ -32,6 +32,8 @@ public interface CouponConvert { | ||
| 32 | 32 | ||
| 33 | CouponRespDTO convert(CouponDO bean); | 33 | CouponRespDTO convert(CouponDO bean); |
| 34 | 34 | ||
| 35 | + AppCouponMatchRespVO convert2(CouponDO bean); | ||
| 36 | + | ||
| 35 | default CouponDO convert(CouponTemplateDO template, Long userId) { | 37 | default CouponDO convert(CouponTemplateDO template, Long userId) { |
| 36 | CouponDO couponDO = new CouponDO() | 38 | CouponDO couponDO = new CouponDO() |
| 37 | .setTemplateId(template.getId()) | 39 | .setTemplateId(template.getId()) |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/discount/DiscountActivityConvert.java
| @@ -121,7 +121,10 @@ public interface DiscountActivityConvert { | @@ -121,7 +121,10 @@ public interface DiscountActivityConvert { | ||
| 121 | default boolean isEquals(DiscountProductDO productDO, DiscountProductDO productVO) { | 121 | default boolean isEquals(DiscountProductDO productDO, DiscountProductDO productVO) { |
| 122 | if (ObjectUtil.notEqual(productDO.getSpuId(), productVO.getSpuId()) | 122 | if (ObjectUtil.notEqual(productDO.getSpuId(), productVO.getSpuId()) |
| 123 | || ObjectUtil.notEqual(productDO.getSkuId(), productVO.getSkuId()) | 123 | || ObjectUtil.notEqual(productDO.getSkuId(), productVO.getSkuId()) |
| 124 | - || ObjectUtil.notEqual(productDO.getDiscountType(), productVO.getDiscountType())) { | 124 | + || ObjectUtil.notEqual(productDO.getDiscountType(), productVO.getDiscountType()) |
| 125 | + || ObjectUtil.notEqual(productDO.getActivityEndTime(), productVO.getActivityEndTime()) | ||
| 126 | + || ObjectUtil.notEqual(productDO.getActivityStartTime(), productVO.getActivityStartTime()) | ||
| 127 | + || ObjectUtil.notEqual(productDO.getActivityStatus(), productVO.getActivityStatus())) { | ||
| 125 | return false; | 128 | return false; |
| 126 | } | 129 | } |
| 127 | if (productDO.getDiscountType().equals(PromotionDiscountTypeEnum.PRICE.getType())) { | 130 | if (productDO.getDiscountType().equals(PromotionDiscountTypeEnum.PRICE.getType())) { |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/reward/RewardActivityConvert.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.promotion.convert.reward; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 4 | +import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO; | ||
| 5 | +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityCreateReqVO; | ||
| 6 | +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityRespVO; | ||
| 7 | +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityUpdateReqVO; | ||
| 8 | +import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; | ||
| 9 | +import org.mapstruct.Mapper; | ||
| 10 | +import org.mapstruct.factory.Mappers; | ||
| 11 | + | ||
| 12 | +import java.util.List; | ||
| 13 | + | ||
| 14 | +/** | ||
| 15 | + * 满减送活动 Convert | ||
| 16 | + * | ||
| 17 | + * @author 芋道源码 | ||
| 18 | + */ | ||
| 19 | +@Mapper | ||
| 20 | +public interface RewardActivityConvert { | ||
| 21 | + | ||
| 22 | + RewardActivityConvert INSTANCE = Mappers.getMapper(RewardActivityConvert.class); | ||
| 23 | + | ||
| 24 | + RewardActivityDO convert(RewardActivityCreateReqVO bean); | ||
| 25 | + | ||
| 26 | + RewardActivityDO convert(RewardActivityUpdateReqVO bean); | ||
| 27 | + | ||
| 28 | + RewardActivityRespVO convert(RewardActivityDO bean); | ||
| 29 | + | ||
| 30 | + PageResult<RewardActivityRespVO> convertPage(PageResult<RewardActivityDO> page); | ||
| 31 | + | ||
| 32 | + List<RewardActivityMatchRespDTO> convertList(List<RewardActivityDO> rewardActivityBySpuIdsAndStatusAndDateTimeLt); | ||
| 33 | +} |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponMapper.java
| @@ -85,19 +85,12 @@ public interface CouponMapper extends BaseMapperX<CouponDO> { | @@ -85,19 +85,12 @@ public interface CouponMapper extends BaseMapperX<CouponDO> { | ||
| 85 | } | 85 | } |
| 86 | 86 | ||
| 87 | default List<CouponDO> selectListByUserIdAndStatusAndUsePriceLeAndProductScope( | 87 | default List<CouponDO> selectListByUserIdAndStatusAndUsePriceLeAndProductScope( |
| 88 | - Long userId, Integer status, Integer usePrice, List<Long> spuIds, List<Long> categoryIds) { | ||
| 89 | - Function<List<Long>, String> productScopeValuesFindInSetFunc = ids -> ids.stream() | ||
| 90 | - .map(id -> StrUtil.format("FIND_IN_SET({}, product_scope_values) ", id)) | ||
| 91 | - .collect(Collectors.joining(" OR ")); | ||
| 92 | - return selectList(new LambdaQueryWrapperX<CouponDO>() | 88 | + Long userId, Integer status) { |
| 89 | + List<CouponDO> couponDOS = selectList(new LambdaQueryWrapperX<CouponDO>() | ||
| 93 | .eq(CouponDO::getUserId, userId) | 90 | .eq(CouponDO::getUserId, userId) |
| 94 | .eq(CouponDO::getStatus, status) | 91 | .eq(CouponDO::getStatus, status) |
| 95 | - .le(CouponDO::getUsePrice, usePrice) // 价格小于等于,满足价格使用条件 | ||
| 96 | - .and(w -> w.eq(CouponDO::getProductScope, PromotionProductScopeEnum.ALL.getScope()) // 商品范围一:全部 | ||
| 97 | - .or(ww -> ww.eq(CouponDO::getProductScope, PromotionProductScopeEnum.SPU.getScope()) // 商品范围二:满足指定商品 | ||
| 98 | - .apply(productScopeValuesFindInSetFunc.apply(spuIds))) | ||
| 99 | - .or(ww -> ww.eq(CouponDO::getProductScope, PromotionProductScopeEnum.CATEGORY.getScope()) // 商品范围三:满足指定分类 | ||
| 100 | - .apply(productScopeValuesFindInSetFunc.apply(categoryIds))))); | 92 | + ); |
| 93 | + return couponDOS; | ||
| 101 | } | 94 | } |
| 102 | 95 | ||
| 103 | default List<CouponDO> selectListByStatusAndValidEndTimeLe(Integer status, LocalDateTime validEndTime) { | 96 | default List<CouponDO> selectListByStatusAndValidEndTimeLe(Integer status, LocalDateTime validEndTime) { |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponTemplateMapper.java
| @@ -70,7 +70,7 @@ public interface CouponTemplateMapper extends BaseMapperX<CouponTemplateDO> { | @@ -70,7 +70,7 @@ public interface CouponTemplateMapper extends BaseMapperX<CouponTemplateDO> { | ||
| 70 | .in(CouponTemplateDO::getTakeType, canTakeTypes) // 2. 领取方式一致 | 70 | .in(CouponTemplateDO::getTakeType, canTakeTypes) // 2. 领取方式一致 |
| 71 | .and(ww -> ww.gt(CouponTemplateDO::getValidEndTime, LocalDateTime.now()) // 3.1 未过期 | 71 | .and(ww -> ww.gt(CouponTemplateDO::getValidEndTime, LocalDateTime.now()) // 3.1 未过期 |
| 72 | .or().eq(CouponTemplateDO::getValidityType, CouponTemplateValidityTypeEnum.TERM.getType())) // 3.2 领取之后 | 72 | .or().eq(CouponTemplateDO::getValidityType, CouponTemplateValidityTypeEnum.TERM.getType())) // 3.2 领取之后 |
| 73 | - .apply(" (take_count < total_count OR total_count = -1 )"); // 4. 剩余数量大于 0,或者无限领取 | 73 | + .apply(" (take_count < total_count OR total_count = -1 or total_count is null)"); // 4. 剩余数量大于 0,或者无限领取,或者是指定发放的券 |
| 74 | } | 74 | } |
| 75 | return canTakeConsumer; | 75 | return canTakeConsumer; |
| 76 | } | 76 | } |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/discount/DiscountProductMapper.java
| 1 | package cn.iocoder.yudao.module.promotion.dal.mysql.discount; | 1 | package cn.iocoder.yudao.module.promotion.dal.mysql.discount; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | 3 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| 4 | +import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO; | ||
| 4 | import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; | 5 | import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; |
| 5 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | 6 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
| 6 | import org.apache.ibatis.annotations.Mapper; | 7 | import org.apache.ibatis.annotations.Mapper; |
| @@ -31,7 +32,7 @@ public interface DiscountProductMapper extends BaseMapperX<DiscountProductDO> { | @@ -31,7 +32,7 @@ public interface DiscountProductMapper extends BaseMapperX<DiscountProductDO> { | ||
| 31 | } | 32 | } |
| 32 | 33 | ||
| 33 | // TODO @zhangshuai:逻辑里,尽量避免写 join 语句哈,你可以看看这个查询,有什么办法优化?目前的一个思路,是分 2 次查询,性能也是 ok 的 | 34 | // TODO @zhangshuai:逻辑里,尽量避免写 join 语句哈,你可以看看这个查询,有什么办法优化?目前的一个思路,是分 2 次查询,性能也是 ok 的 |
| 34 | - List<DiscountProductDO> getMatchDiscountProductList(@Param("skuIds") Collection<Long> skuIds); | 35 | + List<DiscountProductRespDTO> getMatchDiscountProductList(@Param("skuIds") Collection<Long> skuIds); |
| 35 | 36 | ||
| 36 | /** | 37 | /** |
| 37 | * 查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号 | 38 | * 查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号 |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/reward/RewardActivityMapper.java
| 1 | package cn.iocoder.yudao.module.promotion.dal.mysql.reward; | 1 | package cn.iocoder.yudao.module.promotion.dal.mysql.reward; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.util.StrUtil; | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | 5 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| 5 | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | 6 | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| 6 | import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO; | 7 | import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO; |
| 7 | import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; | 8 | import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; |
| 9 | +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; | ||
| 10 | +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | ||
| 8 | import org.apache.ibatis.annotations.Mapper; | 11 | import org.apache.ibatis.annotations.Mapper; |
| 9 | 12 | ||
| 10 | import java.time.LocalDateTime; | 13 | import java.time.LocalDateTime; |
| 14 | +import java.util.Collection; | ||
| 11 | import java.util.List; | 15 | import java.util.List; |
| 16 | +import java.util.function.Function; | ||
| 17 | +import java.util.stream.Collectors; | ||
| 12 | 18 | ||
| 13 | /** | 19 | /** |
| 14 | * 满减送活动 Mapper | 20 | * 满减送活动 Mapper |
| @@ -25,13 +31,48 @@ public interface RewardActivityMapper extends BaseMapperX<RewardActivityDO> { | @@ -25,13 +31,48 @@ public interface RewardActivityMapper extends BaseMapperX<RewardActivityDO> { | ||
| 25 | .orderByDesc(RewardActivityDO::getId)); | 31 | .orderByDesc(RewardActivityDO::getId)); |
| 26 | } | 32 | } |
| 27 | 33 | ||
| 34 | + default List<RewardActivityDO> selectListBySpuIdsAndStatus(Collection<Long> spuIds, Integer status) { | ||
| 35 | + Function<Collection<Long>, String> productScopeValuesFindInSetFunc = ids -> ids.stream() | ||
| 36 | + .map(id -> StrUtil.format("FIND_IN_SET({}, product_scope_values) ", id)) | ||
| 37 | + .collect(Collectors.joining(" OR ")); | ||
| 38 | + return selectList(new QueryWrapper<RewardActivityDO>() | ||
| 39 | + .eq("status", status) | ||
| 40 | + .apply(productScopeValuesFindInSetFunc.apply(spuIds))); | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + /** | ||
| 44 | + * 获取指定活动编号的活动列表且 | ||
| 45 | + * 开始时间和结束时间小于给定时间 dateTime 的活动列表 | ||
| 46 | + * | ||
| 47 | + * @param status 状态 | ||
| 48 | + * @param dateTime 指定日期 | ||
| 49 | + * @return 活动列表 | ||
| 50 | + */ | ||
| 28 | default List<RewardActivityDO> selectListByStatusAndDateTimeLt(Integer status, LocalDateTime dateTime) { | 51 | default List<RewardActivityDO> selectListByStatusAndDateTimeLt(Integer status, LocalDateTime dateTime) { |
| 29 | return selectList(new LambdaQueryWrapperX<RewardActivityDO>() | 52 | return selectList(new LambdaQueryWrapperX<RewardActivityDO>() |
| 30 | .eq(RewardActivityDO::getStatus, status) | 53 | .eq(RewardActivityDO::getStatus, status) |
| 31 | - // 开始时间 < 指定时间(dateTime) < 结束时间,也就是说获取指定时间段的活动 | ||
| 32 | - .lt(RewardActivityDO::getStartTime, dateTime).gt(RewardActivityDO::getEndTime, dateTime) | 54 | + .lt(RewardActivityDO::getStartTime, dateTime) |
| 55 | + .gt(RewardActivityDO::getEndTime, dateTime)// 开始时间 < 指定时间 < 结束时间,也就是说获取指定时间段的活动 | ||
| 33 | .orderByAsc(RewardActivityDO::getStartTime) | 56 | .orderByAsc(RewardActivityDO::getStartTime) |
| 34 | ); | 57 | ); |
| 35 | } | 58 | } |
| 36 | 59 | ||
| 60 | + default List<RewardActivityDO> getRewardActivityByStatusAndDateTimeLt(Collection<Long> spuIds,Collection<Long> categoryIds, Integer status, LocalDateTime dateTime) { | ||
| 61 | + //拼接通用券查询语句 | ||
| 62 | + Function<Collection<Long>, String> productScopeValuesFindInSetFunc = ids -> ids.stream() | ||
| 63 | + .map(id -> StrUtil.format("FIND_IN_SET({}, product_scope_values) ", id)) | ||
| 64 | + .collect(Collectors.joining(" OR ")); | ||
| 65 | + return selectList(new LambdaQueryWrapperX<RewardActivityDO>() | ||
| 66 | + .eq(RewardActivityDO::getStatus,status) | ||
| 67 | + .lt(RewardActivityDO::getStartTime, dateTime) | ||
| 68 | + .gt(RewardActivityDO::getEndTime, dateTime) | ||
| 69 | + .and(i -> i.eq(RewardActivityDO::getProductScope, PromotionProductScopeEnum.SPU.getScope()) | ||
| 70 | + .and(i1 -> i1.apply(productScopeValuesFindInSetFunc.apply(spuIds))) | ||
| 71 | + .or(i1 -> i1.eq(RewardActivityDO::getProductScope, PromotionProductScopeEnum.ALL.getScope())) | ||
| 72 | + .or(i1 -> i1.eq(RewardActivityDO::getProductScope, PromotionProductScopeEnum.CATEGORY.getScope()) | ||
| 73 | + .and(i2 -> i2.apply(productScopeValuesFindInSetFunc.apply(categoryIds))))) | ||
| 74 | + .orderByDesc(RewardActivityDO::getId) | ||
| 75 | + ); | ||
| 76 | + } | ||
| 77 | + | ||
| 37 | } | 78 | } |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillActivityMapper.java
| @@ -51,7 +51,7 @@ public interface SeckillActivityMapper extends BaseMapperX<SeckillActivityDO> { | @@ -51,7 +51,7 @@ public interface SeckillActivityMapper extends BaseMapperX<SeckillActivityDO> { | ||
| 51 | Assert.isTrue(count > 0); | 51 | Assert.isTrue(count > 0); |
| 52 | return update(null, new LambdaUpdateWrapper<SeckillActivityDO>() | 52 | return update(null, new LambdaUpdateWrapper<SeckillActivityDO>() |
| 53 | .eq(SeckillActivityDO::getId, id) | 53 | .eq(SeckillActivityDO::getId, id) |
| 54 | - .gt(SeckillActivityDO::getStock, count) | 54 | + .ge(SeckillActivityDO::getStock, count) |
| 55 | .setSql("stock = stock - " + count)); | 55 | .setSql("stock = stock - " + count)); |
| 56 | } | 56 | } |
| 57 | 57 | ||
| @@ -69,9 +69,11 @@ public interface SeckillActivityMapper extends BaseMapperX<SeckillActivityDO> { | @@ -69,9 +69,11 @@ public interface SeckillActivityMapper extends BaseMapperX<SeckillActivityDO> { | ||
| 69 | .setSql("stock = stock + " + count)); | 69 | .setSql("stock = stock + " + count)); |
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | - default PageResult<SeckillActivityDO> selectPage(AppSeckillActivityPageReqVO pageReqVO, Integer status) { | 72 | + default PageResult<SeckillActivityDO> selectPage(AppSeckillActivityPageReqVO pageReqVO, Integer status, LocalDateTime dateTime) { |
| 73 | return selectPage(pageReqVO, new LambdaQueryWrapperX<SeckillActivityDO>() | 73 | return selectPage(pageReqVO, new LambdaQueryWrapperX<SeckillActivityDO>() |
| 74 | .eqIfPresent(SeckillActivityDO::getStatus, status) | 74 | .eqIfPresent(SeckillActivityDO::getStatus, status) |
| 75 | + .lt(SeckillActivityDO::getStartTime, dateTime) | ||
| 76 | + .gt(SeckillActivityDO::getEndTime, dateTime)// 开始时间 < 指定时间 < 结束时间,也就是说获取指定时间段的活动 | ||
| 75 | .apply(ObjectUtil.isNotNull(pageReqVO.getConfigId()), "FIND_IN_SET(" + pageReqVO.getConfigId() + ",config_ids) > 0")); | 77 | .apply(ObjectUtil.isNotNull(pageReqVO.getConfigId()), "FIND_IN_SET(" + pageReqVO.getConfigId() + ",config_ids) > 0")); |
| 76 | } | 78 | } |
| 77 | 79 |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillconfig/SeckillConfigMapper.java
| 1 | package cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillconfig; | 1 | package cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillconfig; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | 5 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| 5 | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | 6 | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| 6 | import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigPageReqVO; | 7 | import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigPageReqVO; |
| 7 | import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillConfigDO; | 8 | import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillConfigDO; |
| 9 | +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | ||
| 8 | import org.apache.ibatis.annotations.Mapper; | 10 | import org.apache.ibatis.annotations.Mapper; |
| 9 | 11 | ||
| 12 | +import java.time.LocalDateTime; | ||
| 13 | +import java.time.format.DateTimeFormatter; | ||
| 10 | import java.util.List; | 14 | import java.util.List; |
| 11 | 15 | ||
| 12 | @Mapper | 16 | @Mapper |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponService.java
| @@ -5,6 +5,7 @@ import cn.hutool.core.map.MapUtil; | @@ -5,6 +5,7 @@ import cn.hutool.core.map.MapUtil; | ||
| 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponPageReqVO; | 6 | import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponPageReqVO; |
| 7 | import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon.AppCouponMatchReqVO; | 7 | import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon.AppCouponMatchReqVO; |
| 8 | +import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon.AppCouponMatchRespVO; | ||
| 8 | import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; | 9 | import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; |
| 9 | import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; | 10 | import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; |
| 10 | import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum; | 11 | import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum; |
| @@ -178,7 +179,7 @@ public interface CouponService { | @@ -178,7 +179,7 @@ public interface CouponService { | ||
| 178 | * @param matchReqVO 匹配参数 | 179 | * @param matchReqVO 匹配参数 |
| 179 | * @return 优惠券列表 | 180 | * @return 优惠券列表 |
| 180 | */ | 181 | */ |
| 181 | - List<CouponDO> getMatchCouponList(Long userId, AppCouponMatchReqVO matchReqVO); | 182 | + List<AppCouponMatchRespVO> getMatchCouponList(Long userId, AppCouponMatchReqVO matchReqVO); |
| 182 | 183 | ||
| 183 | /** | 184 | /** |
| 184 | * 获取用户是否可以领取优惠券 | 185 | * 获取用户是否可以领取优惠券 |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java
| @@ -13,10 +13,12 @@ import cn.iocoder.yudao.module.member.api.user.MemberUserApi; | @@ -13,10 +13,12 @@ import cn.iocoder.yudao.module.member.api.user.MemberUserApi; | ||
| 13 | import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; | 13 | import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; |
| 14 | import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponPageReqVO; | 14 | import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponPageReqVO; |
| 15 | import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon.AppCouponMatchReqVO; | 15 | import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon.AppCouponMatchReqVO; |
| 16 | +import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon.AppCouponMatchRespVO; | ||
| 16 | import cn.iocoder.yudao.module.promotion.convert.coupon.CouponConvert; | 17 | import cn.iocoder.yudao.module.promotion.convert.coupon.CouponConvert; |
| 17 | import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; | 18 | import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; |
| 18 | import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; | 19 | import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; |
| 19 | import cn.iocoder.yudao.module.promotion.dal.mysql.coupon.CouponMapper; | 20 | import cn.iocoder.yudao.module.promotion.dal.mysql.coupon.CouponMapper; |
| 21 | +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; | ||
| 20 | import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum; | 22 | import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum; |
| 21 | import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum; | 23 | import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum; |
| 22 | import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTemplateValidityTypeEnum; | 24 | import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTemplateValidityTypeEnum; |
| @@ -286,6 +288,7 @@ public class CouponServiceImpl implements CouponService { | @@ -286,6 +288,7 @@ public class CouponServiceImpl implements CouponService { | ||
| 286 | } | 288 | } |
| 287 | // 校验剩余数量(仅在 CouponTakeTypeEnum.USER 用户领取时) | 289 | // 校验剩余数量(仅在 CouponTakeTypeEnum.USER 用户领取时) |
| 288 | if (CouponTakeTypeEnum.isUser(couponTemplate.getTakeCount()) | 290 | if (CouponTakeTypeEnum.isUser(couponTemplate.getTakeCount()) |
| 291 | + && couponTemplate.getTotalCount() != null | ||
| 289 | && couponTemplate.getTakeCount() + userIds.size() > couponTemplate.getTotalCount()) { | 292 | && couponTemplate.getTakeCount() + userIds.size() > couponTemplate.getTotalCount()) { |
| 290 | throw exception(COUPON_TEMPLATE_NOT_ENOUGH); | 293 | throw exception(COUPON_TEMPLATE_NOT_ENOUGH); |
| 291 | } | 294 | } |
| @@ -308,7 +311,7 @@ public class CouponServiceImpl implements CouponService { | @@ -308,7 +311,7 @@ public class CouponServiceImpl implements CouponService { | ||
| 308 | * @param couponTemplate 优惠劵模版 | 311 | * @param couponTemplate 优惠劵模版 |
| 309 | */ | 312 | */ |
| 310 | private void removeTakeLimitUser(Set<Long> userIds, CouponTemplateDO couponTemplate) { | 313 | private void removeTakeLimitUser(Set<Long> userIds, CouponTemplateDO couponTemplate) { |
| 311 | - if (couponTemplate.getTakeLimitCount() <= 0) { | 314 | + if (couponTemplate.getTakeLimitCount() == null || couponTemplate.getTakeLimitCount() <= 0) { |
| 312 | return; | 315 | return; |
| 313 | } | 316 | } |
| 314 | // 查询已领过券的用户 | 317 | // 查询已领过券的用户 |
| @@ -356,13 +359,45 @@ public class CouponServiceImpl implements CouponService { | @@ -356,13 +359,45 @@ public class CouponServiceImpl implements CouponService { | ||
| 356 | } | 359 | } |
| 357 | 360 | ||
| 358 | @Override | 361 | @Override |
| 359 | - public List<CouponDO> getMatchCouponList(Long userId, AppCouponMatchReqVO matchReqVO) { | 362 | + public List<AppCouponMatchRespVO> getMatchCouponList(Long userId, AppCouponMatchReqVO matchReqVO) { |
| 363 | + List<AppCouponMatchRespVO> couponMatchist = new ArrayList<>(); | ||
| 360 | List<CouponDO> list = couponMapper.selectListByUserIdAndStatusAndUsePriceLeAndProductScope(userId, | 364 | List<CouponDO> list = couponMapper.selectListByUserIdAndStatusAndUsePriceLeAndProductScope(userId, |
| 361 | - CouponStatusEnum.UNUSED.getStatus(), | ||
| 362 | - matchReqVO.getPrice(), matchReqVO.getSpuIds(), matchReqVO.getCategoryIds()); | ||
| 363 | - // 兜底逻辑:如果 CouponExpireJob 未执行,status 未变成 EXPIRE ,但是 validEndTime 已经过期了,需要进行过滤 | ||
| 364 | - list.removeIf(coupon -> !LocalDateTimeUtils.isBetween(coupon.getValidStartTime(), coupon.getValidEndTime())); | ||
| 365 | - return list; | 365 | + CouponStatusEnum.UNUSED.getStatus()); |
| 366 | + for (CouponDO couponDO : list) { | ||
| 367 | + AppCouponMatchRespVO appCouponMatchRespVO = CouponConvert.INSTANCE.convert2(couponDO); | ||
| 368 | + Integer productScope = appCouponMatchRespVO.getProductScope(); | ||
| 369 | + List<Long> productScopeValues = appCouponMatchRespVO.getProductScopeValues(); | ||
| 370 | + Integer usePrice = appCouponMatchRespVO.getUsePrice(); | ||
| 371 | + if(matchReqVO.getPrice() < usePrice){ | ||
| 372 | + // 价格小于等于,满足价格使用条件 | ||
| 373 | + appCouponMatchRespVO.setMatch(false); | ||
| 374 | + appCouponMatchRespVO.setDescription("未达到使用门槛"); | ||
| 375 | + }else if(!LocalDateTimeUtils.isBetween(appCouponMatchRespVO.getValidStartTime(), appCouponMatchRespVO.getValidEndTime())) { | ||
| 376 | + //判断时间 | ||
| 377 | + appCouponMatchRespVO.setMatch(false); | ||
| 378 | + appCouponMatchRespVO.setDescription("使用时间未到"); | ||
| 379 | + }else if (PromotionProductScopeEnum.ALL.getScope().equals(productScope)){ | ||
| 380 | + appCouponMatchRespVO.setMatch(true); | ||
| 381 | + }else if (PromotionProductScopeEnum.SPU.getScope().equals(productScope)){ | ||
| 382 | + boolean spu = new HashSet<>(productScopeValues).containsAll(matchReqVO.getSpuIds()); | ||
| 383 | + if(spu){ | ||
| 384 | + appCouponMatchRespVO.setMatch(true); | ||
| 385 | + }else { | ||
| 386 | + appCouponMatchRespVO.setMatch(false); | ||
| 387 | + appCouponMatchRespVO.setDescription("与商品不匹配"); | ||
| 388 | + } | ||
| 389 | + }else if (PromotionProductScopeEnum.CATEGORY.getScope().equals(productScope)){ | ||
| 390 | + boolean category = new HashSet<>(productScopeValues).containsAll(matchReqVO.getCategoryIds()); | ||
| 391 | + if(category){ | ||
| 392 | + appCouponMatchRespVO.setMatch(true); | ||
| 393 | + }else { | ||
| 394 | + appCouponMatchRespVO.setMatch(false); | ||
| 395 | + appCouponMatchRespVO.setDescription("与商品类型不匹配"); | ||
| 396 | + } | ||
| 397 | + } | ||
| 398 | + couponMatchist.add(appCouponMatchRespVO); | ||
| 399 | + } | ||
| 400 | + return couponMatchist; | ||
| 366 | } | 401 | } |
| 367 | 402 | ||
| 368 | @Override | 403 | @Override |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java
| @@ -13,6 +13,7 @@ import cn.iocoder.yudao.module.promotion.dal.mysql.coupon.CouponTemplateMapper; | @@ -13,6 +13,7 @@ import cn.iocoder.yudao.module.promotion.dal.mysql.coupon.CouponTemplateMapper; | ||
| 13 | import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; | 13 | import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; |
| 14 | import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum; | 14 | import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum; |
| 15 | import org.springframework.stereotype.Service; | 15 | import org.springframework.stereotype.Service; |
| 16 | +import jakarta.validation.Validator; | ||
| 16 | import org.springframework.validation.annotation.Validated; | 17 | import org.springframework.validation.annotation.Validated; |
| 17 | 18 | ||
| 18 | import jakarta.annotation.Resource; | 19 | import jakarta.annotation.Resource; |
| @@ -40,9 +41,13 @@ public class CouponTemplateServiceImpl implements CouponTemplateService { | @@ -40,9 +41,13 @@ public class CouponTemplateServiceImpl implements CouponTemplateService { | ||
| 40 | private ProductCategoryApi productCategoryApi; | 41 | private ProductCategoryApi productCategoryApi; |
| 41 | @Resource | 42 | @Resource |
| 42 | private ProductSpuApi productSpuApi; | 43 | private ProductSpuApi productSpuApi; |
| 44 | + @Resource | ||
| 45 | + private Validator validator; | ||
| 43 | 46 | ||
| 44 | @Override | 47 | @Override |
| 45 | public Long createCouponTemplate(CouponTemplateCreateReqVO createReqVO) { | 48 | public Long createCouponTemplate(CouponTemplateCreateReqVO createReqVO) { |
| 49 | + // 校验参数 | ||
| 50 | + createReqVO.validate(validator); | ||
| 46 | // 校验商品范围 | 51 | // 校验商品范围 |
| 47 | validateProductScope(createReqVO.getProductScope(), createReqVO.getProductScopeValues()); | 52 | validateProductScope(createReqVO.getProductScope(), createReqVO.getProductScopeValues()); |
| 48 | // 插入 | 53 | // 插入 |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityService.java
| 1 | package cn.iocoder.yudao.module.promotion.service.discount; | 1 | package cn.iocoder.yudao.module.promotion.service.discount; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | +import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO; | ||
| 4 | import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityCreateReqVO; | 5 | import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityCreateReqVO; |
| 5 | import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityPageReqVO; | 6 | import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityPageReqVO; |
| 6 | import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityUpdateReqVO; | 7 | import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityUpdateReqVO; |
| @@ -27,7 +28,7 @@ public interface DiscountActivityService { | @@ -27,7 +28,7 @@ public interface DiscountActivityService { | ||
| 27 | * @param skuIds SKU 编号数组 | 28 | * @param skuIds SKU 编号数组 |
| 28 | * @return 匹配的限时折扣商品 | 29 | * @return 匹配的限时折扣商品 |
| 29 | */ | 30 | */ |
| 30 | - List<DiscountProductDO> getMatchDiscountProductList(Collection<Long> skuIds); | 31 | + List<DiscountProductRespDTO> getMatchDiscountProductList(Collection<Long> skuIds); |
| 31 | 32 | ||
| 32 | /** | 33 | /** |
| 33 | * 创建限时折扣活动 | 34 | * 创建限时折扣活动 |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityServiceImpl.java
| @@ -6,6 +6,7 @@ import cn.hutool.core.map.MapUtil; | @@ -6,6 +6,7 @@ import cn.hutool.core.map.MapUtil; | ||
| 6 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | 6 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 7 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 7 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 8 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | 8 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 9 | +import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO; | ||
| 9 | import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityBaseVO; | 10 | import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityBaseVO; |
| 10 | import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityCreateReqVO; | 11 | import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityCreateReqVO; |
| 11 | import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityPageReqVO; | 12 | import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityPageReqVO; |
| @@ -49,7 +50,7 @@ public class DiscountActivityServiceImpl implements DiscountActivityService { | @@ -49,7 +50,7 @@ public class DiscountActivityServiceImpl implements DiscountActivityService { | ||
| 49 | private DiscountProductMapper discountProductMapper; | 50 | private DiscountProductMapper discountProductMapper; |
| 50 | 51 | ||
| 51 | @Override | 52 | @Override |
| 52 | - public List<DiscountProductDO> getMatchDiscountProductList(Collection<Long> skuIds) { | 53 | + public List<DiscountProductRespDTO> getMatchDiscountProductList(Collection<Long> skuIds) { |
| 53 | return discountProductMapper.getMatchDiscountProductList(skuIds); | 54 | return discountProductMapper.getMatchDiscountProductList(skuIds); |
| 54 | } | 55 | } |
| 55 | 56 | ||
| @@ -130,7 +131,7 @@ public class DiscountActivityServiceImpl implements DiscountActivityService { | @@ -130,7 +131,7 @@ public class DiscountActivityServiceImpl implements DiscountActivityService { | ||
| 130 | List<DiscountProductDO> list = discountProductMapper.selectListByActivityId(id); | 131 | List<DiscountProductDO> list = discountProductMapper.selectListByActivityId(id); |
| 131 | // TODO @zhangshuai:一般简单的 stream 方法,建议是使用 CollectionUtils,例如说这里是 convertList 对把。 | 132 | // TODO @zhangshuai:一般简单的 stream 方法,建议是使用 CollectionUtils,例如说这里是 convertList 对把。 |
| 132 | List<Long> skuIds = list.stream().map(item -> item.getSkuId()).collect(Collectors.toList()); | 133 | List<Long> skuIds = list.stream().map(item -> item.getSkuId()).collect(Collectors.toList()); |
| 133 | - List<DiscountProductDO> matchDiscountProductList = getMatchDiscountProductList(skuIds); | 134 | + List<DiscountProductRespDTO> matchDiscountProductList = getMatchDiscountProductList(skuIds); |
| 134 | if (id != null) { // 排除自己这个活动 | 135 | if (id != null) { // 排除自己这个活动 |
| 135 | matchDiscountProductList.removeIf(product -> id.equals(product.getActivityId())); | 136 | matchDiscountProductList.removeIf(product -> id.equals(product.getActivityId())); |
| 136 | } | 137 | } |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityService.java
| @@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; | @@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; | ||
| 8 | import jakarta.validation.Valid; | 8 | import jakarta.validation.Valid; |
| 9 | 9 | ||
| 10 | import java.time.LocalDateTime; | 10 | import java.time.LocalDateTime; |
| 11 | +import java.util.Collection; | ||
| 11 | import java.util.List; | 12 | import java.util.List; |
| 12 | 13 | ||
| 13 | /** | 14 | /** |
| @@ -71,4 +72,14 @@ public interface RewardActivityService { | @@ -71,4 +72,14 @@ public interface RewardActivityService { | ||
| 71 | */ | 72 | */ |
| 72 | List<RewardActivityDO> getRewardActivityListByStatusAndDateTimeLt(Integer status, LocalDateTime dateTime); | 73 | List<RewardActivityDO> getRewardActivityListByStatusAndDateTimeLt(Integer status, LocalDateTime dateTime); |
| 73 | 74 | ||
| 75 | + /** | ||
| 76 | + * 获取指定 spu 编号最近参加的活动,每个 spuId 只返回一条记录 | ||
| 77 | + * | ||
| 78 | + * @param spuIds SPU 编号数组 | ||
| 79 | + * @param status 状态 | ||
| 80 | + * @param dateTime 当前日期时间 | ||
| 81 | + * @return 满减送活动列表 | ||
| 82 | + */ | ||
| 83 | + List<RewardActivityDO> getRewardActivityBySpuIdsAndStatusAndDateTimeLt(Collection<Long> spuIds, Integer status, LocalDateTime dateTime); | ||
| 84 | + | ||
| 74 | } | 85 | } |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityServiceImpl.java
| 1 | package cn.iocoder.yudao.module.promotion.service.reward; | 1 | package cn.iocoder.yudao.module.promotion.service.reward; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.collection.CollUtil; | ||
| 3 | import cn.hutool.core.date.LocalDateTimeUtil; | 4 | import cn.hutool.core.date.LocalDateTimeUtil; |
| 4 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | 5 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 6 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| @@ -11,8 +12,10 @@ import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivi | @@ -11,8 +12,10 @@ import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivi | ||
| 11 | import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityCreateReqVO; | 12 | import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityCreateReqVO; |
| 12 | import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO; | 13 | import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO; |
| 13 | import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityUpdateReqVO; | 14 | import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityUpdateReqVO; |
| 15 | +import cn.iocoder.yudao.module.promotion.convert.reward.RewardActivityConvert; | ||
| 14 | import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; | 16 | import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; |
| 15 | import cn.iocoder.yudao.module.promotion.dal.mysql.reward.RewardActivityMapper; | 17 | import cn.iocoder.yudao.module.promotion.dal.mysql.reward.RewardActivityMapper; |
| 18 | +import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum; | ||
| 16 | import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; | 19 | import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; |
| 17 | import cn.iocoder.yudao.module.promotion.util.PromotionUtils; | 20 | import cn.iocoder.yudao.module.promotion.util.PromotionUtils; |
| 18 | import jakarta.annotation.Resource; | 21 | import jakarta.annotation.Resource; |
| @@ -20,8 +23,11 @@ import org.springframework.stereotype.Service; | @@ -20,8 +23,11 @@ import org.springframework.stereotype.Service; | ||
| 20 | import org.springframework.validation.annotation.Validated; | 23 | import org.springframework.validation.annotation.Validated; |
| 21 | 24 | ||
| 22 | import java.time.LocalDateTime; | 25 | import java.time.LocalDateTime; |
| 26 | +import java.util.Collection; | ||
| 27 | +import java.util.Collections; | ||
| 23 | import java.util.List; | 28 | import java.util.List; |
| 24 | import java.util.Objects; | 29 | import java.util.Objects; |
| 30 | +import java.util.stream.Collectors; | ||
| 25 | 31 | ||
| 26 | import static cn.hutool.core.collection.CollUtil.intersectionDistinct; | 32 | import static cn.hutool.core.collection.CollUtil.intersectionDistinct; |
| 27 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 33 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| @@ -52,9 +58,13 @@ public class RewardActivityServiceImpl implements RewardActivityService { | @@ -52,9 +58,13 @@ public class RewardActivityServiceImpl implements RewardActivityService { | ||
| 52 | // 1.2 校验商品是否冲突 | 58 | // 1.2 校验商品是否冲突 |
| 53 | validateRewardActivitySpuConflicts(null, createReqVO); | 59 | validateRewardActivitySpuConflicts(null, createReqVO); |
| 54 | 60 | ||
| 55 | - // 2. 插入 | ||
| 56 | - RewardActivityDO rewardActivity = BeanUtils.toBean(createReqVO, RewardActivityDO.class) | ||
| 57 | - .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getEndTime())); | 61 | + // 插入 |
| 62 | + RewardActivityDO rewardActivity = RewardActivityConvert.INSTANCE.convert(createReqVO) | ||
| 63 | + .setStatus( | ||
| 64 | + PromotionUtils.calculateActivityStatus(createReqVO.getEndTime()).equals(CommonStatusEnum.DISABLE.getStatus())? | ||
| 65 | + PromotionActivityStatusEnum.WAIT.getStatus(): | ||
| 66 | + PromotionActivityStatusEnum.RUN.getStatus() | ||
| 67 | + ); | ||
| 58 | rewardActivityMapper.insert(rewardActivity); | 68 | rewardActivityMapper.insert(rewardActivity); |
| 59 | // 返回 | 69 | // 返回 |
| 60 | return rewardActivity.getId(); | 70 | return rewardActivity.getId(); |
| @@ -199,4 +209,19 @@ public class RewardActivityServiceImpl implements RewardActivityService { | @@ -199,4 +209,19 @@ public class RewardActivityServiceImpl implements RewardActivityService { | ||
| 199 | return rewardActivityMapper.selectListByStatusAndDateTimeLt(status, dateTime); | 209 | return rewardActivityMapper.selectListByStatusAndDateTimeLt(status, dateTime); |
| 200 | } | 210 | } |
| 201 | 211 | ||
| 212 | + @Override | ||
| 213 | + public List<RewardActivityDO> getRewardActivityBySpuIdsAndStatusAndDateTimeLt(Collection<Long> spuIds, Integer status, LocalDateTime dateTime) { | ||
| 214 | + List<ProductSpuRespDTO> spuList = productSpuApi.validateSpuList(spuIds); | ||
| 215 | + //查询出商品的分类ids | ||
| 216 | + List<Long> categoryIds = spuList.stream().map(ProductSpuRespDTO::getCategoryId).collect(Collectors.toList()); | ||
| 217 | + // 1. 查询出指定 spuId 的 spu 参加的活动 | ||
| 218 | + List<RewardActivityDO> rewardActivityList = rewardActivityMapper.getRewardActivityByStatusAndDateTimeLt(spuIds, categoryIds,status,dateTime); | ||
| 219 | + if (CollUtil.isEmpty(rewardActivityList)) { | ||
| 220 | + return Collections.emptyList(); | ||
| 221 | + } | ||
| 222 | + | ||
| 223 | + // 2. 查询活动详情 | ||
| 224 | + return rewardActivityList; | ||
| 225 | + } | ||
| 226 | + | ||
| 202 | } | 227 | } |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityService.java
| @@ -110,7 +110,7 @@ public interface SeckillActivityService { | @@ -110,7 +110,7 @@ public interface SeckillActivityService { | ||
| 110 | List<SeckillActivityDO> getSeckillActivityListByConfigIdAndStatus(Long configId, Integer status); | 110 | List<SeckillActivityDO> getSeckillActivityListByConfigIdAndStatus(Long configId, Integer status); |
| 111 | 111 | ||
| 112 | /** | 112 | /** |
| 113 | - * 通过活动时段获取秒杀活动 | 113 | + * 通过活动时段获取开始的秒杀活动 |
| 114 | * | 114 | * |
| 115 | * @param pageReqVO 请求 | 115 | * @param pageReqVO 请求 |
| 116 | * @return 秒杀活动列表 | 116 | * @return 秒杀活动列表 |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java
| @@ -23,6 +23,7 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillConfigDO; | @@ -23,6 +23,7 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillConfigDO; | ||
| 23 | import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO; | 23 | import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO; |
| 24 | import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity.SeckillActivityMapper; | 24 | import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity.SeckillActivityMapper; |
| 25 | import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity.SeckillProductMapper; | 25 | import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity.SeckillProductMapper; |
| 26 | +import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillconfig.SeckillConfigMapper; | ||
| 26 | import org.springframework.stereotype.Service; | 27 | import org.springframework.stereotype.Service; |
| 27 | import org.springframework.transaction.annotation.Transactional; | 28 | import org.springframework.transaction.annotation.Transactional; |
| 28 | import org.springframework.validation.annotation.Validated; | 29 | import org.springframework.validation.annotation.Validated; |
| @@ -57,6 +58,8 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { | @@ -57,6 +58,8 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { | ||
| 57 | @Resource | 58 | @Resource |
| 58 | private SeckillProductMapper seckillProductMapper; | 59 | private SeckillProductMapper seckillProductMapper; |
| 59 | @Resource | 60 | @Resource |
| 61 | + private SeckillConfigMapper seckillConfigMapper; | ||
| 62 | + @Resource | ||
| 60 | private SeckillConfigService seckillConfigService; | 63 | private SeckillConfigService seckillConfigService; |
| 61 | @Resource | 64 | @Resource |
| 62 | private ProductSpuApi productSpuApi; | 65 | private ProductSpuApi productSpuApi; |
| @@ -289,7 +292,7 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { | @@ -289,7 +292,7 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { | ||
| 289 | 292 | ||
| 290 | @Override | 293 | @Override |
| 291 | public PageResult<SeckillActivityDO> getSeckillActivityAppPageByConfigId(AppSeckillActivityPageReqVO pageReqVO) { | 294 | public PageResult<SeckillActivityDO> getSeckillActivityAppPageByConfigId(AppSeckillActivityPageReqVO pageReqVO) { |
| 292 | - return seckillActivityMapper.selectPage(pageReqVO, CommonStatusEnum.ENABLE.getStatus()); | 295 | + return seckillActivityMapper.selectPage(pageReqVO, CommonStatusEnum.ENABLE.getStatus(),LocalDateTime.now()); |
| 293 | } | 296 | } |
| 294 | 297 | ||
| 295 | @Override | 298 | @Override |
yudao-module-mall/yudao-module-promotion-biz/src/main/resources/mapper/discount/DiscountProductMapper.xml
| @@ -3,8 +3,8 @@ | @@ -3,8 +3,8 @@ | ||
| 3 | <mapper namespace="cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountProductMapper"> | 3 | <mapper namespace="cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountProductMapper"> |
| 4 | 4 | ||
| 5 | 5 | ||
| 6 | - <select id="getMatchDiscountProductList" resultType="cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO"> | ||
| 7 | - SELECT pdp.* | 6 | + <select id="getMatchDiscountProductList" resultType="cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO"> |
| 7 | + SELECT pdp.*,pda.name as activity_name | ||
| 8 | FROM promotion_discount_product pdp | 8 | FROM promotion_discount_product pdp |
| 9 | LEFT JOIN promotion_discount_activity pda | 9 | LEFT JOIN promotion_discount_activity pda |
| 10 | ON pdp.activity_id = pda.id | 10 | ON pdp.activity_id = pda.id |
| @@ -16,9 +16,11 @@ | @@ -16,9 +16,11 @@ | ||
| 16 | </foreach> | 16 | </foreach> |
| 17 | </if> | 17 | </if> |
| 18 | AND pda.start_time <= CURRENT_TIME AND pda.end_time >= CURRENT_TIME | 18 | AND pda.start_time <= CURRENT_TIME AND pda.end_time >= CURRENT_TIME |
| 19 | - AND pda.`status` = 20 | ||
| 20 | - AND pda.deleted != 1 | 19 | + AND pda.`status` = 0 |
| 20 | + AND pda.deleted =0 | ||
| 21 | + AND pdp.deleted = 0 | ||
| 21 | </where> | 22 | </where> |
| 23 | + ORDER BY pdp.id DESC | ||
| 22 | </select> | 24 | </select> |
| 23 | 25 | ||
| 24 | </mapper> | 26 | </mapper> |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java
| 1 | package cn.iocoder.yudao.module.trade.controller.app.order; | 1 | package cn.iocoder.yudao.module.trade.controller.app.order; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 4 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; | 6 | import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; |
| 7 | +import cn.iocoder.yudao.module.member.api.level.MemberLevelApi; | ||
| 8 | +import cn.iocoder.yudao.module.member.api.level.dto.MemberLevelRespDTO; | ||
| 9 | +import cn.iocoder.yudao.module.member.api.user.MemberUserApi; | ||
| 10 | +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; | ||
| 6 | import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO; | 11 | import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO; |
| 12 | +import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; | ||
| 13 | +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; | ||
| 14 | +import cn.iocoder.yudao.module.promotion.api.discount.DiscountActivityApi; | ||
| 15 | +import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO; | ||
| 16 | +import cn.iocoder.yudao.module.promotion.api.reward.RewardActivityApi; | ||
| 17 | +import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO; | ||
| 18 | +import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum; | ||
| 19 | +import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; | ||
| 20 | +import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; | ||
| 7 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.*; | 21 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.*; |
| 8 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemCommentCreateReqVO; | 22 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemCommentCreateReqVO; |
| 9 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemRespVO; | 23 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemRespVO; |
| @@ -27,12 +41,14 @@ import lombok.extern.slf4j.Slf4j; | @@ -27,12 +41,14 @@ import lombok.extern.slf4j.Slf4j; | ||
| 27 | import org.springframework.validation.annotation.Validated; | 41 | import org.springframework.validation.annotation.Validated; |
| 28 | import org.springframework.web.bind.annotation.*; | 42 | import org.springframework.web.bind.annotation.*; |
| 29 | 43 | ||
| 30 | -import java.util.List; | ||
| 31 | -import java.util.Map; | 44 | +import java.time.LocalDateTime; |
| 45 | +import java.util.*; | ||
| 32 | 46 | ||
| 47 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||
| 33 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 48 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 34 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | 49 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; |
| 35 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | 50 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; |
| 51 | +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.DISCOUNT_ACTIVITY_TYPE_NOT_EXISTS; | ||
| 36 | 52 | ||
| 37 | @Tag(name = "用户 App - 交易订单") | 53 | @Tag(name = "用户 App - 交易订单") |
| 38 | @RestController | 54 | @RestController |
| @@ -54,6 +70,17 @@ public class AppTradeOrderController { | @@ -54,6 +70,17 @@ public class AppTradeOrderController { | ||
| 54 | @Resource | 70 | @Resource |
| 55 | private TradeOrderProperties tradeOrderProperties; | 71 | private TradeOrderProperties tradeOrderProperties; |
| 56 | 72 | ||
| 73 | + @Resource | ||
| 74 | + private MemberLevelApi memberLevelApi; | ||
| 75 | + @Resource | ||
| 76 | + private MemberUserApi memberUserApi; | ||
| 77 | + @Resource | ||
| 78 | + private DiscountActivityApi discountActivityApi; | ||
| 79 | + @Resource | ||
| 80 | + private RewardActivityApi rewardActivityApi; | ||
| 81 | + @Resource | ||
| 82 | + private ProductSkuApi productKpuApi; | ||
| 83 | + | ||
| 57 | @GetMapping("/settlement") | 84 | @GetMapping("/settlement") |
| 58 | @Operation(summary = "获得订单结算信息") | 85 | @Operation(summary = "获得订单结算信息") |
| 59 | @PreAuthenticated | 86 | @PreAuthenticated |
| @@ -61,6 +88,58 @@ public class AppTradeOrderController { | @@ -61,6 +88,58 @@ public class AppTradeOrderController { | ||
| 61 | return success(tradeOrderUpdateService.settlementOrder(getLoginUserId(), settlementReqVO)); | 88 | return success(tradeOrderUpdateService.settlementOrder(getLoginUserId(), settlementReqVO)); |
| 62 | } | 89 | } |
| 63 | 90 | ||
| 91 | + @GetMapping("/settlementProduct") | ||
| 92 | + @Operation(summary = "获得商品结算信息") | ||
| 93 | + public CommonResult<List<AppTradeProductSettlementRespVO>> settlementProduct(@RequestParam("ids") Set<Long> ids) { | ||
| 94 | + List<AppTradeProductSettlementRespVO> appTradeProductSettlementRespVOS = new ArrayList<>(); | ||
| 95 | + MemberLevelRespDTO memberLevel = getMemberLevel(); | ||
| 96 | + ids.forEach(spuId -> { | ||
| 97 | + List<AppTradeProductSettlementRespVO.Sku> skus = new ArrayList<>(); | ||
| 98 | + List<ProductSkuRespDTO> skuList = productKpuApi.getSkuListBySpuId(Collections.singletonList(spuId)); | ||
| 99 | + //查询sku的会员和限时优惠 | ||
| 100 | + skuList.forEach(sku -> { | ||
| 101 | + //查询限时优惠价格 | ||
| 102 | + AppTradeProductSettlementRespVO.Sku skuDiscount = calculateDiscountPrice(sku.getId(), sku.getPrice()); | ||
| 103 | + | ||
| 104 | + //查询会员价 | ||
| 105 | + AppTradeProductSettlementRespVO.Sku skuVip = calculateVipPrice(sku.getId(), sku.getPrice(), memberLevel); | ||
| 106 | + | ||
| 107 | + if(skuDiscount != null && skuVip != null){ | ||
| 108 | + if(skuDiscount.getPrice() > skuVip.getPrice()){ | ||
| 109 | + skus.add(skuVip); | ||
| 110 | + }else{ | ||
| 111 | + skus.add(skuDiscount); | ||
| 112 | + } | ||
| 113 | + }else if(skuDiscount != null){ | ||
| 114 | + skus.add(skuDiscount); | ||
| 115 | + }else if(skuVip != null){ | ||
| 116 | + skus.add(skuVip); | ||
| 117 | + } | ||
| 118 | + | ||
| 119 | + }); | ||
| 120 | + AppTradeProductSettlementRespVO.Reward reward = calculateReward(spuId); | ||
| 121 | + AppTradeProductSettlementRespVO respVO = AppTradeProductSettlementRespVO.builder().id(spuId).skus(skus).build(); | ||
| 122 | + if(reward != null){ | ||
| 123 | + //创建满减活动对象 | ||
| 124 | + respVO.setReward(reward); | ||
| 125 | + } | ||
| 126 | + appTradeProductSettlementRespVOS.add(respVO); | ||
| 127 | + }); | ||
| 128 | + return success(appTradeProductSettlementRespVOS); | ||
| 129 | + } | ||
| 130 | + | ||
| 131 | + private MemberLevelRespDTO getMemberLevel() { | ||
| 132 | + Long userId = getLoginUserId(); | ||
| 133 | + if (userId == null) { | ||
| 134 | + return null; | ||
| 135 | + } | ||
| 136 | + MemberUserRespDTO user = memberUserApi.getUser(userId); | ||
| 137 | + if (user.getLevelId() == null || user.getLevelId() <= 0) { | ||
| 138 | + return null; | ||
| 139 | + } | ||
| 140 | + return memberLevelApi.getMemberLevel(user.getLevelId()); | ||
| 141 | + } | ||
| 142 | + | ||
| 64 | @PostMapping("/create") | 143 | @PostMapping("/create") |
| 65 | @Operation(summary = "创建订单") | 144 | @Operation(summary = "创建订单") |
| 66 | @PreAuthenticated | 145 | @PreAuthenticated |
| @@ -188,4 +267,78 @@ public class AppTradeOrderController { | @@ -188,4 +267,78 @@ public class AppTradeOrderController { | ||
| 188 | return success(tradeOrderUpdateService.createOrderItemCommentByMember(getLoginUserId(), createReqVO)); | 267 | return success(tradeOrderUpdateService.createOrderItemCommentByMember(getLoginUserId(), createReqVO)); |
| 189 | } | 268 | } |
| 190 | 269 | ||
| 270 | + /** | ||
| 271 | + * 计算会员 VIP 优惠价格 | ||
| 272 | + * | ||
| 273 | + * @param price 原价 | ||
| 274 | + * @param memberLevel 会员等级 | ||
| 275 | + * @return 优惠价格 | ||
| 276 | + */ | ||
| 277 | + public AppTradeProductSettlementRespVO.Sku calculateVipPrice(Long skuId, Integer price, MemberLevelRespDTO memberLevel) { | ||
| 278 | + if (memberLevel == null || memberLevel.getDiscountPercent() == null) { | ||
| 279 | + return null; | ||
| 280 | + } | ||
| 281 | + Integer newPrice = price * memberLevel.getDiscountPercent() / 100; | ||
| 282 | + return AppTradeProductSettlementRespVO.Sku.builder(). | ||
| 283 | + skuId(skuId). | ||
| 284 | + type(PromotionTypeEnum.MEMBER_LEVEL.getType()). | ||
| 285 | + price(newPrice).build(); | ||
| 286 | + } | ||
| 287 | + | ||
| 288 | + /** | ||
| 289 | + * 计算限时优惠信息 | ||
| 290 | + * | ||
| 291 | + * @param price 原价 | ||
| 292 | + * @param skuId 商品规格id | ||
| 293 | + * @return 优惠价格 | ||
| 294 | + */ | ||
| 295 | + private AppTradeProductSettlementRespVO.Sku calculateDiscountPrice(Long skuId, Integer price) { | ||
| 296 | + if (skuId == null) { | ||
| 297 | + return null; | ||
| 298 | + } | ||
| 299 | + | ||
| 300 | + //根据商品id查询限时优惠 | ||
| 301 | + List<DiscountProductRespDTO> matchDiscountProductList = discountActivityApi.getMatchDiscountProductList(Collections.singletonList(skuId)); | ||
| 302 | + if (matchDiscountProductList != null && !matchDiscountProductList.isEmpty()) { | ||
| 303 | + DiscountProductRespDTO discountProductRespDTO = matchDiscountProductList.get(matchDiscountProductList.size() - 1); | ||
| 304 | + AppTradeProductSettlementRespVO.Sku sku = AppTradeProductSettlementRespVO.Sku.builder(). | ||
| 305 | + skuId(skuId). | ||
| 306 | + discountId(discountProductRespDTO.getId()). | ||
| 307 | + type(PromotionTypeEnum.DISCOUNT_ACTIVITY.getType()). | ||
| 308 | + endTime(discountProductRespDTO.getActivityEndTime()). | ||
| 309 | + build(); | ||
| 310 | + Integer discountType = discountProductRespDTO.getDiscountType(); | ||
| 311 | + if(Objects.equals(PromotionDiscountTypeEnum.PRICE.getType(), discountType)){ | ||
| 312 | + sku.setPrice(price - discountProductRespDTO.getDiscountPrice() * 100); | ||
| 313 | + }else if(Objects.equals(PromotionDiscountTypeEnum.PERCENT.getType(), discountType)){ | ||
| 314 | + Integer newPrice = price * discountProductRespDTO.getDiscountPercent() / 100; | ||
| 315 | + sku.setPrice(price - newPrice); | ||
| 316 | + }else{ | ||
| 317 | + throw exception(DISCOUNT_ACTIVITY_TYPE_NOT_EXISTS); | ||
| 318 | + } | ||
| 319 | + return sku; | ||
| 320 | + } | ||
| 321 | + return null; | ||
| 322 | + } | ||
| 323 | + | ||
| 324 | + /** | ||
| 325 | + * 获取第一层满减活动 | ||
| 326 | + * | ||
| 327 | + * @param spuId 商品规格id | ||
| 328 | + * @return 优惠价格 | ||
| 329 | + */ | ||
| 330 | + private AppTradeProductSettlementRespVO.Reward calculateReward(Long spuId) { | ||
| 331 | + List<RewardActivityMatchRespDTO> matchRewardActivityList = rewardActivityApi.getRewardActivityBySpuIdsAndStatusAndDateTimeLt(Collections.singletonList(spuId), CommonStatusEnum.ENABLE.getStatus(), LocalDateTime.now()); | ||
| 332 | + if(matchRewardActivityList != null && !matchRewardActivityList.isEmpty()){ | ||
| 333 | + RewardActivityMatchRespDTO rewardActivityMatchRespDTO = matchRewardActivityList.get(matchRewardActivityList.size() - 1); | ||
| 334 | + if(rewardActivityMatchRespDTO != null){ | ||
| 335 | + RewardActivityMatchRespDTO.Rule rule = rewardActivityMatchRespDTO.getRules().get(0); | ||
| 336 | + return AppTradeProductSettlementRespVO.Reward.builder(). | ||
| 337 | + rewardActivity("满" + rule.getLimit() / 100 + (Objects.equals(rewardActivityMatchRespDTO.getConditionType(), PromotionConditionTypeEnum.PRICE.getType())?"元":"件"+"减") +rule.getDiscountPrice() / 100) | ||
| 338 | + .id(rewardActivityMatchRespDTO.getId()).build(); | ||
| 339 | + } | ||
| 340 | + } | ||
| 341 | + return null; | ||
| 342 | + } | ||
| 343 | + | ||
| 191 | } | 344 | } |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementRespVO.java
| 1 | package cn.iocoder.yudao.module.trade.controller.app.order.vo; | 1 | package cn.iocoder.yudao.module.trade.controller.app.order.vo; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.module.trade.controller.app.base.property.AppProductPropertyValueDetailRespVO; | 3 | import cn.iocoder.yudao.module.trade.controller.app.base.property.AppProductPropertyValueDetailRespVO; |
| 4 | +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; | ||
| 4 | import io.swagger.v3.oas.annotations.media.Schema; | 5 | import io.swagger.v3.oas.annotations.media.Schema; |
| 5 | import jakarta.validation.constraints.NotNull; | 6 | import jakarta.validation.constraints.NotNull; |
| 6 | import lombok.AllArgsConstructor; | 7 | import lombok.AllArgsConstructor; |
| @@ -31,6 +32,13 @@ public class AppTradeOrderSettlementRespVO { | @@ -31,6 +32,13 @@ public class AppTradeOrderSettlementRespVO { | ||
| 31 | @Schema(description = "总积分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") | 32 | @Schema(description = "总积分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") |
| 32 | private Integer totalPoint; | 33 | private Integer totalPoint; |
| 33 | 34 | ||
| 35 | + /** | ||
| 36 | + * 营销活动数组 | ||
| 37 | + * | ||
| 38 | + * 只对应 {@link TradePriceCalculateRespBO.Price#items} 商品匹配的活动 | ||
| 39 | + */ | ||
| 40 | + private List<TradePriceCalculateRespBO.Promotion> promotions; | ||
| 41 | + | ||
| 34 | @Schema(description = "购物项") | 42 | @Schema(description = "购物项") |
| 35 | @Data | 43 | @Data |
| 36 | public static class Item { | 44 | public static class Item { |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeProductSettlementRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.app.order.vo; | ||
| 2 | + | ||
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | +import lombok.Builder; | ||
| 5 | +import lombok.Data; | ||
| 6 | + | ||
| 7 | +import java.io.Serializable; | ||
| 8 | +import java.time.LocalDateTime; | ||
| 9 | +import java.util.List; | ||
| 10 | + | ||
| 11 | +@Schema(description = "用户 App - 商品结算信息 Response VO") | ||
| 12 | +@Data | ||
| 13 | +@Builder | ||
| 14 | +public class AppTradeProductSettlementRespVO { | ||
| 15 | + | ||
| 16 | + @Schema(description = "spu 商品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||
| 17 | + private Long id; | ||
| 18 | + | ||
| 19 | + @Schema(description = "满减活动对象", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||
| 20 | + private Reward reward; | ||
| 21 | + | ||
| 22 | + @Schema(description = "sku 活动信息", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||
| 23 | + private List<Sku> skus; | ||
| 24 | + | ||
| 25 | + /** | ||
| 26 | + * 满减活动 | ||
| 27 | + */ | ||
| 28 | + @Data | ||
| 29 | + @Builder | ||
| 30 | + public static class Reward implements Serializable { | ||
| 31 | + | ||
| 32 | + @Schema(description = "满减活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||
| 33 | + private Long id; | ||
| 34 | + | ||
| 35 | + @Schema(description = "满减活动信息", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||
| 36 | + private String rewardActivity; | ||
| 37 | + | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + /** | ||
| 41 | + * SKU 数组 | ||
| 42 | + */ | ||
| 43 | + @Data | ||
| 44 | + @Builder | ||
| 45 | + public static class Sku implements Serializable { | ||
| 46 | + | ||
| 47 | + @Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||
| 48 | + private Long skuId; | ||
| 49 | + | ||
| 50 | + @Schema(description = "价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||
| 51 | + private Integer price; | ||
| 52 | + | ||
| 53 | + @Schema(description = "营销类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||
| 54 | + private Integer type; // 对应 PromotionTypeEnum 枚举 | ||
| 55 | + | ||
| 56 | + @Schema(description = "限时优惠id", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 57 | + private Long discountId; | ||
| 58 | + | ||
| 59 | + @Schema(description = "活动结束时间", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 60 | + private LocalDateTime endTime; | ||
| 61 | + | ||
| 62 | + } | ||
| 63 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/aftersale/AfterSaleConvert.java
| @@ -43,11 +43,9 @@ public interface AfterSaleConvert { | @@ -43,11 +43,9 @@ public interface AfterSaleConvert { | ||
| 43 | @Mapping(source = "afterSale.orderId", target = "merchantOrderId"), | 43 | @Mapping(source = "afterSale.orderId", target = "merchantOrderId"), |
| 44 | @Mapping(source = "afterSale.id", target = "merchantRefundId"), | 44 | @Mapping(source = "afterSale.id", target = "merchantRefundId"), |
| 45 | @Mapping(source = "afterSale.applyReason", target = "reason"), | 45 | @Mapping(source = "afterSale.applyReason", target = "reason"), |
| 46 | - @Mapping(source = "afterSale.refundPrice", target = "price"), | ||
| 47 | - @Mapping(source = "orderProperties.payAppKey", target = "appKey") | 46 | + @Mapping(source = "afterSale.refundPrice", target = "price") |
| 48 | }) | 47 | }) |
| 49 | - PayRefundCreateReqDTO convert(String userIp, AfterSaleDO afterSale, | ||
| 50 | - TradeOrderProperties orderProperties); | 48 | + PayRefundCreateReqDTO convert(String userIp, AfterSaleDO afterSale); |
| 51 | 49 | ||
| 52 | MemberUserRespVO convert(MemberUserRespDTO bean); | 50 | MemberUserRespVO convert(MemberUserRespDTO bean); |
| 53 | 51 |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/AfterSaleServiceImpl.java
| @@ -371,8 +371,9 @@ public class AfterSaleServiceImpl implements AfterSaleService { | @@ -371,8 +371,9 @@ public class AfterSaleServiceImpl implements AfterSaleService { | ||
| 371 | @Override | 371 | @Override |
| 372 | public void afterCommit() { | 372 | public void afterCommit() { |
| 373 | // 创建退款单 | 373 | // 创建退款单 |
| 374 | - PayRefundCreateReqDTO createReqDTO = AfterSaleConvert.INSTANCE.convert(userIp, afterSale, tradeOrderProperties) | 374 | + PayRefundCreateReqDTO createReqDTO = AfterSaleConvert.INSTANCE.convert(userIp, afterSale) |
| 375 | .setReason(StrUtil.format("退款【{}】", afterSale.getSpuName())); | 375 | .setReason(StrUtil.format("退款【{}】", afterSale.getSpuName())); |
| 376 | + createReqDTO.setAppKey(tradeOrderProperties.getPayAppKey()); | ||
| 376 | Long payRefundId = payRefundApi.createRefund(createReqDTO); | 377 | Long payRefundId = payRefundApi.createRefund(createReqDTO); |
| 377 | // 更新售后单的退款单号 | 378 | // 更新售后单的退款单号 |
| 378 | tradeAfterSaleMapper.updateById(new AfterSaleDO().setId(afterSale.getId()).setPayRefundId(payRefundId)); | 379 | tradeAfterSaleMapper.updateById(new AfterSaleDO().setId(afterSale.getId()).setPayRefundId(payRefundId)); |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateRespBO.java
| @@ -68,10 +68,11 @@ public class TradePriceCalculateRespBO { | @@ -68,10 +68,11 @@ public class TradePriceCalculateRespBO { | ||
| 68 | */ | 68 | */ |
| 69 | private Long bargainActivityId; | 69 | private Long bargainActivityId; |
| 70 | 70 | ||
| 71 | + | ||
| 71 | /** | 72 | /** |
| 72 | * 是否包邮 | 73 | * 是否包邮 |
| 73 | */ | 74 | */ |
| 74 | - private Boolean freeDelivery; | 75 | + private Boolean freeDelivery = false; |
| 75 | 76 | ||
| 76 | /** | 77 | /** |
| 77 | * 赠送的优惠劵 | 78 | * 赠送的优惠劵 |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculator.java
| @@ -121,10 +121,13 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { | @@ -121,10 +121,13 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { | ||
| 121 | * @return 是否包邮 | 121 | * @return 是否包邮 |
| 122 | */ | 122 | */ |
| 123 | private boolean isGlobalExpressFree(TradePriceCalculateRespBO result) { | 123 | private boolean isGlobalExpressFree(TradePriceCalculateRespBO result) { |
| 124 | + | ||
| 124 | TradeConfigDO config = tradeConfigService.getTradeConfig(); | 125 | TradeConfigDO config = tradeConfigService.getTradeConfig(); |
| 125 | - return config != null | 126 | + return result.getFreeDelivery() || |
| 127 | + (config != null | ||
| 126 | && Boolean.TRUE.equals(config.getDeliveryExpressFreeEnabled()) // 开启包邮 | 128 | && Boolean.TRUE.equals(config.getDeliveryExpressFreeEnabled()) // 开启包邮 |
| 127 | - && result.getPrice().getPayPrice() >= config.getDeliveryExpressFreePrice(); // 满足包邮的价格 | 129 | + && result.getPrice().getPayPrice() >= config.getDeliveryExpressFreePrice() |
| 130 | + ); // 满足包邮的价格 | ||
| 128 | } | 131 | } |
| 129 | 132 | ||
| 130 | private void calculateDeliveryPrice(List<OrderItem> selectedSkus, | 133 | private void calculateDeliveryPrice(List<OrderItem> selectedSkus, |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDiscountActivityPriceCalculator.java
| @@ -3,6 +3,10 @@ package cn.iocoder.yudao.module.trade.service.price.calculator; | @@ -3,6 +3,10 @@ package cn.iocoder.yudao.module.trade.service.price.calculator; | ||
| 3 | import cn.hutool.core.collection.CollUtil; | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | import cn.hutool.core.util.ObjectUtil; | 4 | import cn.hutool.core.util.ObjectUtil; |
| 5 | import cn.hutool.core.util.StrUtil; | 5 | import cn.hutool.core.util.StrUtil; |
| 6 | +import cn.iocoder.yudao.module.member.api.level.MemberLevelApi; | ||
| 7 | +import cn.iocoder.yudao.module.member.api.level.dto.MemberLevelRespDTO; | ||
| 8 | +import cn.iocoder.yudao.module.member.api.user.MemberUserApi; | ||
| 9 | +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; | ||
| 6 | import cn.iocoder.yudao.module.promotion.api.discount.DiscountActivityApi; | 10 | import cn.iocoder.yudao.module.promotion.api.discount.DiscountActivityApi; |
| 7 | import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO; | 11 | import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO; |
| 8 | import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; | 12 | import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; |
| @@ -14,6 +18,8 @@ import org.springframework.core.annotation.Order; | @@ -14,6 +18,8 @@ import org.springframework.core.annotation.Order; | ||
| 14 | import org.springframework.stereotype.Component; | 18 | import org.springframework.stereotype.Component; |
| 15 | 19 | ||
| 16 | import jakarta.annotation.Resource; | 20 | import jakarta.annotation.Resource; |
| 21 | + | ||
| 22 | +import java.math.BigDecimal; | ||
| 17 | import java.util.List; | 23 | import java.util.List; |
| 18 | import java.util.Map; | 24 | import java.util.Map; |
| 19 | 25 | ||
| @@ -32,6 +38,10 @@ public class TradeDiscountActivityPriceCalculator implements TradePriceCalculato | @@ -32,6 +38,10 @@ public class TradeDiscountActivityPriceCalculator implements TradePriceCalculato | ||
| 32 | 38 | ||
| 33 | @Resource | 39 | @Resource |
| 34 | private DiscountActivityApi discountActivityApi; | 40 | private DiscountActivityApi discountActivityApi; |
| 41 | + @Resource | ||
| 42 | + private MemberLevelApi memberLevelApi; | ||
| 43 | + @Resource | ||
| 44 | + private MemberUserApi memberUserApi; | ||
| 35 | 45 | ||
| 36 | @Override | 46 | @Override |
| 37 | public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { | 47 | public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { |
| @@ -39,35 +49,101 @@ public class TradeDiscountActivityPriceCalculator implements TradePriceCalculato | @@ -39,35 +49,101 @@ public class TradeDiscountActivityPriceCalculator implements TradePriceCalculato | ||
| 39 | if (ObjectUtil.notEqual(result.getType(), TradeOrderTypeEnum.NORMAL.getType())) { | 49 | if (ObjectUtil.notEqual(result.getType(), TradeOrderTypeEnum.NORMAL.getType())) { |
| 40 | return; | 50 | return; |
| 41 | } | 51 | } |
| 52 | + | ||
| 53 | + boolean discount; | ||
| 54 | + boolean vip; | ||
| 55 | + | ||
| 56 | + //----------------------------------限时折扣计算----------------------------------------- | ||
| 42 | // 获得 SKU 对应的限时折扣活动 | 57 | // 获得 SKU 对应的限时折扣活动 |
| 43 | List<DiscountProductRespDTO> discountProducts = discountActivityApi.getMatchDiscountProductList( | 58 | List<DiscountProductRespDTO> discountProducts = discountActivityApi.getMatchDiscountProductList( |
| 44 | convertSet(result.getItems(), TradePriceCalculateRespBO.OrderItem::getSkuId)); | 59 | convertSet(result.getItems(), TradePriceCalculateRespBO.OrderItem::getSkuId)); |
| 45 | if (CollUtil.isEmpty(discountProducts)) { | 60 | if (CollUtil.isEmpty(discountProducts)) { |
| 46 | - return; | 61 | + discount = false; |
| 62 | + }else { | ||
| 63 | + discount = true; | ||
| 47 | } | 64 | } |
| 48 | Map<Long, DiscountProductRespDTO> discountProductMap = convertMap(discountProducts, DiscountProductRespDTO::getSkuId); | 65 | Map<Long, DiscountProductRespDTO> discountProductMap = convertMap(discountProducts, DiscountProductRespDTO::getSkuId); |
| 49 | 66 | ||
| 50 | - // 处理每个 SKU 的限时折扣 | 67 | + |
| 68 | + | ||
| 69 | + //----------------------------------会员计算----------------------------------------- | ||
| 70 | + MemberLevelRespDTO level; | ||
| 71 | + // 获得用户的会员等级 | ||
| 72 | + MemberUserRespDTO user = memberUserApi.getUser(param.getUserId()); | ||
| 73 | + if (user.getLevelId() != null && user.getLevelId() > 0) { | ||
| 74 | + level = memberLevelApi.getMemberLevel(user.getLevelId()); | ||
| 75 | + if (level != null && level.getDiscountPercent() != null) { | ||
| 76 | + vip = true; | ||
| 77 | + }else { | ||
| 78 | + vip = false; | ||
| 79 | + } | ||
| 80 | + }else { | ||
| 81 | + level = null; | ||
| 82 | + vip = false; | ||
| 83 | + } | ||
| 84 | + | ||
| 85 | + | ||
| 86 | + // 2. 计算每个 SKU 的优惠金额 | ||
| 51 | result.getItems().forEach(orderItem -> { | 87 | result.getItems().forEach(orderItem -> { |
| 52 | - // 1. 获取该 SKU 的优惠信息 | ||
| 53 | - DiscountProductRespDTO discountProduct = discountProductMap.get(orderItem.getSkuId()); | ||
| 54 | - if (discountProduct == null) { | ||
| 55 | - return; | 88 | + |
| 89 | + //----------------------------------限时折扣计算----------------------------------------- | ||
| 90 | + DiscountProductRespDTO discountProduct = null; | ||
| 91 | + Integer newDiscountPrice = 0; | ||
| 92 | + if (discount){ | ||
| 93 | + // 2.1 计算限时折扣优惠信息 | ||
| 94 | + discountProduct = discountProductMap.get(orderItem.getSkuId()); | ||
| 95 | + if (discountProduct != null) { | ||
| 96 | + // 2.2 计算优惠金额 | ||
| 97 | + Integer newPayPrice = calculatePayPrice(discountProduct, orderItem); | ||
| 98 | + newDiscountPrice = orderItem.getPayPrice() - newPayPrice; | ||
| 99 | + } | ||
| 100 | + } | ||
| 101 | + | ||
| 102 | + | ||
| 103 | + //----------------------------------会员计算----------------------------------------- | ||
| 104 | + Integer vipPrice = 0; | ||
| 105 | + if (vip){ | ||
| 106 | + // 2.3 计算会员优惠金额 | ||
| 107 | + vipPrice = calculateVipPrice(orderItem.getPayPrice(), level.getDiscountPercent()); | ||
| 56 | } | 108 | } |
| 57 | - // 2. 计算优惠金额 | ||
| 58 | - Integer newPayPrice = calculatePayPrice(discountProduct, orderItem); | ||
| 59 | - Integer newDiscountPrice = orderItem.getPayPrice() - newPayPrice; | ||
| 60 | 109 | ||
| 61 | - // 3.1 记录优惠明细 | 110 | + |
| 111 | + // 2.4 记录优惠明细 | ||
| 112 | + // 注意,只有在选中的情况下,才会记录到优惠明细。否则仅仅是更新 SKU 优惠金额,用于展示 | ||
| 62 | if (orderItem.getSelected()) { | 113 | if (orderItem.getSelected()) { |
| 63 | - // 注意,只有在选中的情况下,才会记录到优惠明细。否则仅仅是更新 SKU 优惠金额,用于展示 | ||
| 64 | - TradePriceCalculatorHelper.addPromotion(result, orderItem, | ||
| 65 | - discountProduct.getActivityId(), discountProduct.getActivityName(), PromotionTypeEnum.DISCOUNT_ACTIVITY.getType(), | ||
| 66 | - StrUtil.format("限时折扣:省 {} 元", formatPrice(newDiscountPrice)), | ||
| 67 | - newDiscountPrice); | 114 | + if (discount && vip){ |
| 115 | + if(newDiscountPrice > vipPrice){ | ||
| 116 | + TradePriceCalculatorHelper.addPromotion(result, orderItem, | ||
| 117 | + discountProduct.getActivityId(), discountProduct.getActivityName(), PromotionTypeEnum.DISCOUNT_ACTIVITY.getType(), | ||
| 118 | + StrUtil.format("限时折扣:省 {} 元", formatPrice(newDiscountPrice)), | ||
| 119 | + newDiscountPrice); | ||
| 120 | + // 2.5 更新 SKU 优惠金额 | ||
| 121 | + orderItem.setDiscountPrice(orderItem.getDiscountPrice() + newDiscountPrice); | ||
| 122 | + }else{ | ||
| 123 | + TradePriceCalculatorHelper.addPromotion(result, orderItem, | ||
| 124 | + level.getId(), level.getName(), PromotionTypeEnum.MEMBER_LEVEL.getType(), | ||
| 125 | + String.format("会员等级折扣:省 %s 元", formatPrice(vipPrice)), | ||
| 126 | + vipPrice); | ||
| 127 | + // 2.5 更新 SKU 的优惠金额 | ||
| 128 | + orderItem.setVipPrice(vipPrice); | ||
| 129 | + } | ||
| 130 | + }else if (discount){ | ||
| 131 | + TradePriceCalculatorHelper.addPromotion(result, orderItem, | ||
| 132 | + discountProduct.getActivityId(), discountProduct.getActivityName(), PromotionTypeEnum.DISCOUNT_ACTIVITY.getType(), | ||
| 133 | + StrUtil.format("限时折扣:省 {} 元", formatPrice(newDiscountPrice)), | ||
| 134 | + newDiscountPrice); | ||
| 135 | + // 2.5 更新 SKU 优惠金额 | ||
| 136 | + orderItem.setDiscountPrice(orderItem.getDiscountPrice() + newDiscountPrice); | ||
| 137 | + }else if (vip){ | ||
| 138 | + TradePriceCalculatorHelper.addPromotion(result, orderItem, | ||
| 139 | + level.getId(), level.getName(), PromotionTypeEnum.MEMBER_LEVEL.getType(), | ||
| 140 | + String.format("会员等级折扣:省 %s 元", formatPrice(vipPrice)), | ||
| 141 | + vipPrice); | ||
| 142 | + // 2.5 更新 SKU 的优惠金额 | ||
| 143 | + orderItem.setVipPrice(vipPrice); | ||
| 144 | + } | ||
| 68 | } | 145 | } |
| 69 | - // 3.2 更新 SKU 优惠金额 | ||
| 70 | - orderItem.setDiscountPrice(orderItem.getDiscountPrice() + newDiscountPrice); | 146 | + |
| 71 | TradePriceCalculatorHelper.recountPayPrice(orderItem); | 147 | TradePriceCalculatorHelper.recountPayPrice(orderItem); |
| 72 | }); | 148 | }); |
| 73 | TradePriceCalculatorHelper.recountAllPrice(result); | 149 | TradePriceCalculatorHelper.recountAllPrice(result); |
| @@ -86,4 +162,20 @@ public class TradeDiscountActivityPriceCalculator implements TradePriceCalculato | @@ -86,4 +162,20 @@ public class TradeDiscountActivityPriceCalculator implements TradePriceCalculato | ||
| 86 | return price; | 162 | return price; |
| 87 | } | 163 | } |
| 88 | 164 | ||
| 165 | + /** | ||
| 166 | + * 计算会员 VIP 优惠价格 | ||
| 167 | + * | ||
| 168 | + * @param price 原价 | ||
| 169 | + * @param discountPercent 折扣 | ||
| 170 | + * @return 优惠价格 | ||
| 171 | + */ | ||
| 172 | + public Integer calculateVipPrice(Integer price, Integer discountPercent) { | ||
| 173 | + if (discountPercent == null) { | ||
| 174 | + return 0; | ||
| 175 | + } | ||
| 176 | + BigDecimal divide = new BigDecimal(price).multiply(new BigDecimal(discountPercent)).divide(new BigDecimal(100)); | ||
| 177 | + Integer newPrice = divide.intValue(); | ||
| 178 | + return price - newPrice; | ||
| 179 | + } | ||
| 180 | + | ||
| 89 | } | 181 | } |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeMemberLevelPriceCalculator.java
| @@ -30,44 +30,49 @@ public class TradeMemberLevelPriceCalculator implements TradePriceCalculator { | @@ -30,44 +30,49 @@ public class TradeMemberLevelPriceCalculator implements TradePriceCalculator { | ||
| 30 | @Resource | 30 | @Resource |
| 31 | private MemberUserApi memberUserApi; | 31 | private MemberUserApi memberUserApi; |
| 32 | 32 | ||
| 33 | + /** | ||
| 34 | + * 会员计算迁移到限时优惠计算里 | ||
| 35 | + * @param param | ||
| 36 | + * @param result | ||
| 37 | + */ | ||
| 33 | @Override | 38 | @Override |
| 34 | public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { | 39 | public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { |
| 35 | - // 0. 只有【普通】订单,才计算该优惠 | ||
| 36 | - if (ObjectUtil.notEqual(result.getType(), TradeOrderTypeEnum.NORMAL.getType())) { | ||
| 37 | - return; | ||
| 38 | - } | ||
| 39 | - // 1. 获得用户的会员等级 | ||
| 40 | - MemberUserRespDTO user = memberUserApi.getUser(param.getUserId()); | ||
| 41 | - if (user.getLevelId() == null || user.getLevelId() <= 0) { | ||
| 42 | - return; | ||
| 43 | - } | ||
| 44 | - MemberLevelRespDTO level = memberLevelApi.getMemberLevel(user.getLevelId()); | ||
| 45 | - if (level == null || level.getDiscountPercent() == null) { | ||
| 46 | - return; | ||
| 47 | - } | ||
| 48 | - | ||
| 49 | - // 2. 计算每个 SKU 的优惠金额 | ||
| 50 | - result.getItems().forEach(orderItem -> { | ||
| 51 | - // 2.1 计算优惠金额 | ||
| 52 | - Integer vipPrice = calculateVipPrice(orderItem.getPayPrice(), level.getDiscountPercent()); | ||
| 53 | - if (vipPrice <= 0) { | ||
| 54 | - return; | ||
| 55 | - } | ||
| 56 | - | ||
| 57 | - // 2.2 记录优惠明细 | ||
| 58 | - if (orderItem.getSelected()) { | ||
| 59 | - // 注意,只有在选中的情况下,才会记录到优惠明细。否则仅仅是更新 SKU 优惠金额,用于展示 | ||
| 60 | - TradePriceCalculatorHelper.addPromotion(result, orderItem, | ||
| 61 | - level.getId(), level.getName(), PromotionTypeEnum.MEMBER_LEVEL.getType(), | ||
| 62 | - String.format("会员等级折扣:省 %s 元", formatPrice(vipPrice)), | ||
| 63 | - vipPrice); | ||
| 64 | - } | ||
| 65 | - | ||
| 66 | - // 2.3 更新 SKU 的优惠金额 | ||
| 67 | - orderItem.setVipPrice(vipPrice); | ||
| 68 | - TradePriceCalculatorHelper.recountPayPrice(orderItem); | ||
| 69 | - }); | ||
| 70 | - TradePriceCalculatorHelper.recountAllPrice(result); | 40 | +// // 0. 只有【普通】订单,才计算该优惠 |
| 41 | +// if (ObjectUtil.notEqual(result.getType(), TradeOrderTypeEnum.NORMAL.getType())) { | ||
| 42 | +// return; | ||
| 43 | +// } | ||
| 44 | +// // 1. 获得用户的会员等级 | ||
| 45 | +// MemberUserRespDTO user = memberUserApi.getUser(param.getUserId()); | ||
| 46 | +// if (user.getLevelId() == null || user.getLevelId() <= 0) { | ||
| 47 | +// return; | ||
| 48 | +// } | ||
| 49 | +// MemberLevelRespDTO level = memberLevelApi.getMemberLevel(user.getLevelId()); | ||
| 50 | +// if (level == null || level.getDiscountPercent() == null) { | ||
| 51 | +// return; | ||
| 52 | +// } | ||
| 53 | +// | ||
| 54 | +// // 2. 计算每个 SKU 的优惠金额 | ||
| 55 | +// result.getItems().forEach(orderItem -> { | ||
| 56 | +// // 2.1 计算优惠金额 | ||
| 57 | +// Integer vipPrice = calculateVipPrice(orderItem.getPayPrice(), level.getDiscountPercent()); | ||
| 58 | +// if (vipPrice <= 0) { | ||
| 59 | +// return; | ||
| 60 | +// } | ||
| 61 | +// | ||
| 62 | +// // 2.2 记录优惠明细 | ||
| 63 | +// if (orderItem.getSelected()) { | ||
| 64 | +// // 注意,只有在选中的情况下,才会记录到优惠明细。否则仅仅是更新 SKU 优惠金额,用于展示 | ||
| 65 | +// TradePriceCalculatorHelper.addPromotion(result, orderItem, | ||
| 66 | +// level.getId(), level.getName(), PromotionTypeEnum.MEMBER_LEVEL.getType(), | ||
| 67 | +// String.format("会员等级折扣:省 %s 元", formatPrice(vipPrice)), | ||
| 68 | +// vipPrice); | ||
| 69 | +// } | ||
| 70 | +// | ||
| 71 | +// // 2.3 更新 SKU 的优惠金额 | ||
| 72 | +// orderItem.setVipPrice(vipPrice); | ||
| 73 | +// TradePriceCalculatorHelper.recountPayPrice(orderItem); | ||
| 74 | +// }); | ||
| 75 | +// TradePriceCalculatorHelper.recountAllPrice(result); | ||
| 71 | } | 76 | } |
| 72 | 77 | ||
| 73 | /** | 78 | /** |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeRewardActivityPriceCalculator.java
| @@ -23,7 +23,10 @@ import java.util.Comparator; | @@ -23,7 +23,10 @@ import java.util.Comparator; | ||
| 23 | import java.util.List; | 23 | import java.util.List; |
| 24 | import java.util.Map; | 24 | import java.util.Map; |
| 25 | 25 | ||
| 26 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||
| 27 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | ||
| 26 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; | 28 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; |
| 29 | +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.REWARD_ACTIVITY_TYPE_NOT_EXISTS; | ||
| 27 | import static cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculatorHelper.formatPrice; | 30 | import static cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculatorHelper.formatPrice; |
| 28 | 31 | ||
| 29 | // TODO @puhui999:相关的单测,建议改一改 | 32 | // TODO @puhui999:相关的单测,建议改一改 |
| @@ -47,14 +50,15 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator | @@ -47,14 +50,15 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator | ||
| 47 | return; | 50 | return; |
| 48 | } | 51 | } |
| 49 | // 获得 SKU 对应的满减送活动 | 52 | // 获得 SKU 对应的满减送活动 |
| 50 | - List<RewardActivityMatchRespDTO> rewardActivities = rewardActivityApi.getRewardActivityListByStatusAndNow( | ||
| 51 | - CommonStatusEnum.ENABLE.getStatus(), LocalDateTime.now()); | 53 | + List<RewardActivityMatchRespDTO> rewardActivities = rewardActivityApi.getRewardActivityBySpuIdsAndStatusAndDateTimeLt( |
| 54 | + convertSet(result.getItems(), TradePriceCalculateRespBO.OrderItem::getSpuId), CommonStatusEnum.ENABLE.getStatus(), LocalDateTime.now()); | ||
| 52 | if (CollUtil.isEmpty(rewardActivities)) { | 55 | if (CollUtil.isEmpty(rewardActivities)) { |
| 53 | return; | 56 | return; |
| 54 | } | 57 | } |
| 55 | - | ||
| 56 | - // 处理每个满减送活动 | ||
| 57 | - rewardActivities.forEach(rewardActivity -> calculate(param, result, rewardActivity)); | 58 | + // 处理最新的满减送活动 |
| 59 | + if(!rewardActivities.isEmpty()){ | ||
| 60 | + calculate(param, result, rewardActivities.get(0)); | ||
| 61 | + } | ||
| 58 | } | 62 | } |
| 59 | 63 | ||
| 60 | private void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result, | 64 | private void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result, |
| @@ -77,6 +81,8 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator | @@ -77,6 +81,8 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator | ||
| 77 | Integer newDiscountPrice = rule.getDiscountPrice(); | 81 | Integer newDiscountPrice = rule.getDiscountPrice(); |
| 78 | // 2.2 计算分摊的优惠金额 | 82 | // 2.2 计算分摊的优惠金额 |
| 79 | List<Integer> divideDiscountPrices = TradePriceCalculatorHelper.dividePrice(orderItems, newDiscountPrice); | 83 | List<Integer> divideDiscountPrices = TradePriceCalculatorHelper.dividePrice(orderItems, newDiscountPrice); |
| 84 | + //计算是否包邮 | ||
| 85 | + result.setFreeDelivery(rule.getFreeDelivery()); | ||
| 80 | 86 | ||
| 81 | // 3.1 记录使用的优惠劵 | 87 | // 3.1 记录使用的优惠劵 |
| 82 | result.setCouponId(param.getCouponId()); | 88 | result.setCouponId(param.getCouponId()); |
| @@ -119,27 +125,24 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator | @@ -119,27 +125,24 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator | ||
| 119 | /** | 125 | /** |
| 120 | * 获得满减送的订单项(商品)列表 | 126 | * 获得满减送的订单项(商品)列表 |
| 121 | * | 127 | * |
| 122 | - * @param result 计算结果 | 128 | + * @param result 计算结果 |
| 123 | * @param rewardActivity 满减送活动 | 129 | * @param rewardActivity 满减送活动 |
| 124 | * @return 订单项(商品)列表 | 130 | * @return 订单项(商品)列表 |
| 125 | */ | 131 | */ |
| 126 | private List<TradePriceCalculateRespBO.OrderItem> filterMatchActivityOrderItems(TradePriceCalculateRespBO result, | 132 | private List<TradePriceCalculateRespBO.OrderItem> filterMatchActivityOrderItems(TradePriceCalculateRespBO result, |
| 127 | RewardActivityMatchRespDTO rewardActivity) { | 133 | RewardActivityMatchRespDTO rewardActivity) { |
| 128 | - // 情况一:全部商品都可以参与 | ||
| 129 | - if (PromotionProductScopeEnum.isAll(rewardActivity.getProductScope())) { | 134 | + Integer productScope = rewardActivity.getProductScope(); |
| 135 | + if(PromotionProductScopeEnum.isAll(productScope)){ | ||
| 130 | return result.getItems(); | 136 | return result.getItems(); |
| 131 | - } | ||
| 132 | - // 情况二:指定商品参与 | ||
| 133 | - if (PromotionProductScopeEnum.isSpu(rewardActivity.getProductScope())) { | 137 | + }else if (PromotionProductScopeEnum.isSpu(productScope)) { |
| 134 | return filterList(result.getItems(), | 138 | return filterList(result.getItems(), |
| 135 | orderItem -> CollUtil.contains(rewardActivity.getProductScopeValues(), orderItem.getSpuId())); | 139 | orderItem -> CollUtil.contains(rewardActivity.getProductScopeValues(), orderItem.getSpuId())); |
| 136 | - } | ||
| 137 | - // 情况三:指定商品类型参与 | ||
| 138 | - if (PromotionProductScopeEnum.isCategory(rewardActivity.getProductScope())) { | 140 | + }else if (PromotionProductScopeEnum.isCategory(productScope)) { |
| 139 | return filterList(result.getItems(), | 141 | return filterList(result.getItems(), |
| 140 | orderItem -> CollUtil.contains(rewardActivity.getProductScopeValues(), orderItem.getCategoryId())); | 142 | orderItem -> CollUtil.contains(rewardActivity.getProductScopeValues(), orderItem.getCategoryId())); |
| 143 | + }else{ | ||
| 144 | + throw exception(REWARD_ACTIVITY_TYPE_NOT_EXISTS); | ||
| 141 | } | 145 | } |
| 142 | - return List.of(); | ||
| 143 | } | 146 | } |
| 144 | 147 | ||
| 145 | /** | 148 | /** |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java
| @@ -11,6 +11,7 @@ import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | @@ -11,6 +11,7 @@ import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||
| 11 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | 11 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 12 | import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; | 12 | import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; |
| 13 | import cn.iocoder.yudao.framework.datapermission.core.util.DataPermissionUtils; | 13 | import cn.iocoder.yudao.framework.datapermission.core.util.DataPermissionUtils; |
| 14 | +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; | ||
| 14 | import cn.iocoder.yudao.module.infra.api.config.ConfigApi; | 15 | import cn.iocoder.yudao.module.infra.api.config.ConfigApi; |
| 15 | import cn.iocoder.yudao.module.infra.api.file.FileApi; | 16 | import cn.iocoder.yudao.module.infra.api.file.FileApi; |
| 16 | import cn.iocoder.yudao.module.system.controller.admin.auth.vo.AuthRegisterReqVO; | 17 | import cn.iocoder.yudao.module.system.controller.admin.auth.vo.AuthRegisterReqVO; |
| @@ -104,6 +105,7 @@ public class AdminUserServiceImpl implements AdminUserService { | @@ -104,6 +105,7 @@ public class AdminUserServiceImpl implements AdminUserService { | ||
| 104 | AdminUserDO user = BeanUtils.toBean(createReqVO, AdminUserDO.class); | 105 | AdminUserDO user = BeanUtils.toBean(createReqVO, AdminUserDO.class); |
| 105 | user.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启 | 106 | user.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启 |
| 106 | user.setPassword(encodePassword(createReqVO.getPassword())); // 加密密码 | 107 | user.setPassword(encodePassword(createReqVO.getPassword())); // 加密密码 |
| 108 | + user.setTenantId(TenantContextHolder.getRequiredTenantId()); | ||
| 107 | userMapper.insert(user); | 109 | userMapper.insert(user); |
| 108 | // 2.2 插入关联岗位 | 110 | // 2.2 插入关联岗位 |
| 109 | if (CollectionUtil.isNotEmpty(user.getPostIds())) { | 111 | if (CollectionUtil.isNotEmpty(user.getPostIds())) { |
yudao-server/src/main/resources/application-local.yaml
| @@ -6,7 +6,7 @@ spring: | @@ -6,7 +6,7 @@ spring: | ||
| 6 | # 数据源配置项 | 6 | # 数据源配置项 |
| 7 | autoconfigure: | 7 | autoconfigure: |
| 8 | exclude: | 8 | exclude: |
| 9 | - - org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration # 默认 local 环境,不开启 Quartz 的自动配置 | 9 | + #- org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration # 默认 local 环境,不开启 Quartz 的自动配置 |
| 10 | - de.codecentric.boot.admin.server.config.AdminServerAutoConfiguration # 禁用 Spring Boot Admin 的 Server 的自动配置 | 10 | - de.codecentric.boot.admin.server.config.AdminServerAutoConfiguration # 禁用 Spring Boot Admin 的 Server 的自动配置 |
| 11 | - de.codecentric.boot.admin.server.ui.config.AdminServerUiAutoConfiguration # 禁用 Spring Boot Admin 的 Server UI 的自动配置 | 11 | - de.codecentric.boot.admin.server.ui.config.AdminServerUiAutoConfiguration # 禁用 Spring Boot Admin 的 Server UI 的自动配置 |
| 12 | - de.codecentric.boot.admin.client.config.SpringBootAdminClientAutoConfiguration # 禁用 Spring Boot Admin 的 Client 的自动配置 | 12 | - de.codecentric.boot.admin.client.config.SpringBootAdminClientAutoConfiguration # 禁用 Spring Boot Admin 的 Client 的自动配置 |
| @@ -45,7 +45,7 @@ spring: | @@ -45,7 +45,7 @@ spring: | ||
| 45 | primary: master | 45 | primary: master |
| 46 | datasource: | 46 | datasource: |
| 47 | master: | 47 | master: |
| 48 | - url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 | 48 | + url: jdbc:mysql://192.168.10.207:3306/specialty?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 |
| 49 | # url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true # MySQL Connector/J 5.X 连接的示例 | 49 | # url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true # MySQL Connector/J 5.X 连接的示例 |
| 50 | # url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL 连接的示例 | 50 | # url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL 连接的示例 |
| 51 | # url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例 | 51 | # url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例 |
| @@ -61,19 +61,19 @@ spring: | @@ -61,19 +61,19 @@ spring: | ||
| 61 | # password: SYSDBA001 # DM 连接的示例 | 61 | # password: SYSDBA001 # DM 连接的示例 |
| 62 | # username: root # OpenGauss 连接的示例 | 62 | # username: root # OpenGauss 连接的示例 |
| 63 | # password: Yudao@2024 # OpenGauss 连接的示例 | 63 | # password: Yudao@2024 # OpenGauss 连接的示例 |
| 64 | - slave: # 模拟从库,可根据自己需要修改 | ||
| 65 | - lazy: true # 开启懒加载,保证启动速度 | ||
| 66 | - url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true&nullCatalogMeansCurrent=true | ||
| 67 | - username: root | ||
| 68 | - password: 123456 | 64 | +# slave: # 模拟从库,可根据自己需要修改 |
| 65 | +# lazy: true # 开启懒加载,保证启动速度 | ||
| 66 | +# url: jdbc:mysql://192.168.10.207:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true&nullCatalogMeansCurrent=true | ||
| 67 | +# username: root | ||
| 68 | +# password: 123456 | ||
| 69 | 69 | ||
| 70 | # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 | 70 | # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 |
| 71 | data: | 71 | data: |
| 72 | redis: | 72 | redis: |
| 73 | - host: 127.0.0.1 # 地址 | 73 | + host: 192.168.10.207 # 地址 |
| 74 | port: 6379 # 端口 | 74 | port: 6379 # 端口 |
| 75 | database: 0 # 数据库索引 | 75 | database: 0 # 数据库索引 |
| 76 | -# password: dev # 密码,建议生产环境开启 | 76 | + password: 123456 # 密码,建议生产环境开启 |
| 77 | 77 | ||
| 78 | --- #################### 定时任务相关配置 #################### | 78 | --- #################### 定时任务相关配置 #################### |
| 79 | 79 | ||
| @@ -200,8 +200,8 @@ wx: | @@ -200,8 +200,8 @@ wx: | ||
| 200 | # secret: 6f270509224a7ae1296bbf1c8cb97aed | 200 | # secret: 6f270509224a7ae1296bbf1c8cb97aed |
| 201 | # appid: wxc4598c446f8a9cb3 # 测试号(Kongdy 提供的) | 201 | # appid: wxc4598c446f8a9cb3 # 测试号(Kongdy 提供的) |
| 202 | # secret: 4a1a04e07f6a4a0751b39c3064a92c8b | 202 | # secret: 4a1a04e07f6a4a0751b39c3064a92c8b |
| 203 | - appid: wx66186af0759f47c9 # 测试号(puhui 提供的) | ||
| 204 | - secret: 3218bcbd112cbc614c7264ceb20144ac | 203 | + appid: wx9a0a5b259d852380 # 测试号(puhui 提供的) |
| 204 | + secret: 70e65fa9d1a4f2c4e1b2aa8751d3b75e | ||
| 205 | config-storage: | 205 | config-storage: |
| 206 | type: RedisTemplate # 采用 RedisTemplate 操作 Redis,会自动从 Spring 中获取 | 206 | type: RedisTemplate # 采用 RedisTemplate 操作 Redis,会自动从 Spring 中获取 |
| 207 | key-prefix: wa # Redis Key 的前缀 | 207 | key-prefix: wa # Redis Key 的前缀 |