Commit e44c0e668e45e9a7439ea2fe96b02160f79e3ce5
1 parent
e47b3f0a
【功能】完成商品列表价格计算时,需要支持减免金额的功能
Showing
15 changed files
with
350 additions
and
50 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 不存在"); |
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/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/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 com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | ||
| 8 | import org.apache.ibatis.annotations.Mapper; | 10 | import org.apache.ibatis.annotations.Mapper; |
| 9 | 11 | ||
| 10 | import java.time.LocalDateTime; | 12 | import java.time.LocalDateTime; |
| 13 | +import java.util.Collection; | ||
| 11 | import java.util.List; | 14 | import java.util.List; |
| 15 | +import java.util.function.Function; | ||
| 16 | +import java.util.stream.Collectors; | ||
| 12 | 17 | ||
| 13 | /** | 18 | /** |
| 14 | * 满减送活动 Mapper | 19 | * 满减送活动 Mapper |
| @@ -25,13 +30,47 @@ public interface RewardActivityMapper extends BaseMapperX<RewardActivityDO> { | @@ -25,13 +30,47 @@ public interface RewardActivityMapper extends BaseMapperX<RewardActivityDO> { | ||
| 25 | .orderByDesc(RewardActivityDO::getId)); | 30 | .orderByDesc(RewardActivityDO::getId)); |
| 26 | } | 31 | } |
| 27 | 32 | ||
| 33 | + default List<RewardActivityDO> selectListBySpuIdsAndStatus(Collection<Long> spuIds, Integer status) { | ||
| 34 | + Function<Collection<Long>, String> productScopeValuesFindInSetFunc = ids -> ids.stream() | ||
| 35 | + .map(id -> StrUtil.format("FIND_IN_SET({}, product_scope_values) ", id)) | ||
| 36 | + .collect(Collectors.joining(" OR ")); | ||
| 37 | + return selectList(new QueryWrapper<RewardActivityDO>() | ||
| 38 | + .eq("status", status) | ||
| 39 | + .apply(productScopeValuesFindInSetFunc.apply(spuIds))); | ||
| 40 | + } | ||
| 41 | + | ||
| 42 | + /** | ||
| 43 | + * 获取指定活动编号的活动列表且 | ||
| 44 | + * 开始时间和结束时间小于给定时间 dateTime 的活动列表 | ||
| 45 | + * | ||
| 46 | + * @param status 状态 | ||
| 47 | + * @param dateTime 指定日期 | ||
| 48 | + * @return 活动列表 | ||
| 49 | + */ | ||
| 28 | default List<RewardActivityDO> selectListByStatusAndDateTimeLt(Integer status, LocalDateTime dateTime) { | 50 | default List<RewardActivityDO> selectListByStatusAndDateTimeLt(Integer status, LocalDateTime dateTime) { |
| 29 | return selectList(new LambdaQueryWrapperX<RewardActivityDO>() | 51 | return selectList(new LambdaQueryWrapperX<RewardActivityDO>() |
| 30 | .eq(RewardActivityDO::getStatus, status) | 52 | .eq(RewardActivityDO::getStatus, status) |
| 31 | - // 开始时间 < 指定时间(dateTime) < 结束时间,也就是说获取指定时间段的活动 | ||
| 32 | - .lt(RewardActivityDO::getStartTime, dateTime).gt(RewardActivityDO::getEndTime, dateTime) | 53 | + .lt(RewardActivityDO::getStartTime, dateTime) |
| 54 | + .gt(RewardActivityDO::getEndTime, dateTime)// 开始时间 < 指定时间 < 结束时间,也就是说获取指定时间段的活动 | ||
| 33 | .orderByAsc(RewardActivityDO::getStartTime) | 55 | .orderByAsc(RewardActivityDO::getStartTime) |
| 34 | ); | 56 | ); |
| 35 | } | 57 | } |
| 36 | 58 | ||
| 59 | + default List<RewardActivityDO> getRewardActivityByStatusAndDateTimeLt(Collection<Long> spuIds,Collection<Long> categoryIds, Integer status, LocalDateTime dateTime) { | ||
| 60 | + //拼接通用券查询语句 | ||
| 61 | + Function<Collection<Long>, String> productScopeValuesFindInSetFunc = ids -> ids.stream() | ||
| 62 | + .map(id -> StrUtil.format("FIND_IN_SET({}, product_scope_values) ", id)) | ||
| 63 | + .collect(Collectors.joining(" OR ")); | ||
| 64 | + return selectList(new LambdaQueryWrapperX<RewardActivityDO>() | ||
| 65 | + .eq(RewardActivityDO::getStatus,status) | ||
| 66 | + .lt(RewardActivityDO::getStartTime, dateTime) | ||
| 67 | + .gt(RewardActivityDO::getEndTime, dateTime) | ||
| 68 | + .and(i -> i. eq(RewardActivityDO::getProductScope, 2).and(i1 -> i1.apply(productScopeValuesFindInSetFunc.apply(spuIds)))) | ||
| 69 | + .or(i -> i.eq(RewardActivityDO::getProductScope, 1)) | ||
| 70 | + .or(i -> i. eq(RewardActivityDO::getProductScope, 3).and(i1 -> i1.apply(productScopeValuesFindInSetFunc.apply(categoryIds)))) | ||
| 71 | + .orderByDesc(RewardActivityDO::getId) | ||
| 72 | + .last("limit 1") | ||
| 73 | + ); | ||
| 74 | + } | ||
| 75 | + | ||
| 37 | } | 76 | } |
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; |
| @@ -22,8 +23,11 @@ import org.springframework.stereotype.Service; | @@ -22,8 +23,11 @@ import org.springframework.stereotype.Service; | ||
| 22 | import org.springframework.validation.annotation.Validated; | 23 | import org.springframework.validation.annotation.Validated; |
| 23 | 24 | ||
| 24 | import java.time.LocalDateTime; | 25 | import java.time.LocalDateTime; |
| 26 | +import java.util.Collection; | ||
| 27 | +import java.util.Collections; | ||
| 25 | import java.util.List; | 28 | import java.util.List; |
| 26 | import java.util.Objects; | 29 | import java.util.Objects; |
| 30 | +import java.util.stream.Collectors; | ||
| 27 | 31 | ||
| 28 | import static cn.hutool.core.collection.CollUtil.intersectionDistinct; | 32 | import static cn.hutool.core.collection.CollUtil.intersectionDistinct; |
| 29 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 33 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| @@ -205,4 +209,19 @@ public class RewardActivityServiceImpl implements RewardActivityService { | @@ -205,4 +209,19 @@ public class RewardActivityServiceImpl implements RewardActivityService { | ||
| 205 | return rewardActivityMapper.selectListByStatusAndDateTimeLt(status, dateTime); | 209 | return rewardActivityMapper.selectListByStatusAndDateTimeLt(status, dateTime); |
| 206 | } | 210 | } |
| 207 | 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 | + | ||
| 208 | } | 227 | } |
yudao-module-mall/yudao-module-promotion-biz/src/main/resources/mapper/discount/DiscountProductMapper.xml
| @@ -16,7 +16,7 @@ | @@ -16,7 +16,7 @@ | ||
| 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 | 19 | + AND pda.`status` = 0 |
| 20 | AND pda.deleted != 1 | 20 | AND pda.deleted != 1 |
| 21 | </where> | 21 | </where> |
| 22 | </select> | 22 | </select> |
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,51 @@ public class AppTradeOrderController { | @@ -61,6 +88,51 @@ 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 | + if(skuDiscount != null){ | ||
| 104 | + skus.add(skuDiscount); | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + //查询会员价 | ||
| 108 | + AppTradeProductSettlementRespVO.Sku skuVip = calculateVipPrice(sku.getId(), sku.getPrice(), memberLevel); | ||
| 109 | + if(skuVip != null){ | ||
| 110 | + skus.add(skuVip); | ||
| 111 | + } | ||
| 112 | + }); | ||
| 113 | + AppTradeProductSettlementRespVO.Reward reward = calculateReward(spuId); | ||
| 114 | + AppTradeProductSettlementRespVO respVO = AppTradeProductSettlementRespVO.builder().id(spuId).skus(skus).build(); | ||
| 115 | + if(reward != null){ | ||
| 116 | + //创建满减活动对象 | ||
| 117 | + respVO.setReward(reward); | ||
| 118 | + } | ||
| 119 | + appTradeProductSettlementRespVOS.add(respVO); | ||
| 120 | + }); | ||
| 121 | + return success(appTradeProductSettlementRespVOS); | ||
| 122 | + } | ||
| 123 | + | ||
| 124 | + private MemberLevelRespDTO getMemberLevel() { | ||
| 125 | + Long userId = getLoginUserId(); | ||
| 126 | + if (userId == null) { | ||
| 127 | + return null; | ||
| 128 | + } | ||
| 129 | + MemberUserRespDTO user = memberUserApi.getUser(userId); | ||
| 130 | + if (user.getLevelId() == null || user.getLevelId() <= 0) { | ||
| 131 | + return null; | ||
| 132 | + } | ||
| 133 | + return memberLevelApi.getMemberLevel(user.getLevelId()); | ||
| 134 | + } | ||
| 135 | + | ||
| 64 | @PostMapping("/create") | 136 | @PostMapping("/create") |
| 65 | @Operation(summary = "创建订单") | 137 | @Operation(summary = "创建订单") |
| 66 | @PreAuthenticated | 138 | @PreAuthenticated |
| @@ -188,4 +260,78 @@ public class AppTradeOrderController { | @@ -188,4 +260,78 @@ public class AppTradeOrderController { | ||
| 188 | return success(tradeOrderUpdateService.createOrderItemCommentByMember(getLoginUserId(), createReqVO)); | 260 | return success(tradeOrderUpdateService.createOrderItemCommentByMember(getLoginUserId(), createReqVO)); |
| 189 | } | 261 | } |
| 190 | 262 | ||
| 263 | + /** | ||
| 264 | + * 计算会员 VIP 优惠价格 | ||
| 265 | + * | ||
| 266 | + * @param price 原价 | ||
| 267 | + * @param memberLevel 会员等级 | ||
| 268 | + * @return 优惠价格 | ||
| 269 | + */ | ||
| 270 | + public AppTradeProductSettlementRespVO.Sku calculateVipPrice(Long skuId, Integer price, MemberLevelRespDTO memberLevel) { | ||
| 271 | + if (memberLevel == null || memberLevel.getDiscountPercent() == null) { | ||
| 272 | + return null; | ||
| 273 | + } | ||
| 274 | + Integer newPrice = price * memberLevel.getDiscountPercent() / 100; | ||
| 275 | + return AppTradeProductSettlementRespVO.Sku.builder(). | ||
| 276 | + skuId(skuId). | ||
| 277 | + type(PromotionTypeEnum.MEMBER_LEVEL.getType()). | ||
| 278 | + price(price - newPrice).build(); | ||
| 279 | + } | ||
| 280 | + | ||
| 281 | + /** | ||
| 282 | + * 计算限时优惠信息 | ||
| 283 | + * | ||
| 284 | + * @param price 原价 | ||
| 285 | + * @param skuId 商品规格id | ||
| 286 | + * @return 优惠价格 | ||
| 287 | + */ | ||
| 288 | + private AppTradeProductSettlementRespVO.Sku calculateDiscountPrice(Long skuId, Integer price) { | ||
| 289 | + if (skuId == null) { | ||
| 290 | + return null; | ||
| 291 | + } | ||
| 292 | + | ||
| 293 | + //根据商品id查询限时优惠 | ||
| 294 | + List<DiscountProductRespDTO> matchDiscountProductList = discountActivityApi.getMatchDiscountProductList(Collections.singletonList(skuId)); | ||
| 295 | + if (matchDiscountProductList != null && !matchDiscountProductList.isEmpty()) { | ||
| 296 | + DiscountProductRespDTO discountProductRespDTO = matchDiscountProductList.get(matchDiscountProductList.size() - 1); | ||
| 297 | + AppTradeProductSettlementRespVO.Sku sku = AppTradeProductSettlementRespVO.Sku.builder(). | ||
| 298 | + skuId(skuId). | ||
| 299 | + discountId(discountProductRespDTO.getId()). | ||
| 300 | + type(PromotionTypeEnum.DISCOUNT_ACTIVITY.getType()). | ||
| 301 | + endTime(discountProductRespDTO.getActivityEndTime()). | ||
| 302 | + build(); | ||
| 303 | + Integer discountType = discountProductRespDTO.getDiscountType(); | ||
| 304 | + if(Objects.equals(PromotionDiscountTypeEnum.PRICE.getType(), discountType)){ | ||
| 305 | + sku.setPrice(price - discountProductRespDTO.getDiscountPrice() * 100); | ||
| 306 | + }else if(Objects.equals(PromotionDiscountTypeEnum.PERCENT.getType(), discountType)){ | ||
| 307 | + Integer newPrice = price * discountProductRespDTO.getDiscountPercent() / 100; | ||
| 308 | + sku.setPrice(price - newPrice); | ||
| 309 | + }else{ | ||
| 310 | + throw exception(DISCOUNT_ACTIVITY_TYPE_NOT_EXISTS); | ||
| 311 | + } | ||
| 312 | + return sku; | ||
| 313 | + } | ||
| 314 | + return null; | ||
| 315 | + } | ||
| 316 | + | ||
| 317 | + /** | ||
| 318 | + * 获取第一层满减活动 | ||
| 319 | + * | ||
| 320 | + * @param spuId 商品规格id | ||
| 321 | + * @return 优惠价格 | ||
| 322 | + */ | ||
| 323 | + private AppTradeProductSettlementRespVO.Reward calculateReward(Long spuId) { | ||
| 324 | + List<RewardActivityMatchRespDTO> matchRewardActivityList = rewardActivityApi.getRewardActivityBySpuIdsAndStatusAndDateTimeLt(Collections.singletonList(spuId), CommonStatusEnum.ENABLE.getStatus(), LocalDateTime.now()); | ||
| 325 | + if(matchRewardActivityList != null && !matchRewardActivityList.isEmpty()){ | ||
| 326 | + RewardActivityMatchRespDTO rewardActivityMatchRespDTO = matchRewardActivityList.get(matchRewardActivityList.size() - 1); | ||
| 327 | + if(rewardActivityMatchRespDTO != null){ | ||
| 328 | + RewardActivityMatchRespDTO.Rule rule = rewardActivityMatchRespDTO.getRules().get(0); | ||
| 329 | + return AppTradeProductSettlementRespVO.Reward.builder(). | ||
| 330 | + rewardActivity("满" + rule.getLimit() / 100 + (Objects.equals(rewardActivityMatchRespDTO.getConditionType(), PromotionConditionTypeEnum.PRICE.getType())?"元":"件"+"减") +rule.getDiscountPrice() / 100) | ||
| 331 | + .rewardId(rewardActivityMatchRespDTO.getId()).build(); | ||
| 332 | + } | ||
| 333 | + } | ||
| 334 | + return null; | ||
| 335 | + } | ||
| 336 | + | ||
| 191 | } | 337 | } |
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 = "商品编号", 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 | + @Schema(description = "满减活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||
| 32 | + private Long rewardId; | ||
| 33 | + | ||
| 34 | + @Schema(description = "满减活动信息", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||
| 35 | + private String rewardActivity; | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + /** | ||
| 39 | + * SKU 数组 | ||
| 40 | + */ | ||
| 41 | + @Data | ||
| 42 | + @Builder | ||
| 43 | + public static class Sku implements Serializable { | ||
| 44 | + @Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||
| 45 | + private Long skuId; | ||
| 46 | + | ||
| 47 | + @Schema(description = "价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||
| 48 | + private Integer price; | ||
| 49 | + | ||
| 50 | + @Schema(description = "营销类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") //PromotionTypeEnum | ||
| 51 | + private Integer type; | ||
| 52 | + | ||
| 53 | + @Schema(description = "限时优惠id", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 54 | + private Long discountId; | ||
| 55 | + | ||
| 56 | + @Schema(description = "活动结束时间", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 57 | + private LocalDateTime endTime; | ||
| 58 | + } | ||
| 59 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeRewardActivityPriceCalculator.java
| @@ -23,6 +23,7 @@ import java.util.Comparator; | @@ -23,6 +23,7 @@ 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.util.collection.CollectionUtils.convertSet; | ||
| 26 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; | 27 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; |
| 27 | import static cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculatorHelper.formatPrice; | 28 | import static cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculatorHelper.formatPrice; |
| 28 | 29 | ||
| @@ -47,8 +48,8 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator | @@ -47,8 +48,8 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator | ||
| 47 | return; | 48 | return; |
| 48 | } | 49 | } |
| 49 | // 获得 SKU 对应的满减送活动 | 50 | // 获得 SKU 对应的满减送活动 |
| 50 | - List<RewardActivityMatchRespDTO> rewardActivities = rewardActivityApi.getRewardActivityListByStatusAndNow( | ||
| 51 | - CommonStatusEnum.ENABLE.getStatus(), LocalDateTime.now()); | 51 | + List<RewardActivityMatchRespDTO> rewardActivities = rewardActivityApi.getRewardActivityBySpuIdsAndStatusAndDateTimeLt( |
| 52 | + convertSet(result.getItems(), TradePriceCalculateRespBO.OrderItem::getSpuId), CommonStatusEnum.ENABLE.getStatus(), LocalDateTime.now()); | ||
| 52 | if (CollUtil.isEmpty(rewardActivities)) { | 53 | if (CollUtil.isEmpty(rewardActivities)) { |
| 53 | return; | 54 | return; |
| 54 | } | 55 | } |
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 的前缀 |