Commit 0b35d4a7e3c55b29b2153f00285a31c6b5ecad8c
1 parent
5ecd0d94
订单:完善拼团活动部分 TODO
Showing
16 changed files
with
179 additions
and
102 deletions
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java
| ... | ... | @@ -93,4 +93,44 @@ public class LocalDateTimeUtils { |
| 93 | 93 | LocalDateTime.of(nowDate, startTime2), LocalDateTime.of(nowDate, endTime2)); |
| 94 | 94 | } |
| 95 | 95 | |
| 96 | + /** | |
| 97 | + * 构建日期时间 TODO 后面有需要的话再继续扩展 | |
| 98 | + * | |
| 99 | + * @author HUIHUI | |
| 100 | + */ | |
| 101 | + public static class BuilderDateTime { | |
| 102 | + | |
| 103 | + /** | |
| 104 | + * 日期;2023-10-01 | |
| 105 | + */ | |
| 106 | + private String localDate; | |
| 107 | + /** | |
| 108 | + * 时间;10:01:00 | |
| 109 | + */ | |
| 110 | + private String localTime; | |
| 111 | + | |
| 112 | + public BuilderDateTime() { | |
| 113 | + } | |
| 114 | + | |
| 115 | + public BuilderDateTime withDate(String date) { | |
| 116 | + this.localDate = date; | |
| 117 | + return this; | |
| 118 | + } | |
| 119 | + | |
| 120 | + public BuilderDateTime withDate(LocalDateTime date) { | |
| 121 | + this.localDate = LocalDateTimeUtil.format(date, "yyyy-MM-dd"); | |
| 122 | + return this; | |
| 123 | + } | |
| 124 | + | |
| 125 | + public BuilderDateTime withTime(String time) { | |
| 126 | + this.localTime = time; | |
| 127 | + return this; | |
| 128 | + } | |
| 129 | + | |
| 130 | + public LocalDateTime build() { | |
| 131 | + return LocalDateTimeUtil.parse(this.localDate + " " + this.localTime, "yyyy-MM-dd HH:mm:ss"); | |
| 132 | + } | |
| 133 | + | |
| 134 | + } | |
| 135 | + | |
| 96 | 136 | } | ... | ... |
yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentServiceImplTest.java
| ... | ... | @@ -16,7 +16,6 @@ import cn.iocoder.yudao.module.product.dal.mysql.comment.ProductCommentMapper; |
| 16 | 16 | import cn.iocoder.yudao.module.product.enums.comment.ProductCommentScoresEnum; |
| 17 | 17 | import cn.iocoder.yudao.module.product.service.sku.ProductSkuService; |
| 18 | 18 | import cn.iocoder.yudao.module.product.service.spu.ProductSpuService; |
| 19 | -import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi; | |
| 20 | 19 | import org.junit.jupiter.api.Test; |
| 21 | 20 | import org.springframework.boot.test.mock.mockito.MockBean; |
| 22 | 21 | import org.springframework.context.annotation.Import; |
| ... | ... | @@ -49,8 +48,6 @@ public class ProductCommentServiceImplTest extends BaseDbUnitTest { |
| 49 | 48 | private ProductCommentServiceImpl productCommentService; |
| 50 | 49 | |
| 51 | 50 | @MockBean |
| 52 | - private TradeOrderApi tradeOrderApi; | |
| 53 | - @MockBean | |
| 54 | 51 | private ProductSpuService productSpuService; |
| 55 | 52 | @MockBean |
| 56 | 53 | private ProductSkuService productSkuService; | ... | ... |
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationActivityApi.java
| ... | ... | @@ -7,14 +7,4 @@ package cn.iocoder.yudao.module.promotion.api.combination; |
| 7 | 7 | */ |
| 8 | 8 | public interface CombinationActivityApi { |
| 9 | 9 | |
| 10 | - /** | |
| 11 | - * 校验是否满足拼团条件 | |
| 12 | - * | |
| 13 | - * @param activityId 活动编号 | |
| 14 | - * @param userId 用户编号 | |
| 15 | - * @param skuId sku 编号 | |
| 16 | - * @param count 数量 | |
| 17 | - */ | |
| 18 | - void validateCombination(Long activityId, Long userId, Long skuId, Integer count); | |
| 19 | - | |
| 20 | 10 | } | ... | ... |
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApi.java
| ... | ... | @@ -15,6 +15,16 @@ import java.time.LocalDateTime; |
| 15 | 15 | public interface CombinationRecordApi { |
| 16 | 16 | |
| 17 | 17 | /** |
| 18 | + * 校验是否满足拼团条件 | |
| 19 | + * | |
| 20 | + * @param activityId 活动编号 | |
| 21 | + * @param userId 用户编号 | |
| 22 | + * @param skuId sku 编号 | |
| 23 | + * @param count 数量 | |
| 24 | + */ | |
| 25 | + void validateCombinationRecord(Long activityId, Long userId, Long skuId, Integer count); | |
| 26 | + | |
| 27 | + /** | |
| 18 | 28 | * 创建开团记录 |
| 19 | 29 | * |
| 20 | 30 | * @param reqDTO 请求 DTO | ... | ... |
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
| ... | ... | @@ -75,9 +75,10 @@ public interface ErrorCodeConstants { |
| 75 | 75 | ErrorCode COMBINATION_RECORD_HEAD_NOT_EXISTS = new ErrorCode(1013011002, "拼团失败,父拼团不存在"); |
| 76 | 76 | ErrorCode COMBINATION_RECORD_USER_FULL = new ErrorCode(1013011003, "拼团失败,拼团人数已满"); |
| 77 | 77 | ErrorCode COMBINATION_RECORD_FAILED_HAVE_JOINED = new ErrorCode(1013011004, "拼团失败,已参与其它拼团"); |
| 78 | - ErrorCode COMBINATION_RECORD_FAILED_TIME_END = new ErrorCode(1013011005, "拼团失败,活动已经结束"); | |
| 79 | - ErrorCode COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED = new ErrorCode(1013011006, "拼团失败,原因:单次限购超出"); | |
| 80 | - ErrorCode COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED = new ErrorCode(1013011007, "拼团失败,原因:超出总购买次数"); | |
| 78 | + ErrorCode COMBINATION_RECORD_FAILED_TIME_NOT_START = new ErrorCode(1013011005, "拼团失败,活动未开始"); | |
| 79 | + ErrorCode COMBINATION_RECORD_FAILED_TIME_END = new ErrorCode(1013011006, "拼团失败,活动已经结束"); | |
| 80 | + ErrorCode COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED = new ErrorCode(1013011007, "拼团失败,原因:单次限购超出"); | |
| 81 | + ErrorCode COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED = new ErrorCode(1013011008, "拼团失败,原因:超出总购买次数"); | |
| 81 | 82 | |
| 82 | 83 | // ========== 砍价活动 1013012000 ========== |
| 83 | 84 | ErrorCode BARGAIN_ACTIVITY_NOT_EXISTS = new ErrorCode(1013012000, "砍价活动不存在"); | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationActivityApiImpl.java
| 1 | 1 | package cn.iocoder.yudao.module.promotion.api.combination; |
| 2 | 2 | |
| 3 | -import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService; | |
| 4 | 3 | import org.springframework.stereotype.Service; |
| 5 | 4 | |
| 6 | -import javax.annotation.Resource; | |
| 7 | - | |
| 8 | 5 | /** |
| 9 | 6 | * 拼团活动 Api 接口实现类 |
| 10 | 7 | * |
| ... | ... | @@ -13,12 +10,4 @@ import javax.annotation.Resource; |
| 13 | 10 | @Service |
| 14 | 11 | public class CombinationActivityApiImpl implements CombinationActivityApi { |
| 15 | 12 | |
| 16 | - @Resource | |
| 17 | - private CombinationActivityService activityService; | |
| 18 | - | |
| 19 | - @Override | |
| 20 | - public void validateCombination(Long activityId, Long userId, Long skuId, Integer count) { | |
| 21 | - activityService.validateCombination(activityId, userId, skuId, count); | |
| 22 | - } | |
| 23 | - | |
| 24 | 13 | } | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApiImpl.java
| ... | ... | @@ -20,6 +20,11 @@ public class CombinationRecordApiImpl implements CombinationRecordApi { |
| 20 | 20 | private CombinationRecordService recordService; |
| 21 | 21 | |
| 22 | 22 | @Override |
| 23 | + public void validateCombinationRecord(Long activityId, Long userId, Long skuId, Integer count) { | |
| 24 | + recordService.validateCombinationRecord(activityId, userId, skuId, count); | |
| 25 | + } | |
| 26 | + | |
| 27 | + @Override | |
| 23 | 28 | public void createCombinationRecord(CombinationRecordCreateReqDTO reqDTO) { |
| 24 | 29 | recordService.createCombinationRecord(reqDTO); |
| 25 | 30 | } | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillactivity/SeckillActivityConvert.java
| 1 | 1 | package cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity; |
| 2 | 2 | |
| 3 | -import cn.hutool.core.date.LocalDateTimeUtil; | |
| 4 | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | 4 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; |
| 6 | 5 | import cn.iocoder.yudao.framework.common.util.collection.MapUtils; |
| 6 | +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; | |
| 7 | 7 | import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils; |
| 8 | 8 | import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; |
| 9 | 9 | import cn.iocoder.yudao.module.product.enums.DictTypeConstants; |
| ... | ... | @@ -129,11 +129,14 @@ public interface SeckillActivityConvert { |
| 129 | 129 | default AppSeckillActivityDetailRespVO convert3(SeckillActivityDO seckillActivity, List<SeckillProductDO> products, SeckillConfigDO filteredConfig) { |
| 130 | 130 | return convert2(seckillActivity) |
| 131 | 131 | .setProducts(convertList1(products)) |
| 132 | - // TODO @puhui999:要不要在里面 default 一个方法,处理这个事件;简洁一点; | |
| 133 | - .setStartTime(LocalDateTimeUtil.parse(LocalDateTimeUtil.format(seckillActivity.getStartTime(), "yyyy-MM-dd") + " " + filteredConfig.getStartTime(), | |
| 134 | - "yyyy-MM-dd HH:mm:ss")) // 活动开始日期和时段结合 | |
| 135 | - .setEndTime(LocalDateTimeUtil.parse(LocalDateTimeUtil.format(seckillActivity.getEndTime(), "yyyy-MM-dd") + " " + filteredConfig.getEndTime(), | |
| 136 | - "yyyy-MM-dd HH:mm:ss")); // 活动结束日期和时段结合 | |
| 132 | + .setStartTime(new LocalDateTimeUtils.BuilderDateTime() | |
| 133 | + .withDate(seckillActivity.getStartTime()) | |
| 134 | + .withTime(filteredConfig.getStartTime()) | |
| 135 | + .build())// 活动开始日期和时段结合 | |
| 136 | + .setEndTime(new LocalDateTimeUtils.BuilderDateTime() | |
| 137 | + .withDate(seckillActivity.getEndTime()) | |
| 138 | + .withTime(filteredConfig.getEndTime()) | |
| 139 | + .build()); // 活动结束日期和时段结合 | |
| 137 | 140 | } |
| 138 | 141 | |
| 139 | 142 | List<SeckillActivityProductRespDTO> convertList4(List<SeckillProductDO> seckillActivityProductList); | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/CombinationRecordMapper.java
| ... | ... | @@ -20,6 +20,10 @@ public interface CombinationRecordMapper extends BaseMapperX<CombinationRecordDO |
| 20 | 20 | CombinationRecordDO::getOrderId, orderId); |
| 21 | 21 | } |
| 22 | 22 | |
| 23 | + default List<CombinationRecordDO> selectListByUserId(Long userId) { | |
| 24 | + return selectList(CombinationRecordDO::getUserId, userId); | |
| 25 | + } | |
| 26 | + | |
| 23 | 27 | default List<CombinationRecordDO> selectListByUserIdAndStatus(Long userId, Integer status) { |
| 24 | 28 | return selectList(new LambdaQueryWrapperX<CombinationRecordDO>() |
| 25 | 29 | .eq(CombinationRecordDO::getUserId, userId) | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityService.java
| ... | ... | @@ -85,17 +85,6 @@ public interface CombinationActivityService { |
| 85 | 85 | List<CombinationProductDO> getCombinationProductsByActivityIds(Collection<Long> activityIds); |
| 86 | 86 | |
| 87 | 87 | /** |
| 88 | - * 校验是否满足拼团条件 | |
| 89 | - * 如果不满足,会抛出异常 | |
| 90 | - * | |
| 91 | - * @param activityId 活动编号 | |
| 92 | - * @param userId 用户编号 | |
| 93 | - * @param skuId sku 编号 | |
| 94 | - * @param count 数量 | |
| 95 | - */ | |
| 96 | - void validateCombination(Long activityId, Long userId, Long skuId, Integer count); | |
| 97 | - | |
| 98 | - /** | |
| 99 | 88 | * 获取正在进行的活动分页数据 |
| 100 | 89 | * |
| 101 | 90 | * @param count 需要的数量 | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityServiceImpl.java
| ... | ... | @@ -17,12 +17,8 @@ import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product |
| 17 | 17 | import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert; |
| 18 | 18 | import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO; |
| 19 | 19 | import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO; |
| 20 | -import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO; | |
| 21 | 20 | import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationActivityMapper; |
| 22 | 21 | import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationProductMapper; |
| 23 | -import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum; | |
| 24 | -import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi; | |
| 25 | -import org.springframework.context.annotation.Lazy; | |
| 26 | 22 | import org.springframework.stereotype.Service; |
| 27 | 23 | import org.springframework.transaction.annotation.Transactional; |
| 28 | 24 | import org.springframework.validation.annotation.Validated; |
| ... | ... | @@ -33,7 +29,8 @@ import java.util.List; |
| 33 | 29 | import java.util.Map; |
| 34 | 30 | |
| 35 | 31 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 36 | -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; | |
| 32 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; | |
| 33 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; | |
| 37 | 34 | import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS; |
| 38 | 35 | import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS; |
| 39 | 36 | import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; |
| ... | ... | @@ -54,15 +51,9 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic |
| 54 | 51 | private CombinationProductMapper combinationProductMapper; |
| 55 | 52 | |
| 56 | 53 | @Resource |
| 57 | - @Lazy // TODO @puhui999:我感觉 validateCombination 可以挪到 CombinationRecordServiceImpl 中,因为它更偏向能不能创建拼团记录; | |
| 58 | - private CombinationRecordService combinationRecordService; | |
| 59 | - | |
| 60 | - @Resource | |
| 61 | 54 | private ProductSpuApi productSpuApi; |
| 62 | 55 | @Resource |
| 63 | 56 | private ProductSkuApi productSkuApi; |
| 64 | - @Resource | |
| 65 | - private TradeOrderApi tradeOrderApi; | |
| 66 | 57 | |
| 67 | 58 | @Override |
| 68 | 59 | @Transactional(rollbackFor = Exception.class) |
| ... | ... | @@ -216,36 +207,6 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic |
| 216 | 207 | } |
| 217 | 208 | |
| 218 | 209 | @Override |
| 219 | - public void validateCombination(Long activityId, Long userId, Long skuId, Integer count) { | |
| 220 | - // 1.1 校验拼团活动是否存在 | |
| 221 | - CombinationActivityDO activity = validateCombinationActivityExists(activityId); | |
| 222 | - // 1.2 校验活动是否开启 | |
| 223 | - if (ObjectUtil.equal(activity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) { | |
| 224 | - throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE); | |
| 225 | - } | |
| 226 | - // 1.3 校验是否超出单次限购数量 | |
| 227 | - if (count > activity.getSingleLimitCount()) { | |
| 228 | - throw exception(COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED); | |
| 229 | - } | |
| 230 | - | |
| 231 | - // 2. 校验是否超出总限购数量 | |
| 232 | - List<CombinationRecordDO> recordList = combinationRecordService.getRecordListByUserIdAndActivityId(userId, activityId); | |
| 233 | - if (CollUtil.isEmpty(recordList)) { | |
| 234 | - return; | |
| 235 | - } | |
| 236 | - // 过滤出拼团成功的 | |
| 237 | - // TODO @puhui999:count 要不存一个在 record 里? | |
| 238 | - List<Long> skuIds = convertList(recordList, CombinationRecordDO::getSkuId, | |
| 239 | - item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())); | |
| 240 | - Integer countSum = tradeOrderApi.getOrderItemCountSumByOrderIdAndSkuId(convertList(recordList, | |
| 241 | - CombinationRecordDO::getOrderId, | |
| 242 | - item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), skuIds); | |
| 243 | - if (activity.getTotalLimitCount() < countSum) { | |
| 244 | - throw exception(COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED); | |
| 245 | - } | |
| 246 | - } | |
| 247 | - | |
| 248 | - @Override | |
| 249 | 210 | public List<CombinationActivityDO> getCombinationActivityListByCount(Integer count) { |
| 250 | 211 | return combinationActivityMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus(), count); |
| 251 | 212 | } | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordService.java
| ... | ... | @@ -23,6 +23,17 @@ public interface CombinationRecordService { |
| 23 | 23 | void updateCombinationRecordStatusByUserIdAndOrderId(Integer status, Long userId, Long orderId); |
| 24 | 24 | |
| 25 | 25 | /** |
| 26 | + * 校验是否满足拼团条件 | |
| 27 | + * 如果不满足,会抛出异常 | |
| 28 | + * | |
| 29 | + * @param activityId 活动编号 | |
| 30 | + * @param userId 用户编号 | |
| 31 | + * @param skuId sku 编号 | |
| 32 | + * @param count 数量 | |
| 33 | + */ | |
| 34 | + void validateCombinationRecord(Long activityId, Long userId, Long skuId, Integer count); | |
| 35 | + | |
| 36 | + /** | |
| 26 | 37 | * 创建拼团记录 |
| 27 | 38 | * |
| 28 | 39 | * @param reqDTO 创建信息 | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java
| ... | ... | @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.promotion.service.combination; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | 4 | import cn.hutool.core.util.ObjectUtil; |
| 5 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | |
| 5 | 6 | import cn.iocoder.yudao.module.member.api.user.MemberUserApi; |
| 6 | 7 | import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; |
| 7 | 8 | import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; |
| ... | ... | @@ -14,6 +15,7 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationA |
| 14 | 15 | import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO; |
| 15 | 16 | import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationRecordMapper; |
| 16 | 17 | import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum; |
| 18 | +import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi; | |
| 17 | 19 | import org.springframework.context.annotation.Lazy; |
| 18 | 20 | import org.springframework.stereotype.Service; |
| 19 | 21 | import org.springframework.transaction.annotation.Transactional; |
| ... | ... | @@ -24,6 +26,7 @@ import java.time.LocalDateTime; |
| 24 | 26 | import java.util.List; |
| 25 | 27 | |
| 26 | 28 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 29 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | |
| 27 | 30 | import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; |
| 28 | 31 | |
| 29 | 32 | // TODO 芋艿:等拼团记录做完,完整 review 下 |
| ... | ... | @@ -51,6 +54,8 @@ public class CombinationRecordServiceImpl implements CombinationRecordService { |
| 51 | 54 | @Resource |
| 52 | 55 | @Lazy |
| 53 | 56 | private ProductSkuApi productSkuApi; |
| 57 | + @Resource | |
| 58 | + private TradeOrderApi tradeOrderApi; | |
| 54 | 59 | |
| 55 | 60 | @Override |
| 56 | 61 | @Transactional(rollbackFor = Exception.class) |
| ... | ... | @@ -97,6 +102,35 @@ public class CombinationRecordServiceImpl implements CombinationRecordService { |
| 97 | 102 | } |
| 98 | 103 | |
| 99 | 104 | // TODO @puhui999:有一个应该在创建那要做下;就是当前 activityId 已经有未支付的订单,不允许在发起新的;要么支付,要么去掉先; |
| 105 | + @Override | |
| 106 | + public void validateCombinationRecord(Long activityId, Long userId, Long skuId, Integer count) { | |
| 107 | + // 1.1 校验拼团活动是否存在 | |
| 108 | + CombinationActivityDO activity = combinationActivityService.validateCombinationActivityExists(activityId); | |
| 109 | + // 1.2 校验活动是否开启 | |
| 110 | + if (ObjectUtil.equal(activity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) { | |
| 111 | + throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE); | |
| 112 | + } | |
| 113 | + // 1.3 校验是否超出单次限购数量 | |
| 114 | + if (count > activity.getSingleLimitCount()) { | |
| 115 | + throw exception(COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED); | |
| 116 | + } | |
| 117 | + | |
| 118 | + // 2. 校验是否超出总限购数量 | |
| 119 | + List<CombinationRecordDO> recordList = getRecordListByUserIdAndActivityId(userId, activityId); | |
| 120 | + if (CollUtil.isEmpty(recordList)) { | |
| 121 | + return; | |
| 122 | + } | |
| 123 | + // 过滤出拼团成功的 | |
| 124 | + // TODO @puhui999:count 要不存一个在 record 里? | |
| 125 | + List<Long> skuIds = convertList(recordList, CombinationRecordDO::getSkuId, | |
| 126 | + item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())); | |
| 127 | + Integer countSum = tradeOrderApi.getOrderItemCountSumByOrderIdAndSkuId(convertList(recordList, | |
| 128 | + CombinationRecordDO::getOrderId, | |
| 129 | + item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), skuIds); | |
| 130 | + if (activity.getTotalLimitCount() < countSum) { | |
| 131 | + throw exception(COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED); | |
| 132 | + } | |
| 133 | + } | |
| 100 | 134 | |
| 101 | 135 | @Override |
| 102 | 136 | @Transactional(rollbackFor = Exception.class) |
| ... | ... | @@ -105,21 +139,26 @@ public class CombinationRecordServiceImpl implements CombinationRecordService { |
| 105 | 139 | CombinationActivityDO activity = combinationActivityService.validateCombinationActivityExists(reqDTO.getActivityId()); |
| 106 | 140 | // 1.2 需要校验下,他当前是不是已经参加了该拼团; |
| 107 | 141 | // TODO @puhui999:拼团应该可以重复参加;应该去校验总共的上限哈,就是 activity.totalLimitCount |
| 108 | - CombinationRecordDO recordDO = recordMapper.selectByUserIdAndOrderId(reqDTO.getUserId(), reqDTO.getOrderId()); | |
| 109 | - if (recordDO != null) { | |
| 110 | - throw exception(COMBINATION_RECORD_EXISTS); | |
| 142 | + List<CombinationRecordDO> records = recordMapper.selectListByUserId(reqDTO.getUserId()); | |
| 143 | + List<Long> orderIds = convertList(records, CombinationRecordDO::getOrderId); | |
| 144 | + // 1.2.1 如果存在订单才去校验 | |
| 145 | + if (CollUtil.isNotEmpty(orderIds)) { | |
| 146 | + | |
| 111 | 147 | } |
| 112 | 148 | // 1.3 校验用户是否参加了其它拼团 |
| 113 | 149 | List<CombinationRecordDO> recordDOList = recordMapper.selectListByUserIdAndStatus(reqDTO.getUserId(), CombinationRecordStatusEnum.IN_PROGRESS.getStatus()); |
| 114 | 150 | if (CollUtil.isNotEmpty(recordDOList)) { |
| 115 | 151 | throw exception(COMBINATION_RECORD_FAILED_HAVE_JOINED); |
| 116 | 152 | } |
| 117 | - // TODO @puhui999:有个开始时间未校验 | |
| 118 | - // 1.4 校验当前活动是否过期 | |
| 153 | + // 1、4 校验活动是否开启 | |
| 154 | + if (LocalDateTime.now().isAfter(activity.getStartTime())) { | |
| 155 | + throw exception(COMBINATION_RECORD_FAILED_TIME_NOT_START); | |
| 156 | + } | |
| 157 | + // 1.5 校验当前活动是否过期 | |
| 119 | 158 | if (LocalDateTime.now().isAfter(activity.getEndTime())) { |
| 120 | 159 | throw exception(COMBINATION_RECORD_FAILED_TIME_END); |
| 121 | 160 | } |
| 122 | - // 1.5 父拼团是否存在,是否已经满了 | |
| 161 | + // 1.6 父拼团是否存在,是否已经满了 | |
| 123 | 162 | if (reqDTO.getHeadId() != null) { |
| 124 | 163 | // 查询进行中的父拼团 |
| 125 | 164 | CombinationRecordDO record = recordMapper.selectOneByHeadId(reqDTO.getHeadId(), CombinationRecordStatusEnum.IN_PROGRESS.getStatus()); | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java
| ... | ... | @@ -56,6 +56,7 @@ import cn.iocoder.yudao.module.trade.service.cart.CartService; |
| 56 | 56 | import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService; |
| 57 | 57 | import cn.iocoder.yudao.module.trade.service.message.TradeMessageService; |
| 58 | 58 | import cn.iocoder.yudao.module.trade.service.message.bo.TradeOrderMessageWhenDeliveryOrderReqBO; |
| 59 | +import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterPayOrderReqBO; | |
| 59 | 60 | import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO; |
| 60 | 61 | import cn.iocoder.yudao.module.trade.service.order.handler.TradeOrderHandler; |
| 61 | 62 | import cn.iocoder.yudao.module.trade.service.price.TradePriceService; |
| ... | ... | @@ -333,13 +334,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { |
| 333 | 334 | if (updateCount == 0) { |
| 334 | 335 | throw exception(ORDER_UPDATE_PAID_STATUS_NOT_UNPAID); |
| 335 | 336 | } |
| 336 | - // 校验活动 | |
| 337 | - // 1、拼团活动 | |
| 338 | - // TODO @puhui999:这块也抽象到 handler 里 | |
| 339 | - if (Objects.equals(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) { | |
| 340 | - // 更新拼团状态 TODO puhui999:订单支付失败或订单支付过期删除这条拼团记录 | |
| 341 | - combinationRecordApi.updateRecordStatusToInProgress(order.getUserId(), order.getId(), LocalDateTime.now()); | |
| 342 | - } | |
| 337 | + // 订单支付成功后 | |
| 338 | + tradeOrderHandlers.forEach(tradeOrderHandler -> tradeOrderHandler.afterPayOrder(new TradeAfterPayOrderReqBO() | |
| 339 | + .setOrderId(order.getId()).setOrderType(order.getType()).setUserId(order.getUserId()).setPayTime(LocalDateTime.now()))); | |
| 343 | 340 | // TODO 芋艿:发送订单变化的消息 |
| 344 | 341 | |
| 345 | 342 | // TODO 芋艿:发送站内信 |
| ... | ... | @@ -742,7 +739,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { |
| 742 | 739 | } |
| 743 | 740 | |
| 744 | 741 | // 3. TODO 活动相关库存回滚需要活动 id,活动 id 怎么获取?app 端能否传过来;回复:从订单里拿呀 |
| 745 | - tradeOrderHandlers.forEach(handler -> handler.rollback()); | |
| 742 | + tradeOrderHandlers.forEach(handler -> handler.cancelOrder()); | |
| 746 | 743 | |
| 747 | 744 | // 4. 回滚库存 |
| 748 | 745 | List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(id); | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/bo/TradeAfterPayOrderReqBO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.service.order.bo; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; | |
| 4 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 5 | +import lombok.Data; | |
| 6 | + | |
| 7 | +import java.time.LocalDateTime; | |
| 8 | + | |
| 9 | +/** | |
| 10 | + * 订单支付后 Request BO | |
| 11 | + * | |
| 12 | + * @author HUIHUI | |
| 13 | + */ | |
| 14 | +@Data | |
| 15 | +public class TradeAfterPayOrderReqBO { | |
| 16 | + | |
| 17 | + /** | |
| 18 | + * 订单编号 | |
| 19 | + */ | |
| 20 | + @Schema(description = "订单编号", example = "6") | |
| 21 | + private Long orderId; | |
| 22 | + | |
| 23 | + /** | |
| 24 | + * 订单类型 | |
| 25 | + * | |
| 26 | + * 枚举 {@link TradeOrderTypeEnum} | |
| 27 | + */ | |
| 28 | + @Schema(description = "订单类型", example = "3") | |
| 29 | + private Integer orderType; | |
| 30 | + | |
| 31 | + /** | |
| 32 | + * 用户编号 | |
| 33 | + */ | |
| 34 | + @Schema(description = "用户编号", example = "11") | |
| 35 | + private Long userId; | |
| 36 | + | |
| 37 | + /** | |
| 38 | + * 订单支付时间 | |
| 39 | + */ | |
| 40 | + @Schema(description = "订单支付时间", example = "2023-08-15 10:00:00") | |
| 41 | + private LocalDateTime payTime; | |
| 42 | + | |
| 43 | +} | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeSeckillActivityPriceCalculator.java
| 1 | 1 | package cn.iocoder.yudao.module.trade.service.price.calculator; |
| 2 | 2 | |
| 3 | -import cn.hutool.core.util.ObjectUtil; | |
| 4 | 3 | import cn.iocoder.yudao.module.promotion.api.seckill.SeckillActivityApi; |
| 5 | 4 | import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityProductRespDTO; |
| 6 | -import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; | |
| 7 | 5 | import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; |
| 8 | 6 | import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; |
| 9 | 7 | import org.springframework.core.annotation.Order; |
| ... | ... | @@ -31,7 +29,7 @@ public class TradeSeckillActivityPriceCalculator implements TradePriceCalculator |
| 31 | 29 | @Override |
| 32 | 30 | public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { |
| 33 | 31 | // 1、判断订单类型和是否具有秒杀活动编号 |
| 34 | - if (ObjectUtil.notEqual(param.getType(), TradeOrderTypeEnum.SECKILL.getType()) && param.getSeckillActivityId() == null) { | |
| 32 | + if (param.getSeckillActivityId() == null) { | |
| 35 | 33 | return; |
| 36 | 34 | } |
| 37 | 35 | // 2、获取秒杀活动商品信息 | ... | ... |