From a1e9bedf343f05c4cf2f654ca0189db00af561ae Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 3 Oct 2023 21:45:51 +0800 Subject: [PATCH 1/3] =?UTF-8?q?promotion=EF=BC=9A=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E7=A7=92=E6=9D=80=E7=9A=84=20uniapp=20=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/util/date/LocalDateTimeUtils.java | 43 +-------- .../seckill/AppSeckillActivityController.java | 91 ++++++++++++++----- .../seckill/AppSeckillConfigController.java | 5 +- .../AppSeckillActivityDetailRespVO.java | 2 - .../SeckillActivityConvert.java | 41 +++++---- .../dataobject/seckill/SeckillActivityDO.java | 14 +-- .../seckill/SeckillActivityService.java | 8 -- .../seckill/SeckillActivityServiceImpl.java | 45 ++++----- .../service/seckill/SeckillConfigService.java | 8 +- .../seckill/SeckillConfigServiceImpl.java | 11 ++- 10 files changed, 129 insertions(+), 139 deletions(-) diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java index 3ce2a95d3..2674a110e 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java @@ -79,7 +79,8 @@ public class LocalDateTimeUtils { return false; } LocalDate nowDate = LocalDate.now(); - return LocalDateTimeUtil.isIn(LocalDateTime.now(), LocalDateTime.of(nowDate, LocalTime.parse(startTime)), + return LocalDateTimeUtil.isIn(LocalDateTime.now(), + LocalDateTime.of(nowDate, LocalTime.parse(startTime)), LocalDateTime.of(nowDate, LocalTime.parse(endTime))); } @@ -98,46 +99,6 @@ public class LocalDateTimeUtils { LocalDateTime.of(nowDate, startTime2), LocalDateTime.of(nowDate, endTime2)); } - /** - * 构建日期时间 TODO 后面有需要的话再继续扩展 - * - * @author HUIHUI - */ - public static class BuilderDateTime { - - /** - * 日期;2023-10-01 - */ - private String localDate; - /** - * 时间;10:01:00 - */ - private String localTime; - - public BuilderDateTime() { - } - - public BuilderDateTime withDate(String date) { - this.localDate = date; - return this; - } - - public BuilderDateTime withDate(LocalDateTime date) { - this.localDate = LocalDateTimeUtil.format(date, "yyyy-MM-dd"); - return this; - } - - public BuilderDateTime withTime(String time) { - this.localTime = time; - return this; - } - - public LocalDateTime build() { - return LocalDateTimeUtil.parse(this.localDate + " " + this.localTime, "yyyy-MM-dd HH:mm:ss"); - } - - } - /** * 获取指定日期所在的月份的开始时间 * 例如:2023-09-30 00:00:00,000 diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/AppSeckillActivityController.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/AppSeckillActivityController.java index 22e8c2b4e..5e34621e6 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/AppSeckillActivityController.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/AppSeckillActivityController.java @@ -5,6 +5,7 @@ import cn.hutool.core.util.ObjectUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityDetailRespVO; @@ -13,10 +14,12 @@ import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppS import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityRespVO; import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert; import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityDO; -import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillConfigDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO; import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService; import cn.iocoder.yudao.module.promotion.service.seckill.SeckillConfigService; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; @@ -28,16 +31,37 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; +import java.time.Duration; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; import java.util.List; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.cache.CacheUtils.buildAsyncReloadingCache; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.findFirst; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.isBetween; @Tag(name = "用户 App - 秒杀活动") @RestController @RequestMapping("/promotion/seckill-activity") @Validated public class AppSeckillActivityController { + + /** + * {@link AppSeckillActivityNowRespVO} 缓存,通过它异步刷新 {@link #getNowSeckillActivity()} 所要的首页数据 + */ + private final LoadingCache nowSeckillActivityCache = buildAsyncReloadingCache(Duration.ofSeconds(10L), + new CacheLoader() { + + @Override + public AppSeckillActivityNowRespVO load(String key) { + return getNowSeckillActivity0(); + } + + }); + @Resource private SeckillActivityService activityService; @Resource @@ -47,21 +71,25 @@ public class AppSeckillActivityController { @Resource private ProductSpuApi spuApi; - // TODO 芋艿:需要增加 spring cache @GetMapping("/get-now") @Operation(summary = "获得当前秒杀活动", description = "获取当前正在进行的活动,提供给首页使用") public CommonResult getNowSeckillActivity() { + return success(nowSeckillActivityCache.getUnchecked("")); + } + + private AppSeckillActivityNowRespVO getNowSeckillActivity0() { // 1. 获取当前时间处在哪个秒杀阶段 - SeckillConfigDO configList = configService.getSeckillConfigListByStatusOnCurrentTime(CommonStatusEnum.ENABLE.getStatus()); - if (configList == null) { // 时段不存在直接返回 null - return success(null); + SeckillConfigDO config = configService.getCurrentSeckillConfig(); + if (config == null) { // 时段不存在直接返回 null + return new AppSeckillActivityNowRespVO(); } - // 2. 查询满足当前阶段的活动 - List activityList = activityService.getSeckillActivityListByConfigIdAndStatus(configList.getId(), CommonStatusEnum.ENABLE.getStatus()); - // 3 获取 spu 信息 + // 2.1 查询满足当前阶段的活动 + List activityList = activityService.getSeckillActivityListByConfigIdAndStatus(config.getId(), CommonStatusEnum.ENABLE.getStatus()); + List productList = activityService.getSeckillProductListByActivityId(convertList(activityList, SeckillActivityDO::getId)); + // 2.2 获取 spu 信息 List spuList = spuApi.getSpuList(convertList(activityList, SeckillActivityDO::getSpuId)); - return success(SeckillActivityConvert.INSTANCE.convert(configList, activityList, spuList)); + return SeckillActivityConvert.INSTANCE.convert(config, activityList, productList, spuList); } @GetMapping("/page") @@ -72,31 +100,52 @@ public class AppSeckillActivityController { if (CollUtil.isEmpty(pageResult.getList())) { return success(PageResult.empty(pageResult.getTotal())); } + List productList = activityService.getSeckillProductListByActivityId( + convertList(pageResult.getList(), SeckillActivityDO::getId)); + // 2. 拼接数据 List spuList = spuApi.getSpuList(convertList(pageResult.getList(), SeckillActivityDO::getSpuId)); - return success(SeckillActivityConvert.INSTANCE.convertPage(pageResult, spuList)); + return success(SeckillActivityConvert.INSTANCE.convertPage02(pageResult, productList, spuList)); } @GetMapping("/get-detail") @Operation(summary = "获得秒杀活动明细") @Parameter(name = "id", description = "活动编号", required = true, example = "1024") public CommonResult getSeckillActivity(@RequestParam("id") Long id) { - // 1. 获取当前时间处在哪个秒杀阶段 - SeckillConfigDO configList = configService.getSeckillConfigListByStatusOnCurrentTime(CommonStatusEnum.ENABLE.getStatus()); - if (configList == null) { // 时段不存在直接返回 null + // 1. 获取活动 + SeckillActivityDO activity = activityService.getSeckillActivity(id); + if (activity == null + || ObjectUtil.equal(activity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) { return success(null); } - // 2. 获取活动 - SeckillActivityDO seckillActivity = activityService.getSeckillActivity(id); - if (seckillActivity == null - || ObjectUtil.equal(seckillActivity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) { - return success(null); + // 2. 获取时间段 + List configs = configService.getSeckillConfigListByStatus(CommonStatusEnum.ENABLE.getStatus()); + configs.removeIf(config -> !CollUtil.contains(activity.getConfigIds(), config.getId())); + // 2.1 优先使用当前时间段 + SeckillConfigDO config = findFirst(configs, config0 -> isBetween(config0.getStartTime(), config0.getEndTime())); + // 2.2 如果没有,则获取最后一个,因为倾向优先展示“未开始” > “已结束” + if (config == null) { + config = CollUtil.getLast(configs); } + if (config == null) { + return null; + } + // 3. 计算开始时间、结束时间 + LocalDate nowDate; + // 3.1 如果在活动日期范围内,则以今天为 nowDate + if (LocalDateTimeUtils.isBetween(activity.getStartTime(), activity.getEndTime())) { + nowDate = LocalDate.now(); + } else { + // 3.2 如果不在活动时间范围内,则直接以活动的 endTime 作为 nowDate,因为还是倾向优先展示“未开始” > “已结束” + nowDate = activity.getEndTime().toLocalDate(); + } + LocalDateTime startTime = LocalDateTime.of(nowDate, LocalTime.parse(config.getStartTime())); + LocalDateTime endTime = LocalDateTime.of(nowDate, LocalTime.parse(config.getEndTime())); - // 3. 拼接数据 - List productList = activityService.getSeckillProductListByActivityId(seckillActivity.getId()); - return success(SeckillActivityConvert.INSTANCE.convert3(seckillActivity, productList, configList)); + // 4. 拼接数据 + List productList = activityService.getSeckillProductListByActivityId(activity.getId()); + return success(SeckillActivityConvert.INSTANCE.convert3(activity, productList, startTime, endTime)); } } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/AppSeckillConfigController.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/AppSeckillConfigController.java index ec60b2141..12ff30944 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/AppSeckillConfigController.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/AppSeckillConfigController.java @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.config.AppSeckillConfigRespVO; import cn.iocoder.yudao.module.promotion.convert.seckill.seckillconfig.SeckillConfigConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillConfigDO; import cn.iocoder.yudao.module.promotion.service.seckill.SeckillConfigService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -28,8 +29,8 @@ public class AppSeckillConfigController { @GetMapping("/list") @Operation(summary = "获得秒杀时间段列表") public CommonResult> getSeckillConfigList() { - return success(SeckillConfigConvert.INSTANCE.convertList2( - configService.getSeckillConfigListByStatus(CommonStatusEnum.ENABLE.getStatus()))); + List list = configService.getSeckillConfigListByStatus(CommonStatusEnum.ENABLE.getStatus()); + return success(SeckillConfigConvert.INSTANCE.convertList2(list)); } } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/vo/activity/AppSeckillActivityDetailRespVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/vo/activity/AppSeckillActivityDetailRespVO.java index 799b2f8db..ebb5ac54d 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/vo/activity/AppSeckillActivityDetailRespVO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/vo/activity/AppSeckillActivityDetailRespVO.java @@ -19,8 +19,6 @@ public class AppSeckillActivityDetailRespVO { @Schema(description = "活动状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Integer status; - // TODO @芋艿:开始时间、结束时间,要和场次结合起来;就是要算到当前场次,是几点哈; - @Schema(description = "活动开始时间", requiredMode = Schema.RequiredMode.REQUIRED) private LocalDateTime startTime; diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillactivity/SeckillActivityConvert.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillactivity/SeckillActivityConvert.java index 0c9848baa..b15ad53c5 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillactivity/SeckillActivityConvert.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillactivity/SeckillActivityConvert.java @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.collection.MapUtils; -import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils; import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; import cn.iocoder.yudao.module.product.enums.DictTypeConstants; @@ -19,17 +18,18 @@ import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppS import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityRespVO; import cn.iocoder.yudao.module.promotion.convert.seckill.seckillconfig.SeckillConfigConvert; import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityDO; -import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillConfigDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.Mappings; import org.mapstruct.factory.Mappers; +import java.time.LocalDateTime; import java.util.List; import java.util.Map; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; /** @@ -93,16 +93,19 @@ public interface SeckillActivityConvert { List convertList3(List activityList); - default AppSeckillActivityNowRespVO convert(SeckillConfigDO filteredConfig, List activityList, List spuList) { + default AppSeckillActivityNowRespVO convert(SeckillConfigDO filteredConfig, List activityList, + List productList, List spuList) { AppSeckillActivityNowRespVO respVO = new AppSeckillActivityNowRespVO(); respVO.setConfig(SeckillConfigConvert.INSTANCE.convert1(filteredConfig)); Map spuMap = convertMap(spuList, ProductSpuRespDTO::getId); + Map> productMap = convertMultiMap(productList, SeckillProductDO::getActivityId); respVO.setActivities(CollectionUtils.convertList(convertList3(activityList), item -> { - findAndThen(spuMap, item.getSpuId(), spu -> { - item.setPicUrl(spu.getPicUrl()) - .setMarketPrice(spu.getMarketPrice()) - .setUnitName(DictFrameworkUtils.getDictDataLabel(DictTypeConstants.PRODUCT_UNIT, spu.getUnit())); - }); + // product 信息 + item.setSeckillPrice(getMinValue(productMap.get(item.getId()), SeckillProductDO::getSeckillPrice)); + // spu 信息 + findAndThen(spuMap, item.getSpuId(), spu -> + item.setPicUrl(spu.getPicUrl()).setMarketPrice(spu.getMarketPrice()) + .setUnitName(DictFrameworkUtils.getDictDataLabel(DictTypeConstants.PRODUCT_UNIT, spu.getUnit()))); return item; })); return respVO; @@ -110,10 +113,14 @@ public interface SeckillActivityConvert { PageResult convertPage1(PageResult pageResult); - default PageResult convertPage(PageResult pageResult, List spuList) { + default PageResult convertPage02(PageResult pageResult, List productList, List spuList) { PageResult result = convertPage1(pageResult); Map spuMap = convertMap(spuList, ProductSpuRespDTO::getId); + Map> productMap = convertMultiMap(productList, SeckillProductDO::getActivityId); List list = CollectionUtils.convertList(result.getList(), item -> { + // product 信息 + item.setSeckillPrice(getMinValue(productMap.get(item.getId()), SeckillProductDO::getSeckillPrice)); + // spu 信息 findAndThen(spuMap, item.getSpuId(), spu -> item.setPicUrl(spu.getPicUrl()).setMarketPrice(spu.getMarketPrice()) .setUnitName(DictFrameworkUtils.getDictDataLabel(DictTypeConstants.PRODUCT_UNIT, spu.getUnit()))); return item; @@ -126,17 +133,11 @@ public interface SeckillActivityConvert { List convertList1(List products); - default AppSeckillActivityDetailRespVO convert3(SeckillActivityDO seckillActivity, List products, SeckillConfigDO filteredConfig) { - return convert2(seckillActivity) + default AppSeckillActivityDetailRespVO convert3(SeckillActivityDO activity, List products, + LocalDateTime startTime, LocalDateTime endTime) { + return convert2(activity) .setProducts(convertList1(products)) - .setStartTime(new LocalDateTimeUtils.BuilderDateTime() - .withDate(seckillActivity.getStartTime()) - .withTime(filteredConfig.getStartTime()) - .build())// 活动开始日期和时段结合 - .setEndTime(new LocalDateTimeUtils.BuilderDateTime() - .withDate(seckillActivity.getEndTime()) - .withTime(filteredConfig.getEndTime()) - .build()); // 活动结束日期和时段结合 + .setStartTime(startTime).setEndTime(endTime); } List convertList4(List seckillActivityProductList); diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/seckill/SeckillActivityDO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/seckill/SeckillActivityDO.java index a9d897e5c..76a08ac70 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/seckill/SeckillActivityDO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/seckill/SeckillActivityDO.java @@ -66,18 +66,7 @@ public class SeckillActivityDO extends BaseDO { */ @TableField(typeHandler = LongListTypeHandler.class) private List configIds; - /** - * 新增订单数 - */ - private Integer orderCount; - /** - * 付款人数 - */ - private Integer userCount; - /** - * 订单实付金额,单位:分 - */ - private Long totalPrice; + /** * 总限购数量 */ @@ -86,6 +75,7 @@ public class SeckillActivityDO extends BaseDO { * 单次限够数量 */ private Integer singleLimitCount; + /** * 秒杀库存(剩余库存秒杀时扣减) */ diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityService.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityService.java index 0bae0f5e4..fe238a7fb 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityService.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityService.java @@ -89,14 +89,6 @@ public interface SeckillActivityService { */ List getSeckillProductListByActivityId(Collection activityIds); - /** - * 通过活动时段获取秒杀活动 - * - * @param ids 时段配置编号 - * @return 秒杀活动列表 - */ - List getSeckillActivityListByConfigIds(Collection ids); - /** * 通过活动时段编号获取指定 status 的秒杀活动 * diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java index 77394993e..69f1a3134 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java @@ -18,7 +18,6 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityD import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO; import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity.SeckillActivityMapper; import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity.SeckillProductMapper; -import cn.iocoder.yudao.module.promotion.util.PromotionUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -60,17 +59,18 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { @Override @Transactional(rollbackFor = Exception.class) public Long createSeckillActivity(SeckillActivityCreateReqVO createReqVO) { - // 校验商品秒杀时段是否冲突 + // 1.1 校验商品秒杀时段是否冲突 validateProductConflict(createReqVO.getConfigIds(), createReqVO.getSpuId(), null); - // 校验商品是否存在 + // 1.2 校验商品是否存在 validateProductExists(createReqVO.getSpuId(), createReqVO.getProducts()); - // 插入秒杀活动 + // 2.1 插入秒杀活动 SeckillActivityDO activity = SeckillActivityConvert.INSTANCE.convert(createReqVO) - .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getEndTime())) - .setTotalStock(getSumValue(createReqVO.getProducts(), SeckillProductBaseVO::getStock, Integer::sum)); + .setStatus(CommonStatusEnum.ENABLE.getStatus()) + .setStock(getSumValue(createReqVO.getProducts(), SeckillProductBaseVO::getStock, Integer::sum)); + activity.setTotalStock(activity.getStock()); seckillActivityMapper.insert(activity); - // 插入商品 + // 2.2 插入商品 List products = SeckillActivityConvert.INSTANCE.convertList(createReqVO.getProducts(), activity); seckillProductMapper.insertBatch(products); return activity.getId(); @@ -128,22 +128,24 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { @Override @Transactional(rollbackFor = Exception.class) public void updateSeckillActivity(SeckillActivityUpdateReqVO updateReqVO) { - // 校验存在 - SeckillActivityDO seckillActivity = validateSeckillActivityExists(updateReqVO.getId()); - if (CommonStatusEnum.DISABLE.getStatus().equals(seckillActivity.getStatus())) { + // 1.1 校验存在 + SeckillActivityDO activity = validateSeckillActivityExists(updateReqVO.getId()); + if (CommonStatusEnum.DISABLE.getStatus().equals(activity.getStatus())) { throw exception(SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED); } - // 校验商品是否冲突 + // 1.2 校验商品是否冲突 validateProductConflict(updateReqVO.getConfigIds(), updateReqVO.getSpuId(), updateReqVO.getId()); - // 校验商品是否存在 + // 1.3 校验商品是否存在 validateProductExists(updateReqVO.getSpuId(), updateReqVO.getProducts()); - // 更新活动 + // 2.1 更新活动 SeckillActivityDO updateObj = SeckillActivityConvert.INSTANCE.convert(updateReqVO) - .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getEndTime())) - .setTotalStock(getSumValue(updateReqVO.getProducts(), SeckillProductBaseVO::getStock, Integer::sum)); + .setStock(getSumValue(updateReqVO.getProducts(), SeckillProductBaseVO::getStock, Integer::sum)); + if (updateObj.getStock() > activity.getTotalStock()) { // 如果更新的库存大于原来的库存,则更新总库存 + updateObj.setTotalStock(updateObj.getStock()); + } seckillActivityMapper.updateById(updateObj); - // 更新商品 + // 2.2 更新商品 updateSeckillProduct(updateObj, updateReqVO.getProducts()); } @@ -151,7 +153,7 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { @Transactional(rollbackFor = Exception.class) public void updateSeckillStock(Long id, Long skuId, Integer count) { // 1.1 校验活动库存是否充足 - SeckillActivityDO seckillActivity = getSeckillActivity(id); + SeckillActivityDO seckillActivity = validateSeckillActivityExists(id); if (count > seckillActivity.getTotalStock()) { throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL); } @@ -243,7 +245,7 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { @Override public SeckillActivityDO getSeckillActivity(Long id) { - return validateSeckillActivityExists(id); + return seckillActivityMapper.selectById(id); } @Override @@ -261,12 +263,6 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { return seckillProductMapper.selectListByActivityId(activityIds); } - @Override - public List getSeckillActivityListByConfigIds(Collection ids) { - return filterList(seckillActivityMapper.selectList(), - item -> anyMatch(item.getConfigIds(), ids::contains)); - } - @Override public List getSeckillActivityListByConfigIdAndStatus(Long configId, Integer status) { return filterList(seckillActivityMapper.selectList(SeckillActivityDO::getStatus, status), @@ -289,7 +285,6 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { if (CollectionUtil.isEmpty(productList)) { throw exception(SKU_NOT_EXISTS); } - return productList; } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillConfigService.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillConfigService.java index 2c9a233fc..13214e7f8 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillConfigService.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillConfigService.java @@ -54,7 +54,6 @@ public interface SeckillConfigService { */ List getSeckillConfigList(); - /** * 校验秒杀时段是否存在 * @@ -87,11 +86,12 @@ public interface SeckillConfigService { void updateSeckillConfigStatus(Long id, Integer status); /** - * 获取当前日期时间处于的秒杀时段且状态为 status + * 获得当前的秒杀时段 + * + * 要求必须处于开启状态、且在当前时间段内 * - * @param status 状态 * @return 时段 */ - SeckillConfigDO getSeckillConfigListByStatusOnCurrentTime(Integer status); + SeckillConfigDO getCurrentSeckillConfig(); } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillConfigServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillConfigServiceImpl.java index bdfdcca82..c24493bd9 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillConfigServiceImpl.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillConfigServiceImpl.java @@ -17,6 +17,7 @@ import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import java.time.LocalTime; import java.util.Collection; +import java.util.Comparator; import java.util.List; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; @@ -70,9 +71,9 @@ public class SeckillConfigServiceImpl implements SeckillConfigService { } @Override - public SeckillConfigDO getSeckillConfigListByStatusOnCurrentTime(Integer status) { - return findFirst(seckillConfigMapper.selectList(SeckillConfigDO::getStatus, status), - config -> isBetween(config.getStartTime(), config.getEndTime())); + public SeckillConfigDO getCurrentSeckillConfig() { + List list = seckillConfigMapper.selectList(SeckillConfigDO::getStatus, CommonStatusEnum.ENABLE.getStatus()); + return findFirst(list, config -> isBetween(config.getStartTime(), config.getEndTime())); } @Override @@ -151,7 +152,9 @@ public class SeckillConfigServiceImpl implements SeckillConfigService { @Override public List getSeckillConfigListByStatus(Integer status) { - return seckillConfigMapper.selectListByStatus(status); + List list = seckillConfigMapper.selectListByStatus(status); + list.sort(Comparator.comparing(SeckillConfigDO::getStartTime)); + return list; } } From 20f5834d9a284353ce72271cc7453f60d899fd6e Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 4 Oct 2023 00:30:03 +0800 Subject: [PATCH 2/3] =?UTF-8?q?trade=EF=BC=9A=E4=BB=B7=E6=A0=BC=E8=AE=A1?= =?UTF-8?q?=E7=AE=97=E6=97=B6=EF=BC=8C=E6=8E=A5=E5=85=A5=E4=BC=98=E6=83=A0?= =?UTF-8?q?=E5=8A=B5=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/seckill/SeckillActivityApi.java | 17 +++-- .../dto/SeckillActivityProductRespDTO.java | 65 ------------------- .../dto/SeckillValidateJoinRespDTO.java | 27 ++++++++ .../promotion/enums/ErrorCodeConstants.java | 4 ++ .../api/seckill/SeckillActivityApiImpl.java | 9 +-- .../SeckillActivityConvert.java | 4 +- .../SeckillActivityMapper.java | 2 +- .../seckill/SeckillActivityService.java | 12 ++++ .../seckill/SeckillActivityServiceImpl.java | 38 ++++++++++- .../trade/enums/ErrorCodeConstants.java | 1 + .../vo/AppTradeOrderSettlementRespVO.java | 5 +- .../convert/order/TradeOrderConvert.java | 3 +- .../dal/dataobject/order/TradeOrderDO.java | 7 ++ .../dal/mysql/order/TradeOrderItemMapper.java | 15 +++++ .../dal/mysql/order/TradeOrderMapper.java | 6 ++ .../service/order/TradeOrderQueryService.java | 9 +++ .../order/TradeOrderQueryServiceImpl.java | 13 ++++ .../TradeSeckillActivityPriceCalculator.java | 56 +++++++++++----- 18 files changed, 191 insertions(+), 102 deletions(-) delete mode 100644 yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/dto/SeckillActivityProductRespDTO.java create mode 100644 yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/dto/SeckillValidateJoinRespDTO.java diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApi.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApi.java index 6f01d57ba..30b756610 100644 --- a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApi.java +++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApi.java @@ -1,9 +1,6 @@ package cn.iocoder.yudao.module.promotion.api.seckill; -import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityProductRespDTO; - -import java.util.Collection; -import java.util.List; +import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillValidateJoinRespDTO; /** * 秒杀活动 API 接口 @@ -22,12 +19,14 @@ public interface SeckillActivityApi { void updateSeckillStock(Long id, Long skuId, Integer count); /** - * 获取秒杀活动商品信息 + * 校验是否参与秒杀商品 * - * @param id 活动编号 - * @param skuIds sku 编号 - * @return 秒杀活动商品信息列表 + * 如果校验失败,则抛出业务异常 + * + * @param activityId 活动编号 + * @param skuId SKU 编号 + * @param count 数量 */ - List getSeckillActivityProductList(Long id, Collection skuIds); + SeckillValidateJoinRespDTO validateJoinSeckill(Long activityId, Long skuId, Integer count); } diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/dto/SeckillActivityProductRespDTO.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/dto/SeckillActivityProductRespDTO.java deleted file mode 100644 index 5fb0554d3..000000000 --- a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/dto/SeckillActivityProductRespDTO.java +++ /dev/null @@ -1,65 +0,0 @@ -package cn.iocoder.yudao.module.promotion.api.seckill.dto; - -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import lombok.Data; - -import java.time.LocalDateTime; -import java.util.List; - -/** - * 秒杀活动商品 Response DTO - * - * @author HUIHUI - */ -@Data -public class SeckillActivityProductRespDTO { - - /** - * 秒杀参与商品编号 - */ - private Long id; - /** - * 秒杀活动 id - * - * 关联 SeckillActivityDO#getId() - */ - private Long activityId; - /** - * 秒杀时段 id - * - * 关联 SeckillConfigDO#getId() - */ - private List configIds; - /** - * 商品 SPU 编号 - */ - private Long spuId; - /** - * 商品 SKU 编号 - */ - private Long skuId; - /** - * 秒杀金额,单位:分 - */ - private Integer seckillPrice; - /** - * 秒杀库存 - */ - private Integer stock; - - /** - * 秒杀商品状态 - * - * 枚举 {@link CommonStatusEnum 对应的类} - */ - private Integer activityStatus; - /** - * 活动开始时间点 - */ - private LocalDateTime activityStartTime; - /** - * 活动结束时间点 - */ - private LocalDateTime activityEndTime; - -} diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/dto/SeckillValidateJoinRespDTO.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/dto/SeckillValidateJoinRespDTO.java new file mode 100644 index 000000000..aae89a415 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/dto/SeckillValidateJoinRespDTO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.promotion.api.seckill.dto; + +import lombok.Data; + +/** + * 校验参与秒杀 Response DTO + */ +@Data +public class SeckillValidateJoinRespDTO { + + /** + * 秒杀活动名称 + */ + private String name; + /** + * 总限购数量 + * + * 目的:目前只有 trade 有具体下单的数据,需要交给 trade 价格计算使用 + */ + private Integer totalLimitCount; + + /** + * 秒杀金额 + */ + private Integer seckillPrice; + +} diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java index cb0f74f5b..4102c6160 100644 --- a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java +++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java @@ -56,6 +56,10 @@ public interface ErrorCodeConstants { ErrorCode SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1_013_008_004, "秒杀活动未关闭或未结束,不能删除"); ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_008_005, "秒杀活动已关闭,不能重复关闭"); ErrorCode SECKILL_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1_013_008_006, "秒杀失败,原因秒杀库存不足"); + ErrorCode SECKILL_JOIN_ACTIVITY_TIME_ERROR = new ErrorCode(1_013_008_007, "秒杀失败,原因:不在活动时间范围内"); + ErrorCode SECKILL_JOIN_ACTIVITY_STATUS_CLOSED = new ErrorCode(1_013_008_008, "秒杀失败,原因:秒杀活动已关闭"); + ErrorCode SECKILL_JOIN_ACTIVITY_SINGLE_LIMIT_COUNT_EXCEED = new ErrorCode(1_013_008_009, "秒杀失败,原因:单次限购超出"); + ErrorCode SECKILL_JOIN_ACTIVITY_PRODUCT_NOT_EXISTS = new ErrorCode(1_013_008_010, "秒杀失败,原因:商品不存在"); // ========== 秒杀时段 1-013-009-000 ========== ErrorCode SECKILL_CONFIG_NOT_EXISTS = new ErrorCode(1_013_009_000, "秒杀时段不存在"); diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApiImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApiImpl.java index b837dac7e..239cdf4ba 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApiImpl.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApiImpl.java @@ -1,13 +1,10 @@ package cn.iocoder.yudao.module.promotion.api.seckill; -import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityProductRespDTO; -import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert; +import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillValidateJoinRespDTO; import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService; import org.springframework.stereotype.Service; import javax.annotation.Resource; -import java.util.Collection; -import java.util.List; /** * 秒杀活动接口 Api 接口实现类 @@ -26,8 +23,8 @@ public class SeckillActivityApiImpl implements SeckillActivityApi { } @Override - public List getSeckillActivityProductList(Long id, Collection skuIds) { - return SeckillActivityConvert.INSTANCE.convertList4(activityService.getSeckillActivityProductList(id, skuIds)); + public SeckillValidateJoinRespDTO validateJoinSeckill(Long activityId, Long skuId, Integer count) { + return activityService.validateJoinSeckill(activityId, skuId, count); } } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillactivity/SeckillActivityConvert.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillactivity/SeckillActivityConvert.java index b15ad53c5..271a0340f 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillactivity/SeckillActivityConvert.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillactivity/SeckillActivityConvert.java @@ -6,7 +6,7 @@ import cn.iocoder.yudao.framework.common.util.collection.MapUtils; import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils; import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; import cn.iocoder.yudao.module.product.enums.DictTypeConstants; -import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityProductRespDTO; +import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillValidateJoinRespDTO; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityDetailRespVO; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityRespVO; @@ -140,6 +140,6 @@ public interface SeckillActivityConvert { .setStartTime(startTime).setEndTime(endTime); } - List convertList4(List seckillActivityProductList); + SeckillValidateJoinRespDTO convert02(SeckillActivityDO activity, SeckillProductDO product); } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillActivityMapper.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillActivityMapper.java index 668a9e1cf..28f764dae 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillActivityMapper.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillActivityMapper.java @@ -46,7 +46,7 @@ public interface SeckillActivityMapper extends BaseMapperX { .eq(SeckillActivityDO::getId, id) .gt(SeckillActivityDO::getTotalStock, 0) .setSql("stock = stock + " + count) - .setSql("totalStock = totalStock - " + count)); + .setSql("total_stock = total_stock - " + count)); } default PageResult selectPage(AppSeckillActivityPageReqVO pageReqVO, Integer status) { diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityService.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityService.java index fe238a7fb..f5663640f 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityService.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityService.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.promotion.service.seckill; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillValidateJoinRespDTO; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO; @@ -115,4 +116,15 @@ public interface SeckillActivityService { */ List getSeckillActivityProductList(Long id, Collection skuIds); + /** + * 校验是否参与秒杀商品 + * + * 如果校验失败,则抛出业务异常 + * + * @param activityId 活动编号 + * @param skuId SKU 编号 + * @param count 数量 + */ + SeckillValidateJoinRespDTO validateJoinSeckill(Long activityId, Long skuId, Integer count); + } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java index 69f1a3134..671ae4466 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java @@ -4,10 +4,12 @@ import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.ObjectUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; +import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillValidateJoinRespDTO; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO; @@ -15,6 +17,7 @@ import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.Sec import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityPageReqVO; import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert; import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillConfigDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO; import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity.SeckillActivityMapper; import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity.SeckillProductMapper; @@ -277,8 +280,7 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { @Override public List getSeckillActivityProductList(Long id, Collection skuIds) { - // 1、校验秒杀活动是否存在 - validateSeckillActivityExists(id); + // 2、校验活动商品是否存在 List productList = filterList(seckillProductMapper.selectListByActivityId(id), item -> skuIds.contains(item.getSkuId())); @@ -288,4 +290,36 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { return productList; } + @Override + public SeckillValidateJoinRespDTO validateJoinSeckill(Long activityId, Long skuId, Integer count) { + // 1.1 校验秒杀活动是否存在 + SeckillActivityDO activity = validateSeckillActivityExists(activityId); + if (ObjectUtil.notEqual(activity.getStatus(), CommonStatusEnum.ENABLE.getStatus())) { + throw exception(SECKILL_JOIN_ACTIVITY_STATUS_CLOSED); + } + // 1.2 是否在活动时间范围内 + if (!LocalDateTimeUtils.isBetween(activity.getStartTime(), activity.getEndTime())) { + throw exception(SECKILL_JOIN_ACTIVITY_TIME_ERROR); + } + SeckillConfigDO config = seckillConfigService.getCurrentSeckillConfig(); + if (config == null || !CollectionUtil.contains(activity.getConfigIds(), config.getId())) { + throw exception(SECKILL_JOIN_ACTIVITY_TIME_ERROR); + } + // 1.3 超过单次购买限制 + if (count > activity.getSingleLimitCount()) { + throw exception(SECKILL_JOIN_ACTIVITY_SINGLE_LIMIT_COUNT_EXCEED); + } + + // 2.1 校验秒杀商品是否存在 + SeckillProductDO product = seckillProductMapper.selectByActivityIdAndSkuId(activityId, skuId); + if (product == null) { + throw exception(SECKILL_JOIN_ACTIVITY_PRODUCT_NOT_EXISTS); + } + // 2.2 校验库存是否充足 + if (count > product.getStock()) { + throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL); + } + return SeckillActivityConvert.INSTANCE.convert02(activity, product); + } + } diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java index 7539aa22e..d50ff34dc 100644 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java @@ -55,6 +55,7 @@ public interface ErrorCodeConstants { ErrorCode PRICE_CALCULATE_PAY_PRICE_ILLEGAL = new ErrorCode(1_011_003_000, "支付价格计算异常,原因:价格小于等于 0"); ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_TEMPLATE_NOT_FOUND = new ErrorCode(1_011_003_002, "计算快递运费异常,找不到对应的运费模板"); ErrorCode PRICE_CALCULATE_COUPON_NOT_MATCH_NORMAL_ORDER = new ErrorCode(1_011_003_004, "参与秒杀、拼团、砍价的营销商品,无法使用优惠劵"); + ErrorCode PRICE_CALCULATE_SECKILL_TOTAL_LIMIT_COUNT = new ErrorCode(1_011_003_005, "参与秒杀的商品,超过了秒杀总限购数量"); // ========== 物流 Express 模块 1-011-004-000 ========== ErrorCode EXPRESS_NOT_EXISTS = new ErrorCode(1_011_004_000, "快递公司不存在"); diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementRespVO.java index 2ac2f5245..0c851bf34 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementRespVO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementRespVO.java @@ -14,7 +14,7 @@ import java.util.List; public class AppTradeOrderSettlementRespVO { @Schema(description = "交易类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") // 对应 TradeOrderTypeEnum 枚举 - private Integer type = 1; // TODO 芋艿:改成计算 + private Integer type; @Schema(description = "购物项数组", requiredMode = Schema.RequiredMode.REQUIRED) private List items; @@ -75,6 +75,9 @@ public class AppTradeOrderSettlementRespVO { @Schema(description = "商品原价(总),单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "500") private Integer totalPrice; + @Schema(description = "订单优惠(总),单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "66") + private Integer discountPrice; + @Schema(description = "运费金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "50") private Integer deliveryPrice; diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java index b4cdca58c..8f9afbd74 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java @@ -211,7 +211,8 @@ public interface TradeOrderConvert { .setCouponId(settlementReqVO.getCouponId()).setPointStatus(settlementReqVO.getPointStatus()) .setDeliveryType(settlementReqVO.getDeliveryType()).setAddressId(settlementReqVO.getAddressId()) .setPickUpStoreId(settlementReqVO.getPickUpStoreId()) - .setItems(new ArrayList<>(settlementReqVO.getItems().size())); + .setItems(new ArrayList<>(settlementReqVO.getItems().size())) + .setSeckillActivityId(settlementReqVO.getSeckillActivityId()); // 商品项的构建 Map cartMap = convertMap(cartList, CartDO::getId); for (AppTradeOrderSettlementReqVO.Item item : settlementReqVO.getItems()) { diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java index 2909eb432..903f7be40 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java @@ -288,4 +288,11 @@ public class TradeOrderDO extends BaseDO { */ private Integer vipPrice; + /** + * 秒杀活动编号 + * + * 关联 SeckillActivityDO 的 id 字段 + */ + private Long seckillActivityId; + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderItemMapper.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderItemMapper.java index 480fe7ddd..b701b7f87 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderItemMapper.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderItemMapper.java @@ -1,13 +1,19 @@ package cn.iocoder.yudao.module.trade.dal.mysql.order; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; import java.util.Collection; import java.util.List; +import java.util.Map; +import java.util.Set; @Mapper public interface TradeOrderItemMapper extends BaseMapperX { @@ -38,4 +44,13 @@ public interface TradeOrderItemMapper extends BaseMapperX { .eq(TradeOrderItemDO::getCommentStatus, commentStatus)); } + default int selectProductSumByOrderId(@Param("orderIds") Set orderIds) { + // SQL sum 查询 + List> result = selectMaps(new QueryWrapper() + .select("SUM(count) AS sumCount") + .in("order_id", orderIds)); // 只计算选中的 + // 获得数量 + return CollUtil.getFirst(result) != null ? MapUtil.getInt(result.get(0), "sumCount") : 0; + } + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderMapper.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderMapper.java index 743f31baa..22265c9f7 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderMapper.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderMapper.java @@ -82,4 +82,10 @@ public interface TradeOrderMapper extends BaseMapperX { .eq(TradeOrderDO::getCommentStatus, commentStatus)); } + default List selectListByUserIdAndSeckillActivityId(Long userId, Long seckillActivityId) { + return selectList(new LambdaUpdateWrapper<>(TradeOrderDO.class) + .eq(TradeOrderDO::getUserId, userId) + .eq(TradeOrderDO::getSeckillActivityId, seckillActivityId)); + } + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryService.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryService.java index 442f83d3b..70e7a723b 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryService.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryService.java @@ -82,6 +82,15 @@ public interface TradeOrderQueryService { */ List getExpressTrackList(Long id); + /** + * 【会员】在指定秒杀活动下,用户购买的商品数量 + * + * @param userId 用户编号 + * @param activityId 活动编号 + * @return 秒杀商品数量 + */ + int getSeckillProductCount(Long userId, Long activityId); + // =================== Order Item =================== /** diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryServiceImpl.java index c0dfbfd8c..8d24c0a3a 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryServiceImpl.java @@ -13,6 +13,7 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper; import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; import cn.iocoder.yudao.module.trade.framework.delivery.core.client.ExpressClientFactory; import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackQueryReqDTO; import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackRespDTO; @@ -120,6 +121,18 @@ public class TradeOrderQueryServiceImpl implements TradeOrderQueryService { return getExpressTrackList(order); } + @Override + public int getSeckillProductCount(Long userId, Long activityId) { + // 获得订单列表 + List orders = tradeOrderMapper.selectListByUserIdAndSeckillActivityId(userId, activityId); + orders.removeIf(order -> TradeOrderStatusEnum.isCanceled(order.getStatus())); // 过滤掉【已取消】的订单 + if (CollUtil.isEmpty(orders)) { + return 0; + } + // 获得订单项列表 + return tradeOrderItemMapper.selectProductSumByOrderId(convertSet(orders, TradeOrderDO::getId)); + } + // TODO @puhui999:可以加个 spring 缓存,30 分钟;主要考虑及时性要求不高,但是每次调用需要钱; /** * 获得订单的物流轨迹 diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeSeckillActivityPriceCalculator.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeSeckillActivityPriceCalculator.java index 95996ab9f..457419443 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeSeckillActivityPriceCalculator.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeSeckillActivityPriceCalculator.java @@ -1,19 +1,22 @@ package cn.iocoder.yudao.module.trade.service.price.calculator; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.module.promotion.api.seckill.SeckillActivityApi; -import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityProductRespDTO; +import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillValidateJoinRespDTO; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; +import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService; import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import javax.annotation.Resource; -import java.util.List; -import java.util.Map; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.PRICE_CALCULATE_SECKILL_TOTAL_LIMIT_COUNT; +// TODO huihui:单测需要补充 /** * 秒杀活动的 {@link TradePriceCalculator} 实现类 * @@ -24,22 +27,45 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils. public class TradeSeckillActivityPriceCalculator implements TradePriceCalculator { @Resource - private SeckillActivityApi activityApi; + private SeckillActivityApi seckillActivityApi; + + @Resource + private TradeOrderQueryService tradeOrderQueryService; @Override public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { - // 1、判断订单类型和是否具有秒杀活动编号 + // 1. 判断订单类型和是否具有秒杀活动编号 if (param.getSeckillActivityId() == null) { return; } - // 2、获取秒杀活动商品信息 - List productList = activityApi.getSeckillActivityProductList(param.getSeckillActivityId(), convertSet(param.getItems(), - TradePriceCalculateReqBO.Item::getSkuId)); - Map productMap = convertMap(productList, SeckillActivityProductRespDTO::getSkuId); - result.getItems().forEach(item -> { - SeckillActivityProductRespDTO product = productMap.get(item.getSkuId()); - item.setActivityPrice(product.getSeckillPrice()); // 设置活动金额 - }); + Assert.isTrue(param.getItems().size() == 1, "秒杀时,只允许选择一个商品"); + // 2. 校验是否可以参与秒杀 + TradePriceCalculateRespBO.OrderItem orderItem = result.getItems().get(0); + SeckillValidateJoinRespDTO seckillActivity = validateJoinSeckill( + param.getUserId(), param.getSeckillActivityId(), + orderItem.getSkuId(), orderItem.getCount()); + + // 3.1 记录优惠明细 + Integer discountPrice = orderItem.getPayPrice() - seckillActivity.getSeckillPrice(); + TradePriceCalculatorHelper.addPromotion(result, orderItem, + param.getSeckillActivityId(), seckillActivity.getName(), PromotionTypeEnum.SECKILL_ACTIVITY.getType(), + StrUtil.format("秒杀活动:省 {} 元", TradePriceCalculatorHelper.formatPrice(discountPrice)), + discountPrice); + // 3.2 更新 SKU 优惠金额 + orderItem.setDiscountPrice(orderItem.getDiscountPrice() + discountPrice); + TradePriceCalculatorHelper.recountPayPrice(orderItem); + TradePriceCalculatorHelper.recountAllPrice(result); + } + + private SeckillValidateJoinRespDTO validateJoinSeckill(Long userId, Long activityId, Long skuId, Integer count) { + // 1. 校验是否可以参与秒杀 + SeckillValidateJoinRespDTO seckillActivity = seckillActivityApi.validateJoinSeckill(activityId, skuId, count); + // 2. 校验总限购数量,目前只有 trade 有具体下单的数据,需要交给 trade 价格计算使用 + int seckillProductCount = tradeOrderQueryService.getSeckillProductCount(userId, activityId); + if (seckillProductCount + count > seckillActivity.getTotalLimitCount()) { + throw exception(PRICE_CALCULATE_SECKILL_TOTAL_LIMIT_COUNT); + } + return seckillActivity; } } From dc1347184fba2f5feec1a86fe34c35f48c9b3ee5 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 4 Oct 2023 00:47:17 +0800 Subject: [PATCH 3/3] =?UTF-8?q?code=20review=EF=BC=9A=E6=8B=BC=E5=9B=A2?= =?UTF-8?q?=E3=80=81=E7=A0=8D=E4=BB=B7=E6=B4=BB=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CombinationRecordServiceImpl.java | 3 ++ .../module/trade/api/order/TradeOrderApi.java | 1 + .../vo/AppTradeOrderSettlementReqVO.java | 3 +- .../order/handler/TradeBargainHandler.java | 2 +- .../handler/TradeCombinationHandler.java | 2 +- .../handler/TradeOrderDefaultHandler.java | 34 ------------------- .../order/handler/TradeOrderHandler.java | 8 ++--- .../order/handler/TradeSeckillHandler.java | 2 +- .../price/bo/TradePriceCalculateRespBO.java | 19 +---------- .../TradePriceCalculatorHelper.java | 3 -- .../TradeSeckillActivityPriceCalculator.java | 2 +- 11 files changed, 15 insertions(+), 64 deletions(-) delete mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeOrderDefaultHandler.java diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java index e56271445..eef7d5992 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java @@ -102,6 +102,7 @@ public class CombinationRecordServiceImpl implements CombinationRecordService { return recordDO; } + // TODO @芋艿:在详细预览下; @Override public void validateCombinationRecord(Long activityId, Long userId, Long skuId, Integer count) { // 1.1 校验拼团活动是否存在 @@ -132,12 +133,14 @@ public class CombinationRecordServiceImpl implements CombinationRecordService { } // 5.1、查询关联的订单是否已经支付 // 当前 activityId 已经有未支付的订单,不允许在发起新的;要么支付,要么去掉先; + // TODO 芋艿:看看是不是可以删除掉; Integer orderStatus = tradeOrderApi.getOrderStatus(record.getOrderId()); if (ObjectUtil.equal(orderStatus, TradeOrderStatusEnum.UNPAID.getStatus())) { throw exception(COMBINATION_RECORD_FAILED_ORDER_STATUS_UNPAID); } } + // TODO 芋艿:在详细 review 下; @Override @Transactional(rollbackFor = Exception.class) public void createCombinationRecord(CombinationRecordCreateReqDTO reqDTO) { diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApi.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApi.java index d1f49cd80..643ed88fb 100644 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApi.java +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApi.java @@ -7,6 +7,7 @@ package cn.iocoder.yudao.module.trade.api.order; */ public interface TradeOrderApi { + // TODO 芋艿:看看是不是可以删除掉; /** * 获取订单状态 * diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementReqVO.java index 06b7f11fb..1ce00ab26 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementReqVO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementReqVO.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.trade.controller.app.order.vo; +import cn.hutool.core.util.ObjUtil; import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.framework.common.validation.Mobile; import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; @@ -67,7 +68,7 @@ public class AppTradeOrderSettlementReqVO { @JsonIgnore public boolean isValidActivityItems() { // 校验是否是活动订单 - if (seckillActivityId == null && combinationActivityId == null && combinationHeadId == null) { + if (ObjUtil.isAllEmpty(seckillActivityId, combinationActivityId, combinationHeadId)) { return true; } // 校验订单项是否超出 diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeBargainHandler.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeBargainHandler.java index 4f5dc15e6..29082a2c4 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeBargainHandler.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeBargainHandler.java @@ -14,7 +14,7 @@ import javax.annotation.Resource; * @author HUIHUI */ @Component -public class TradeBargainHandler extends TradeOrderDefaultHandler { +public class TradeBargainHandler implements TradeOrderHandler { @Resource private BargainActivityApi bargainActivityApi; diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeCombinationHandler.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeCombinationHandler.java index 3887f97a9..e8757ee22 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeCombinationHandler.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeCombinationHandler.java @@ -17,7 +17,7 @@ import javax.annotation.Resource; * @author HUIHUI */ @Component -public class TradeCombinationHandler extends TradeOrderDefaultHandler { +public class TradeCombinationHandler implements TradeOrderHandler { @Resource private CombinationRecordApi combinationRecordApi; diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeOrderDefaultHandler.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeOrderDefaultHandler.java deleted file mode 100644 index 824ad803c..000000000 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeOrderDefaultHandler.java +++ /dev/null @@ -1,34 +0,0 @@ -package cn.iocoder.yudao.module.trade.service.order.handler; - -import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO; -import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterPayOrderReqBO; -import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO; - -/** - * 订单活动特殊逻辑处理器 handler 默认抽象实现类 - * - * @author HUIHUI - */ -public abstract class TradeOrderDefaultHandler implements TradeOrderHandler { - - @Override - public void beforeOrderCreate(TradeBeforeOrderCreateReqBO reqBO) { - - } - - @Override - public void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO) { - - } - - @Override - public void afterPayOrder(TradeAfterPayOrderReqBO reqBO) { - - } - - @Override - public void cancelOrder() { - - } - -} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeOrderHandler.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeOrderHandler.java index 5429b1add..190be6c32 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeOrderHandler.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeOrderHandler.java @@ -17,25 +17,25 @@ public interface TradeOrderHandler { * * @param reqBO 请求 */ - void beforeOrderCreate(TradeBeforeOrderCreateReqBO reqBO); + default void beforeOrderCreate(TradeBeforeOrderCreateReqBO reqBO) {} /** * 订单创建后 * * @param reqBO 请求 */ - void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO); + default void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO) {} /** * 支付订单后 * * @param reqBO 请求 */ - void afterPayOrder(TradeAfterPayOrderReqBO reqBO); + default void afterPayOrder(TradeAfterPayOrderReqBO reqBO) {} /** * 订单取消 */ - void cancelOrder(); + default void cancelOrder() {} } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeSeckillHandler.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeSeckillHandler.java index c7d89037b..50d683114 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeSeckillHandler.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeSeckillHandler.java @@ -14,7 +14,7 @@ import javax.annotation.Resource; * @author HUIHUI */ @Component -public class TradeSeckillHandler extends TradeOrderDefaultHandler { +public class TradeSeckillHandler implements TradeOrderHandler { @Resource private SeckillActivityApi seckillActivityApi; diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateRespBO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateRespBO.java index 0527a120e..af73332de 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateRespBO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateRespBO.java @@ -98,19 +98,9 @@ public class TradePriceCalculateRespBO { * VIP 减免金额,单位:分 */ private Integer vipPrice; - /** - * 秒杀、拼团、砍价活动商品的总金额,单位:分 - * - * 基于 {@link OrderItem#getActivityPrice()} ()} * {@link OrderItem#getCount()} 求和 - */ - private Integer activityPrice; /** * 最终购买金额(总),单位:分 * - * ==========活动情况=========== - * = {@link #activityPrice} - * + {@link #deliveryPrice} - * ==========正常情况=========== * = {@link #totalPrice} * - {@link #couponPrice} * - {@link #pointPrice} @@ -186,16 +176,9 @@ public class TradePriceCalculateRespBO { * VIP 减免金额,单位:分 */ private Integer vipPrice; - /** - * 秒杀、拼团、砍价活动商品的金额,单位:分 - */ - private Integer activityPrice; /** * 应付金额(总),单位:分 - * ==========活动情况=========== - * = {@link #activityPrice} * {@link #count} - * + {@link #deliveryPrice} - * ==========正常情况=========== + * * = {@link #price} * {@link #count} * - {@link #couponPrice} * - {@link #pointPrice} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java index aed6a8f22..efe96f876 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java @@ -105,9 +105,6 @@ public class TradePriceCalculatorHelper { if (!item.getSelected()) { return; } - // TODO puhui: 需要在这里计算活动的价格 - // ========== 一、活动情况 ========== - // ========== 二、正常情况 ========== price.setTotalPrice(price.getTotalPrice() + item.getPrice() * item.getCount()); price.setDiscountPrice(price.getDiscountPrice() + item.getDiscountPrice()); price.setDeliveryPrice(price.getDeliveryPrice() + item.getDeliveryPrice()); diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeSeckillActivityPriceCalculator.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeSeckillActivityPriceCalculator.java index 457419443..10cd235ee 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeSeckillActivityPriceCalculator.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeSeckillActivityPriceCalculator.java @@ -46,7 +46,7 @@ public class TradeSeckillActivityPriceCalculator implements TradePriceCalculator orderItem.getSkuId(), orderItem.getCount()); // 3.1 记录优惠明细 - Integer discountPrice = orderItem.getPayPrice() - seckillActivity.getSeckillPrice(); + Integer discountPrice = orderItem.getPayPrice() - seckillActivity.getSeckillPrice() * orderItem.getCount(); TradePriceCalculatorHelper.addPromotion(result, orderItem, param.getSeckillActivityId(), seckillActivity.getName(), PromotionTypeEnum.SECKILL_ACTIVITY.getType(), StrUtil.format("秒杀活动:省 {} 元", TradePriceCalculatorHelper.formatPrice(discountPrice)),