Commit de828e3d047020482358bad58f0c9e02dbd08ee5

Authored by puhui999
2 parents e2a8f7b3 36da5d69

Merge remote-tracking branch 'yudao/feature/mall_product' into feature/mall_product

# Conflicts:
#	yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/BargainActivityController.java
#	yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/BargainActivityCreateReqVO.java
#	yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/BargainActivityRespVO.java
#	yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/BargainActivityUpdateReqVO.java
#	yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/activity/BargainActivityCreateReqVO.java
#	yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/activity/BargainActivityPageReqVO.java
#	yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/product/BargainProductBaseVO.java
#	yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityPageReqVO.java
#	yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/bargain/BargainActivityConvert.java
#	yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/combination/CombinationActivityConvert.java
#	yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillactivity/SeckillActivityConvert.java
#	yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/bargain/BargainActivityDO.java
#	yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/bargain/BargainProductDO.java
#	yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/CombinationActivityMapper.java
#	yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainActivityService.java
#	yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainActivityServiceImpl.java
#	yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationServiceImpl.java
#	yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityServiceImplTest.java
#	yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java
Showing 51 changed files with 683 additions and 351 deletions
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/app/file/AppFileController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.app.file;
  2 +
  3 +import cn.hutool.core.io.IoUtil;
  4 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  5 +import cn.iocoder.yudao.module.infra.controller.app.file.vo.AppFileUploadReqVO;
  6 +import cn.iocoder.yudao.module.infra.service.file.FileService;
  7 +import io.swagger.v3.oas.annotations.Operation;
  8 +import io.swagger.v3.oas.annotations.tags.Tag;
  9 +import lombok.extern.slf4j.Slf4j;
  10 +import org.springframework.validation.annotation.Validated;
  11 +import org.springframework.web.bind.annotation.PostMapping;
  12 +import org.springframework.web.bind.annotation.RequestMapping;
  13 +import org.springframework.web.bind.annotation.RestController;
  14 +import org.springframework.web.multipart.MultipartFile;
  15 +
  16 +import javax.annotation.Resource;
  17 +
  18 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  19 +
  20 +@Tag(name = "用户 App - 文件存储")
  21 +@RestController
  22 +@RequestMapping("/infra/file")
  23 +@Validated
  24 +@Slf4j
  25 +public class AppFileController {
  26 +
  27 + @Resource
  28 + private FileService fileService;
  29 +
  30 + @PostMapping("/upload")
  31 + @Operation(summary = "上传文件")
  32 + public CommonResult<String> uploadFile(AppFileUploadReqVO uploadReqVO) throws Exception {
  33 + MultipartFile file = uploadReqVO.getFile();
  34 + String path = uploadReqVO.getPath();
  35 + return success(fileService.createFile(file.getOriginalFilename(), path, IoUtil.readBytes(file.getInputStream())));
  36 + }
  37 +
  38 +}
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/app/file/vo/AppFileUploadReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.app.file.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +import org.springframework.web.multipart.MultipartFile;
  6 +
  7 +import javax.validation.constraints.NotNull;
  8 +
  9 +@Schema(description = "用户 App - 上传文件 Request VO")
  10 +@Data
  11 +public class AppFileUploadReqVO {
  12 +
  13 + @Schema(description = "文件附件", requiredMode = Schema.RequiredMode.REQUIRED)
  14 + @NotNull(message = "文件附件不能为空")
  15 + private MultipartFile file;
  16 +
  17 + @Schema(description = "文件附件", example = "yudaoyuanma.png")
  18 + private String path;
  19 +
  20 +}
... ...
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/ProductSpuApi.java
... ... @@ -21,4 +21,11 @@ public interface ProductSpuApi {
21 21 */
22 22 List<ProductSpuRespDTO> getSpuList(Collection<Long> ids);
23 23  
  24 + /**
  25 + * 获得 SPU
  26 + *
  27 + * @return SPU
  28 + */
  29 + ProductSpuRespDTO getSpu(Long id);
  30 +
24 31 }
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/spu/ProductSpuApiImpl.java
... ... @@ -5,6 +5,8 @@ import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
5 5 import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert;
6 6 import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
7 7 import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper;
  8 +import cn.iocoder.yudao.module.product.service.sku.ProductSkuService;
  9 +import cn.iocoder.yudao.module.product.service.spu.ProductSpuService;
8 10 import org.springframework.stereotype.Service;
9 11 import org.springframework.validation.annotation.Validated;
10 12  
... ... @@ -24,15 +26,19 @@ import java.util.List;
24 26 public class ProductSpuApiImpl implements ProductSpuApi {
25 27  
26 28 @Resource
27   - private ProductSpuMapper productSpuMapper;
  29 + private ProductSpuService spuService;
28 30  
29 31 @Override
30   - public List<ProductSpuRespDTO> getSpuList(Collection<Long> spuIds) {
31   - if (CollectionUtil.isEmpty(spuIds)) {
  32 + public List<ProductSpuRespDTO> getSpuList(Collection<Long> ids) {
  33 + if (CollectionUtil.isEmpty(ids)) {
32 34 return Collections.emptyList();
33 35 }
34   - List<ProductSpuDO> productSpuDOList = productSpuMapper.selectBatchIds(spuIds);
35   - return ProductSpuConvert.INSTANCE.convertList2(productSpuDOList);
  36 + return ProductSpuConvert.INSTANCE.convertList2(spuService.getSpuList(ids));
  37 + }
  38 +
  39 + @Override
  40 + public ProductSpuRespDTO getSpu(Long id) {
  41 + return ProductSpuConvert.INSTANCE.convert02(spuService.getSpu(id));
36 42 }
37 43  
38 44 }
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java
... ... @@ -64,6 +64,8 @@ public interface ProductSpuConvert {
64 64  
65 65 ProductSpuDetailRespVO convert03(ProductSpuDO spu);
66 66  
  67 + ProductSpuRespDTO convert02(ProductSpuDO bean);
  68 +
67 69 // ========== 用户 App 相关 ==========
68 70  
69 71 PageResult<AppProductSpuPageRespVO> convertPageForGetSpuPage(PageResult<ProductSpuDO> page);
... ...
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
... ... @@ -50,14 +50,11 @@ public interface ErrorCodeConstants {
50 50 ErrorCode SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1013008003, "秒杀活动已关闭,不能修改");
51 51 ErrorCode SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013008004, "秒杀活动未关闭或未结束,不能删除");
52 52 ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1013008005, "秒杀活动已关闭,不能重复关闭");
53   - ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_END = new ErrorCode(1013008006, "秒杀活动已结束,不能关闭");
54 53  
55 54 // ========== 秒杀时段 1013009000 ==========
56   - ErrorCode SECKILL_TIME_NOT_EXISTS = new ErrorCode(1013009000, "秒杀时段不存在");
57   - ErrorCode SECKILL_TIME_CONFLICTS = new ErrorCode(1013009001, "秒杀时段冲突");
58   - ErrorCode SECKILL_TIME_EQUAL = new ErrorCode(1013009002, "秒杀时段开始时间和结束时间不能相等");
59   - ErrorCode SECKILL_START_TIME_BEFORE_END_TIME = new ErrorCode(1013009003, "秒杀时段开始时间不能在结束时间之后");
60   - ErrorCode SECKILL_TIME_DISABLE = new ErrorCode(1013009004, "秒杀时段已关闭");
  55 + ErrorCode SECKILL_CONFIG_NOT_EXISTS = new ErrorCode(1013009000, "秒杀时段不存在");
  56 + ErrorCode SECKILL_CONFIG_TIME_CONFLICTS = new ErrorCode(1013009001, "秒杀时段冲突");
  57 + ErrorCode SECKILL_CONFIG_DISABLE = new ErrorCode(1013009004, "秒杀时段已关闭");
61 58  
62 59 // ========== 拼团活动 1013010000 ==========
63 60 ErrorCode COMBINATION_ACTIVITY_NOT_EXISTS = new ErrorCode(1013010000, "拼团活动不存在");
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/BargainActivityController.java
1 1 package cn.iocoder.yudao.module.promotion.controller.admin.bargain;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
3 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 6 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
6   -import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityCreateReqVO;
7   -import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityPageReqVO;
8   -import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityRespVO;
9   -import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityUpdateReqVO;
  7 +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
  8 +import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityCreateReqVO;
  9 +import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityPageReqVO;
  10 +import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityRespVO;
  11 +import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityUpdateReqVO;
10 12 import cn.iocoder.yudao.module.promotion.convert.bargain.BargainActivityConvert;
11 13 import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService;
12 14 import io.swagger.v3.oas.annotations.Operation;
... ... @@ -18,6 +20,8 @@ import org.springframework.web.bind.annotation.*;
18 20  
19 21 import javax.annotation.Resource;
20 22 import javax.validation.Valid;
  23 +import java.util.Collections;
  24 +import java.util.List;
21 25  
22 26 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
23 27  
... ... @@ -31,7 +35,7 @@ public class BargainActivityController {
31 35 private BargainActivityService activityService;
32 36  
33 37 @Resource
34   - private ProductSpuApi spuApi;
  38 + private ProductSpuApi productSpuApi;
35 39  
36 40 @PostMapping("/create")
37 41 @Operation(summary = "创建砍价活动")
... ... @@ -70,6 +74,19 @@ public class BargainActivityController {
70 74 @PreAuthorize("@ss.hasPermission('promotion:bargain-activity:query')")
71 75 public CommonResult<PageResult<BargainActivityRespVO>> getBargainActivityPage(
72 76 @Valid BargainActivityPageReqVO pageVO) {
  77 + // 查询砍价活动
  78 + PageResult<BargainActivityDO> pageResult = activityService.getBargainActivityPage(pageVO);
  79 + if (CollUtil.isEmpty(pageResult.getList())) {
  80 + return success(PageResult.empty(pageResult.getTotal()));
  81 + }
  82 +
  83 + // 拼接数据
  84 +// List<BargainProductDO> products = activityService.getBargainProductsByActivityIds(
  85 +// convertSet(pageResult.getList(), BargainActivityDO::getId));
  86 + List<BargainProductDO> products = Collections.emptyList();
  87 + List<ProductSpuRespDTO> spus = productSpuApi.getSpuList(
  88 + convertSet(pageResult.getList(), BargainActivityDO::getSpuId));
  89 + return success(BargainActivityConvert.INSTANCE.convertPage(pageResult, products, spus));
73 90 return success(BargainActivityConvert.INSTANCE.convertPage(activityService.getBargainActivityPage(pageVO)));
74 91 }
75 92  
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/BargainActivityBaseVO.java
... ... @@ -22,7 +22,7 @@ public class BargainActivityBaseVO {
22 22 @NotNull(message = "砍价名称不能为空")
23 23 private String name;
24 24  
25   - @Schema(description = "商品 SPU 编号,关联 ProductSpuDO 的 id", example = "[1,2,3]")
  25 + @Schema(description = "商品 SPU 编号", example = "1")
26 26 @NotNull(message = "砍价商品不能为空")
27 27 private Long spuId;
28 28  
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/BargainActivityCreateReqVO.java deleted
1   -package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo;
2   -
3   -import io.swagger.v3.oas.annotations.media.Schema;
4   -import lombok.Data;
5   -import lombok.EqualsAndHashCode;
6   -import lombok.ToString;
7   -
8   -@Schema(description = "管理后台 - 砍价活动创建 Request VO")
9   -@Data
10   -@EqualsAndHashCode(callSuper = true)
11   -@ToString(callSuper = true)
12   -public class BargainActivityCreateReqVO extends BargainActivityBaseVO {
13   -
14   -}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/CombinationActivityController.java
1 1 package cn.iocoder.yudao.module.promotion.controller.admin.combination;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
3 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 6 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
  7 +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
6 8 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
7 9 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO;
8 10 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityRespVO;
... ... @@ -21,7 +23,6 @@ import org.springframework.web.bind.annotation.*;
21 23 import javax.annotation.Resource;
22 24 import javax.validation.Valid;
23 25 import java.util.List;
24   -import java.util.Set;
25 26  
26 27 import static cn.hutool.core.collection.CollectionUtil.newArrayList;
27 28 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
... ... @@ -37,7 +38,7 @@ public class CombinationActivityController {
37 38 private CombinationActivityService combinationActivityService;
38 39  
39 40 @Resource
40   - private ProductSpuApi spuApi;
  41 + private ProductSpuApi productSpuApi;
41 42  
42 43 @PostMapping("/create")
43 44 @Operation(summary = "创建拼团活动")
... ... @@ -80,12 +81,16 @@ public class CombinationActivityController {
80 81 @Valid CombinationActivityPageReqVO pageVO) {
81 82 // 查询拼团活动
82 83 PageResult<CombinationActivityDO> pageResult = combinationActivityService.getCombinationActivityPage(pageVO);
  84 + if (CollUtil.isEmpty(pageResult.getList())) {
  85 + return success(PageResult.empty(pageResult.getTotal()));
  86 + }
  87 +
83 88 // 拼接数据
84   - Set<Long> activityIds = convertSet(pageResult.getList(), CombinationActivityDO::getId);
85   - Set<Long> spuIds = convertSet(pageResult.getList(), CombinationActivityDO::getSpuId);
86   - return success(CombinationActivityConvert.INSTANCE.convertPage(pageResult,
87   - combinationActivityService.getCombinationProductsByActivityIds(activityIds),
88   - spuApi.getSpuList(spuIds)));
  89 + List<CombinationProductDO> products = combinationActivityService.getCombinationProductsByActivityIds(
  90 + convertSet(pageResult.getList(), CombinationActivityDO::getId));
  91 + List<ProductSpuRespDTO> spus = productSpuApi.getSpuList(
  92 + convertSet(pageResult.getList(), CombinationActivityDO::getSpuId));
  93 + return success(CombinationActivityConvert.INSTANCE.convertPage(pageResult, products, spus));
89 94 }
90 95  
91 96 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityBaseVO.java
... ... @@ -22,7 +22,7 @@ public class CombinationActivityBaseVO {
22 22 @NotNull(message = "拼团名称不能为空")
23 23 private String name;
24 24  
25   - @Schema(description = "商品 SPU 编号,关联 ProductSpuDO 的 id", example = "[1,2,3]")
  25 + @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
26 26 @NotNull(message = "拼团商品不能为空")
27 27 private Long spuId;
28 28  
... ... @@ -48,7 +48,7 @@ public class CombinationActivityBaseVO {
48 48 @NotNull(message = "开团人数不能为空")
49 49 private Integer userSize;
50 50  
51   - @Schema(description = "限制时长(小时)", requiredMode = Schema.RequiredMode.REQUIRED)
  51 + @Schema(description = "限制时长(小时)", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
52 52 @NotNull(message = "限制时长不能为空")
53 53 private Integer limitDuration;
54 54  
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityCreateReqVO.java
1 1 package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity;
2 2  
3   -import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductCreateReqVO;
  3 +import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductBaseVO;
4 4 import io.swagger.v3.oas.annotations.media.Schema;
5 5 import lombok.Data;
6 6 import lombok.EqualsAndHashCode;
... ... @@ -17,6 +17,6 @@ public class CombinationActivityCreateReqVO extends CombinationActivityBaseVO {
17 17  
18 18 @Schema(description = "拼团商品", requiredMode = Schema.RequiredMode.REQUIRED)
19 19 @Valid
20   - private List<CombinationProductCreateReqVO> products;
  20 + private List<CombinationProductBaseVO> products;
21 21  
22 22 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityRespVO.java
... ... @@ -17,40 +17,34 @@ import java.util.List;
17 17 @ToString(callSuper = true)
18 18 public class CombinationActivityRespVO extends CombinationActivityBaseVO {
19 19  
20   - @Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "618大促")
  20 + @Schema(description = "活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "22901")
  21 + private Long id;
  22 +
  23 + @Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "618 大促")
21 24 private String spuName;
22 25  
23 26 @Schema(description = "商品主图", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.png")
24 27 private String picUrl;
25 28  
26   - @Schema(description = "活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "22901")
27   - private Long id;
28   -
29 29 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
30 30 private LocalDateTime createTime;
31 31  
32   - @Schema(description = "开团人数", requiredMode = Schema.RequiredMode.REQUIRED)
33   - @NotNull(message = "开团人数不能为空")
  32 + @Schema(description = "开团人数", requiredMode = Schema.RequiredMode.REQUIRED, example = "666")
34 33 private Integer userSize;
35 34  
36   - @Schema(description = "开团组数", requiredMode = Schema.RequiredMode.REQUIRED)
37   - @NotNull(message = "开团组数不能为空")
38   - private Integer totalNum;
  35 + @Schema(description = "开团组数", requiredMode = Schema.RequiredMode.REQUIRED, example = "33")
  36 + private Integer totalCount;
39 37  
40   - @Schema(description = "成团组数", requiredMode = Schema.RequiredMode.REQUIRED)
41   - @NotNull(message = "成团组数不能为空")
42   - private Integer successNum;
  38 + @Schema(description = "成团组数", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
  39 + private Integer successCount;
43 40  
44   - @Schema(description = "虚拟成团", requiredMode = Schema.RequiredMode.REQUIRED)
45   - @NotNull(message = "虚拟成团不能为空")
  41 + @Schema(description = "虚拟成团", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
46 42 private Integer virtualGroup;
47 43  
48 44 @Schema(description = "活动状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
49   - @NotNull(message = "活动状态不能为空")
50 45 private Integer status;
51 46  
52 47 @Schema(description = "拼团商品", requiredMode = Schema.RequiredMode.REQUIRED)
53   - @Valid
54 48 private List<CombinationProductRespVO> products;
55 49  
56 50 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityUpdateReqVO.java
1 1 package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity;
2 2  
3   -import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductUpdateReqVO;
  3 +import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductBaseVO;
4 4 import io.swagger.v3.oas.annotations.media.Schema;
5 5 import lombok.Data;
6 6 import lombok.EqualsAndHashCode;
... ... @@ -22,6 +22,6 @@ public class CombinationActivityUpdateReqVO extends CombinationActivityBaseVO {
22 22  
23 23 @Schema(description = "拼团商品", requiredMode = Schema.RequiredMode.REQUIRED)
24 24 @Valid
25   - private List<CombinationProductUpdateReqVO> products;
  25 + private List<CombinationProductBaseVO> products;
26 26  
27 27 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductBaseVO.java
... ... @@ -21,7 +21,7 @@ public class CombinationProductBaseVO {
21 21 private Long skuId;
22 22  
23 23 @Schema(description = "拼团价格,单位分", requiredMode = Schema.RequiredMode.REQUIRED, example = "27682")
24   - @NotNull(message = "拼团价格,单位分不能为空")
25   - private Integer activePrice;
  24 + @NotNull(message = "拼团价格不能为空")
  25 + private Integer combinationPrice;
26 26  
27 27 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductCreateReqVO.java deleted
1   -package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product;
2   -
3   -import io.swagger.v3.oas.annotations.media.Schema;
4   -import lombok.Data;
5   -import lombok.EqualsAndHashCode;
6   -import lombok.ToString;
7   -
8   -@Schema(description = "管理后台 - 拼团商品创建 Request VO")
9   -@Data
10   -@EqualsAndHashCode(callSuper = true)
11   -@ToString(callSuper = true)
12   -public class CombinationProductCreateReqVO extends CombinationProductBaseVO {
13   -
14   -}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductUpdateReqVO.java deleted
1   -package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product;
2   -
3   -import io.swagger.v3.oas.annotations.media.Schema;
4   -import lombok.Data;
5   -import lombok.EqualsAndHashCode;
6   -import lombok.ToString;
7   -
8   -@Schema(description = "管理后台 - 拼团商品更新 Request VO")
9   -@Data
10   -@EqualsAndHashCode(callSuper = true)
11   -@ToString(callSuper = true)
12   -public class CombinationProductUpdateReqVO extends CombinationProductBaseVO {
13   -
14   -}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/SeckillActivityController.java
1 1 package cn.iocoder.yudao.module.promotion.controller.admin.seckill;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
3 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 6 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
... ... @@ -8,7 +9,7 @@ import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.*;
8 9 import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert;
9 10 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
10 11 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
11   -import cn.iocoder.yudao.module.promotion.service.seckill.seckillactivity.SeckillActivityService;
  12 +import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService;
12 13 import io.swagger.v3.oas.annotations.Operation;
13 14 import io.swagger.v3.oas.annotations.Parameter;
14 15 import io.swagger.v3.oas.annotations.tags.Tag;
... ... @@ -19,7 +20,6 @@ import org.springframework.web.bind.annotation.*;
19 20 import javax.annotation.Resource;
20 21 import javax.validation.Valid;
21 22 import java.util.List;
22   -import java.util.Set;
23 23  
24 24 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
25 25 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
... ... @@ -33,7 +33,7 @@ public class SeckillActivityController {
33 33 @Resource
34 34 private SeckillActivityService seckillActivityService;
35 35 @Resource
36   - private ProductSpuApi spuApi;
  36 + private ProductSpuApi productSpuApi;
37 37  
38 38 @PostMapping("/create")
39 39 @Operation(summary = "创建秒杀活动")
... ... @@ -73,21 +73,27 @@ public class SeckillActivityController {
73 73 @Parameter(name = "id", description = "编号", required = true, example = "1024")
74 74 @PreAuthorize("@ss.hasPermission('promotion:seckill-activity:query')")
75 75 public CommonResult<SeckillActivityDetailRespVO> getSeckillActivity(@RequestParam("id") Long id) {
76   - SeckillActivityDO seckillActivity = seckillActivityService.getSeckillActivity(id);
77   - List<SeckillProductDO> seckillProducts = seckillActivityService.getSeckillProductListByActivityId(id);
78   - return success(SeckillActivityConvert.INSTANCE.convert(seckillActivity, seckillProducts));
  76 + SeckillActivityDO activity = seckillActivityService.getSeckillActivity(id);
  77 + List<SeckillProductDO> products = seckillActivityService.getSeckillProductListByActivityId(id);
  78 + return success(SeckillActivityConvert.INSTANCE.convert(activity, products));
79 79 }
80 80  
81 81 @GetMapping("/page")
82 82 @Operation(summary = "获得秒杀活动分页")
83 83 @PreAuthorize("@ss.hasPermission('promotion:seckill-activity:query')")
84 84 public CommonResult<PageResult<SeckillActivityRespVO>> getSeckillActivityPage(@Valid SeckillActivityPageReqVO pageVO) {
  85 + // 查询活动列表
85 86 PageResult<SeckillActivityDO> pageResult = seckillActivityService.getSeckillActivityPage(pageVO);
86   - Set<Long> aIds = convertSet(pageResult.getList(), SeckillActivityDO::getId);
87   - List<SeckillProductDO> seckillProducts = seckillActivityService.getSeckillProductListByActivityId(aIds);
88   - Set<Long> spuIds = convertSet(pageResult.getList(), SeckillActivityDO::getSpuId);
89   - List<ProductSpuRespDTO> spuList = spuApi.getSpuList(spuIds);
90   - return success(SeckillActivityConvert.INSTANCE.convertPage(pageResult, seckillProducts, spuList));
  87 + if (CollUtil.isEmpty(pageResult.getList())) {
  88 + return success(PageResult.empty(pageResult.getTotal()));
  89 + }
  90 +
  91 + // 拼接数据
  92 + List<SeckillProductDO> products = seckillActivityService.getSeckillProductListByActivityId(
  93 + convertSet(pageResult.getList(), SeckillActivityDO::getId));
  94 + List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(
  95 + convertSet(pageResult.getList(), SeckillActivityDO::getSpuId));
  96 + return success(SeckillActivityConvert.INSTANCE.convertPage(pageResult, products, spuList));
91 97 }
92 98  
93 99 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/SeckillConfigController.java
... ... @@ -6,7 +6,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 6 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.*;
7 7 import cn.iocoder.yudao.module.promotion.convert.seckill.seckillconfig.SeckillConfigConvert;
8 8 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillconfig.SeckillConfigDO;
9   -import cn.iocoder.yudao.module.promotion.service.seckill.seckillconfig.SeckillConfigService;
  9 +import cn.iocoder.yudao.module.promotion.service.seckill.SeckillConfigService;
10 10 import io.swagger.v3.oas.annotations.Operation;
11 11 import io.swagger.v3.oas.annotations.Parameter;
12 12 import io.swagger.v3.oas.annotations.tags.Tag;
... ... @@ -92,4 +92,5 @@ public class SeckillConfigController {
92 92 PageResult<SeckillConfigDO> pageResult = seckillConfigService.getSeckillConfigPage(pageVO);
93 93 return success(SeckillConfigConvert.INSTANCE.convertPage(pageResult));
94 94 }
  95 +
95 96 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityBaseVO.java
... ... @@ -20,7 +20,7 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
20 20 @Data
21 21 public class SeckillActivityBaseVO {
22 22  
23   - @Schema(description = "秒杀活动商品id", requiredMode = Schema.RequiredMode.REQUIRED, example = "[121,1212]")
  23 + @Schema(description = "秒杀活动商品 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "[121,1212]")
24 24 @NotNull(message = "秒杀活动商品不能为空")
25 25 private Long spuId;
26 26  
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityCreateReqVO.java
1 1 package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity;
2 2  
3 3  
4   -import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductCreateReqVO;
  4 +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductBaseVO;
5 5 import io.swagger.v3.oas.annotations.media.Schema;
6 6 import lombok.Data;
7 7 import lombok.EqualsAndHashCode;
... ... @@ -16,6 +16,6 @@ import java.util.List;
16 16 public class SeckillActivityCreateReqVO extends SeckillActivityBaseVO {
17 17  
18 18 @Schema(description = "秒杀商品", requiredMode = Schema.RequiredMode.REQUIRED)
19   - private List<SeckillProductCreateReqVO> products;
  19 + private List<SeckillProductBaseVO> products;
20 20  
21 21 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityRespVO.java
... ... @@ -21,28 +21,28 @@ public class SeckillActivityRespVO extends SeckillActivityBaseVO {
21 21 @Schema(description = "商品主图", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.png")
22 22 private String picUrl;
23 23  
24   - @Schema(description = "秒杀活动id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  24 + @Schema(description = "秒杀活动 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
25 25 private Long id;
26 26  
27 27 @Schema(description = "秒杀商品", requiredMode = Schema.RequiredMode.REQUIRED)
28 28 private List<SeckillProductRespVO> products;
29 29  
30   - @Schema(description = "活动状态 开启:0 禁用:1", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
  30 + @Schema(description = "活动状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
31 31 private Integer status;
32 32  
33 33 @Schema(description = "订单实付金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "22354")
34 34 private Integer totalPrice;
35 35  
36   - @Schema(description = "秒杀库存", example = "10")
  36 + @Schema(description = "秒杀库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
37 37 private Integer stock;
38 38  
39   - @Schema(description = "秒杀总库存", example = "20")
  39 + @Schema(description = "秒杀总库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
40 40 private Integer totalStock;
41 41  
42   - @Schema(description = "新增订单数", example = "20")
  42 + @Schema(description = "新增订单数", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
43 43 private Integer orderCount;
44 44  
45   - @Schema(description = "付款人数", example = "20")
  45 + @Schema(description = "付款人数", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
46 46 private Integer userCount;
47 47  
48 48 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityUpdateReqVO.java
1 1 package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity;
2 2  
3   -import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductUpdateReqVO;
  3 +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductBaseVO;
4 4 import io.swagger.v3.oas.annotations.media.Schema;
5 5 import lombok.Data;
6 6 import lombok.EqualsAndHashCode;
... ... @@ -18,6 +18,6 @@ public class SeckillActivityUpdateReqVO extends SeckillActivityBaseVO {
18 18 private Long id;
19 19  
20 20 @Schema(description = "秒杀商品", requiredMode = Schema.RequiredMode.REQUIRED)
21   - private List<SeckillProductUpdateReqVO> products;
  21 + private List<SeckillProductBaseVO> products;
22 22  
23 23 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/product/SeckillProductBaseVO.java
... ... @@ -22,7 +22,7 @@ public class SeckillProductBaseVO {
22 22 @NotNull(message = "秒杀金额,单位:分不能为空")
23 23 private Integer seckillPrice;
24 24  
25   - @Schema(description = "秒杀库存", requiredMode = Schema.RequiredMode.REQUIRED)
  25 + @Schema(description = "秒杀库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
26 26 @NotNull(message = "秒杀库存不能为空")
27 27 private Integer stock;
28 28  
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/product/SeckillProductCreateReqVO.java deleted
1   -package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product;
2   -
3   -import io.swagger.v3.oas.annotations.media.Schema;
4   -import lombok.Data;
5   -import lombok.EqualsAndHashCode;
6   -import lombok.ToString;
7   -@Schema(description = "管理后台 - 秒杀参与商品创建 Request VO")
8   -@Data
9   -@EqualsAndHashCode(callSuper = true)
10   -@ToString(callSuper = true)
11   -public class SeckillProductCreateReqVO extends SeckillProductBaseVO {
12   -
13   -}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/product/SeckillProductUpdateReqVO.java deleted
1   -package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product;
2   -
3   -import io.swagger.v3.oas.annotations.media.Schema;
4   -import lombok.Data;
5   -import lombok.EqualsAndHashCode;
6   -import lombok.ToString;
7   -
8   -@Schema(description = "管理后台 - 秒杀参与商品更新 Request VO")
9   -@Data
10   -@EqualsAndHashCode(callSuper = true)
11   -@ToString(callSuper = true)
12   -public class SeckillProductUpdateReqVO extends SeckillProductBaseVO {
13   -
14   -}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/CombinationActivityDO.java
... ... @@ -62,11 +62,11 @@ public class CombinationActivityDO extends BaseDO {
62 62 /**
63 63 * 开团组数
64 64 */
65   - private Integer totalNum;
  65 + private Integer totalCount;
66 66 /**
67 67 * 成团组数
68 68 */
69   - private Integer successNum;
  69 + private Integer successCount;
70 70 /**
71 71 * 参与人数
72 72 */
... ... @@ -76,7 +76,7 @@ public class CombinationActivityDO extends BaseDO {
76 76 */
77 77 private Integer virtualGroup;
78 78 /**
79   - * 活动状态:0开启 1关闭
  79 + * 活动状态
80 80 *
81 81 * 枚举 {@link CommonStatusEnum}
82 82 */
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/CombinationProductDO.java
... ... @@ -41,6 +41,11 @@ public class CombinationProductDO extends BaseDO {
41 41 */
42 42 private Long skuId;
43 43 /**
  44 + * 拼团价格,单位分
  45 + */
  46 + private Integer combinationPrice;
  47 +
  48 + /**
44 49 * 拼团商品状态
45 50 *
46 51 * 关联 {@link CombinationActivityDO#getStatus()}
... ... @@ -48,15 +53,15 @@ public class CombinationProductDO extends BaseDO {
48 53 private Integer activityStatus;
49 54 /**
50 55 * 活动开始时间点
  56 + *
  57 + * 冗余 {@link CombinationActivityDO#getStartTime()}
51 58 */
52 59 private LocalDateTime activityStartTime;
53 60 /**
54 61 * 活动结束时间点
  62 + *
  63 + * 冗余 {@link CombinationActivityDO#getEndTime()}
55 64 */
56 65 private LocalDateTime activityEndTime;
57   - /**
58   - * 拼团价格,单位分
59   - */
60   - private Integer activePrice;
61 66  
62 67 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/CombinationProductMapper.java
... ... @@ -26,7 +26,7 @@ public interface CombinationProductMapper extends BaseMapperX&lt;CombinationProduct
26 26 .eqIfPresent(CombinationProductDO::getActivityStatus, reqVO.getActivityStatus())
27 27 .betweenIfPresent(CombinationProductDO::getActivityStartTime, reqVO.getActivityStartTime())
28 28 .betweenIfPresent(CombinationProductDO::getActivityEndTime, reqVO.getActivityEndTime())
29   - .eqIfPresent(CombinationProductDO::getActivePrice, reqVO.getActivePrice())
  29 + .eqIfPresent(CombinationProductDO::getCombinationPrice, reqVO.getActivePrice())
30 30 .betweenIfPresent(CombinationProductDO::getCreateTime, reqVO.getCreateTime())
31 31 .orderByDesc(CombinationProductDO::getId));
32 32 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillProductMapper.java
1 1 package cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity;
2 2  
3   -import cn.hutool.core.collection.CollUtil;
4 3 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5 4 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
6   -import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
7 5 import org.apache.ibatis.annotations.Mapper;
8 6  
9 7 import java.util.Collection;
... ... @@ -25,15 +23,4 @@ public interface SeckillProductMapper extends BaseMapperX&lt;SeckillProductDO&gt; {
25 23 return selectList(SeckillProductDO::getActivityId, ids);
26 24 }
27 25  
28   - default List<SeckillProductDO> selectListBySkuIds(Collection<Long> skuIds) {
29   - return selectList(SeckillProductDO::getSkuId, skuIds);
30   - }
31   -
32   - default void updateTimeIdsByActivityId(Long id, List<Long> timeIds) {
33   - new LambdaUpdateChainWrapper<>(this)
34   - .set(SeckillProductDO::getConfigIds, CollUtil.join(timeIds, ","))
35   - .eq(SeckillProductDO::getActivityId, id)
36   - .update();
37   - }
38   -
39 26 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainServiceImpl.java renamed to yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainActivityServiceImpl.java
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityService.java
... ... @@ -41,20 +41,20 @@ public interface CombinationActivityService {
41 41 void deleteCombinationActivity(Long id);
42 42  
43 43 /**
44   - * 获得拼团活动
  44 + * 校验拼团活动是否存在
45 45 *
46 46 * @param id 编号
47 47 * @return 拼团活动
48 48 */
49   - CombinationActivityDO getCombinationActivity(Long id);
  49 + CombinationActivityDO validateCombinationActivityExists(Long id);
50 50  
51 51 /**
52   - * 获得拼团活动列表
  52 + * 获得拼团活动
53 53 *
54   - * @param ids 编号
55   - * @return 拼团活动列表
  54 + * @param id 编号
  55 + * @return 拼团活动
56 56 */
57   - List<CombinationActivityDO> getCombinationActivityList(Collection<Long> ids);
  57 + CombinationActivityDO getCombinationActivity(Long id);
58 58  
59 59 /**
60 60 * 获得拼团活动分页
... ... @@ -67,9 +67,9 @@ public interface CombinationActivityService {
67 67 /**
68 68 * 获得拼团活动商品列表
69 69 *
70   - * @param ids 拼团活动 ids
  70 + * @param activityIds 拼团活动 ids
71 71 * @return 拼团活动的商品列表
72 72 */
73   - List<CombinationProductDO> getCombinationProductsByActivityIds(Collection<Long> ids);
  73 + List<CombinationProductDO> getCombinationProductsByActivityIds(Collection<Long> activityIds);
74 74  
75 75 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.service.combination;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.util.ObjectUtil;
  5 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  6 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  7 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  8 +import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
  9 +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
  10 +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
  11 +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
  12 +import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
  13 +import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO;
  14 +import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO;
  15 +import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductBaseVO;
  16 +import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
  17 +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
  18 +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO;
  19 +import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationActivityMapper;
  20 +import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationProductMapper;
  21 +import org.springframework.stereotype.Service;
  22 +import org.springframework.transaction.annotation.Transactional;
  23 +import org.springframework.validation.annotation.Validated;
  24 +
  25 +import javax.annotation.Resource;
  26 +import java.util.Collection;
  27 +import java.util.List;
  28 +import java.util.Map;
  29 +
  30 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  31 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
  32 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
  33 +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;
  34 +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS;
  35 +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
  36 +import static java.util.Collections.singletonList;
  37 +
  38 +/**
  39 + * 拼团活动 Service 实现类
  40 + *
  41 + * @author HUIHUI
  42 + */
  43 +@Service
  44 +@Validated
  45 +public class CombinationActivityServiceImpl implements CombinationActivityService {
  46 +
  47 + @Resource
  48 + private CombinationActivityMapper combinationActivityMapper;
  49 + @Resource
  50 + private CombinationProductMapper combinationProductMapper;
  51 +
  52 + @Resource
  53 + private ProductSpuApi productSpuApi;
  54 + @Resource
  55 + private ProductSkuApi productSkuApi;
  56 +
  57 + @Override
  58 + @Transactional(rollbackFor = Exception.class)
  59 + public Long createCombinationActivity(CombinationActivityCreateReqVO createReqVO) {
  60 + // 校验商品 SPU 是否存在是否参加的别的活动
  61 + validateProductConflict(createReqVO.getSpuId(), null);
  62 + // 校验商品是否存在
  63 + validateProductExists(createReqVO.getSpuId(), createReqVO.getProducts());
  64 +
  65 + // 插入拼团活动
  66 + CombinationActivityDO activity = CombinationActivityConvert.INSTANCE.convert(createReqVO)
  67 + .setStatus(CommonStatusEnum.ENABLE.getStatus())
  68 + .setTotalCount(0).setSuccessCount(0).setOrderUserCount(0).setVirtualGroup(0);
  69 + combinationActivityMapper.insert(activity);
  70 + // 插入商品
  71 + List<CombinationProductDO> products = CombinationActivityConvert.INSTANCE.convertList(createReqVO.getProducts(), activity);
  72 + combinationProductMapper.insertBatch(products);
  73 + // 返回
  74 + return activity.getId();
  75 + }
  76 +
  77 + /**
  78 + * 校验拼团商品参与的活动是否存在冲突
  79 + *
  80 + * @param spuId 商品 SPU 编号
  81 + * @param activityId 拼团活动编号
  82 + */
  83 + private void validateProductConflict(Long spuId, Long activityId) {
  84 + // 查询所有开启的拼团活动
  85 + List<CombinationActivityDO> activityList = combinationActivityMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
  86 + if (activityId != null) { // 时排除自己
  87 + activityList.removeIf(item -> ObjectUtil.equal(item.getId(), activityId));
  88 + }
  89 + // 查找是否有其它活动,选择了该产品
  90 + List<CombinationActivityDO> matchActivityList = filterList(activityList, activity -> ObjectUtil.equal(activity.getId(), spuId));
  91 + if (CollUtil.isNotEmpty(matchActivityList)) {
  92 + throw exception(COMBINATION_ACTIVITY_SPU_CONFLICTS);
  93 + }
  94 + }
  95 +
  96 + /**
  97 + * 校验拼团商品是否都存在
  98 + *
  99 + * @param spuId 商品 SPU 编号
  100 + * @param products 秒杀商品
  101 + */
  102 + private void validateProductExists(Long spuId, List<CombinationProductBaseVO> products) {
  103 + // 1. 校验商品 spu 是否存在
  104 + ProductSpuRespDTO spu = productSpuApi.getSpu(spuId);
  105 + if (spu == null) {
  106 + throw exception(SPU_NOT_EXISTS);
  107 + }
  108 +
  109 + // 2. 校验商品 sku 都存在
  110 + Map<Long, ProductSkuRespDTO> skuMap = convertMap(productSkuApi.getSkuListBySpuId(singletonList(spuId)),
  111 + ProductSkuRespDTO::getId);
  112 + products.forEach(product -> {
  113 + if (!skuMap.containsKey(product.getSkuId())) {
  114 + throw exception(SKU_NOT_EXISTS);
  115 + }
  116 + });
  117 + }
  118 +
  119 + @Override
  120 + @Transactional(rollbackFor = Exception.class)
  121 + public void updateCombinationActivity(CombinationActivityUpdateReqVO updateReqVO) {
  122 + // 校验存在
  123 + CombinationActivityDO activityDO = validateCombinationActivityExists(updateReqVO.getId());
  124 + // 校验状态
  125 + if (ObjectUtil.equal(activityDO.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
  126 + throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE);
  127 + }
  128 + // 校验商品冲突
  129 + validateProductConflict(updateReqVO.getSpuId(), updateReqVO.getId());
  130 + // 校验商品是否存在
  131 + validateProductExists(updateReqVO.getSpuId(), updateReqVO.getProducts());
  132 +
  133 + // 更新活动
  134 + CombinationActivityDO updateObj = CombinationActivityConvert.INSTANCE.convert(updateReqVO);
  135 + combinationActivityMapper.updateById(updateObj);
  136 + // 更新商品
  137 + updateCombinationProduct(updateObj, updateReqVO.getProducts());
  138 + }
  139 +
  140 + /**
  141 + * 更新拼团商品
  142 + *
  143 + * @param activity 拼团活动
  144 + * @param products 该活动的最新商品配置
  145 + */
  146 + private void updateCombinationProduct(CombinationActivityDO activity, List<CombinationProductBaseVO> products) {
  147 + // 第一步,对比新老数据,获得添加、修改、删除的列表
  148 + List<CombinationProductDO> newList = CombinationActivityConvert.INSTANCE.convertList(products, activity);
  149 + List<CombinationProductDO> oldList = combinationProductMapper.selectListByActivityIds(CollUtil.newArrayList(activity.getId()));
  150 + List<List<CombinationProductDO>> diffList = CollectionUtils.diffList(oldList, newList, (oldVal, newVal) -> {
  151 + boolean same = ObjectUtil.equal(oldVal.getSkuId(), newVal.getSkuId());
  152 + if (same) {
  153 + newVal.setId(oldVal.getId());
  154 + }
  155 + return same;
  156 + });
  157 +
  158 + // 第二步,批量添加、修改、删除
  159 + if (CollUtil.isNotEmpty(diffList.get(0))) {
  160 + combinationProductMapper.insertBatch(diffList.get(0));
  161 + }
  162 + if (CollUtil.isNotEmpty(diffList.get(1))) {
  163 + combinationProductMapper.updateBatch(diffList.get(1));
  164 + }
  165 + if (CollUtil.isNotEmpty(diffList.get(2))) {
  166 + combinationProductMapper.deleteBatchIds(CollectionUtils.convertList(diffList.get(2), CombinationProductDO::getId));
  167 + }
  168 + }
  169 +
  170 + @Override
  171 + @Transactional(rollbackFor = Exception.class)
  172 + public void deleteCombinationActivity(Long id) {
  173 + // 校验存在
  174 + CombinationActivityDO activityDO = validateCombinationActivityExists(id);
  175 + // 校验状态
  176 + if (ObjectUtil.equal(activityDO.getStatus(), CommonStatusEnum.ENABLE.getStatus())) {
  177 + throw exception(COMBINATION_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END);
  178 + }
  179 +
  180 + // 删除
  181 + combinationActivityMapper.deleteById(id);
  182 + }
  183 +
  184 + @Override
  185 + public CombinationActivityDO validateCombinationActivityExists(Long id) {
  186 + CombinationActivityDO activityDO = combinationActivityMapper.selectById(id);
  187 + if (activityDO == null) {
  188 + throw exception(COMBINATION_ACTIVITY_NOT_EXISTS);
  189 + }
  190 + return activityDO;
  191 + }
  192 +
  193 + @Override
  194 + public CombinationActivityDO getCombinationActivity(Long id) {
  195 + return validateCombinationActivityExists(id);
  196 + }
  197 +
  198 + @Override
  199 + public PageResult<CombinationActivityDO> getCombinationActivityPage(CombinationActivityPageReqVO pageReqVO) {
  200 + return combinationActivityMapper.selectPage(pageReqVO);
  201 + }
  202 +
  203 + @Override
  204 + public List<CombinationProductDO> getCombinationProductsByActivityIds(Collection<Long> activityIds) {
  205 + return combinationProductMapper.selectListByActivityIds(activityIds);
  206 + }
  207 +
  208 +}
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordService.java
... ... @@ -7,7 +7,7 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationR
7 7 import java.util.List;
8 8  
9 9 /**
10   - * 商品活动记录 service
  10 + * 拼团记录 Service 接口
11 11 *
12 12 * @author HUIHUI
13 13 */
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.service.combination;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.util.ObjectUtil;
  5 +import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
  6 +import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordUpdateStatusReqDTO;
  7 +import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
  8 +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
  9 +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO;
  10 +import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationRecordMapper;
  11 +import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
  12 +import org.springframework.stereotype.Service;
  13 +import org.springframework.transaction.annotation.Transactional;
  14 +import org.springframework.validation.annotation.Validated;
  15 +
  16 +import javax.annotation.Resource;
  17 +import java.util.List;
  18 +
  19 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  20 +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
  21 +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COMBINATION_RECORD_USER_FULL;
  22 +
  23 +// TODO 芋艿:等拼团记录做完,完整 review 下
  24 +/**
  25 + * 拼团记录 Service 实现类
  26 + *
  27 + * @author HUIHUI
  28 + */
  29 +@Service
  30 +@Validated
  31 +public class CombinationRecordServiceImpl implements CombinationRecordService {
  32 +
  33 + @Resource
  34 + private CombinationActivityService combinationActivityService;
  35 +
  36 + @Resource
  37 + private CombinationRecordMapper recordMapper;
  38 +
  39 + @Override
  40 + public void updateCombinationRecordStatusByUserIdAndOrderId(CombinationRecordUpdateStatusReqDTO reqDTO) {
  41 + // 校验拼团是否存在
  42 + CombinationRecordDO recordDO = validateCombinationRecord(reqDTO.getUserId(), reqDTO.getOrderId());
  43 +
  44 + // 更新状态
  45 + recordDO.setStatus(reqDTO.getStatus());
  46 + recordMapper.updateById(recordDO);
  47 + }
  48 +
  49 + @Override
  50 + @Transactional(rollbackFor = Exception.class)
  51 + public void updateCombinationRecordStatusAndStartTimeByUserIdAndOrderId(CombinationRecordUpdateStatusReqDTO reqDTO) {
  52 + CombinationRecordDO recordDO = validateCombinationRecord(reqDTO.getUserId(), reqDTO.getOrderId());
  53 + // 更新状态
  54 + recordDO.setStatus(reqDTO.getStatus());
  55 + // 更新开始时间
  56 + recordDO.setStartTime(reqDTO.getStartTime());
  57 + recordMapper.updateById(recordDO);
  58 +
  59 + // 更新拼团参入人数
  60 + List<CombinationRecordDO> recordDOs = recordMapper.selectListByHeadIdAndStatus(recordDO.getHeadId(), reqDTO.getStatus());
  61 + if (CollUtil.isNotEmpty(recordDOs)) {
  62 + recordDOs.forEach(item -> {
  63 + item.setUserCount(recordDOs.size());
  64 + // 校验拼团是否满足要求
  65 + if (ObjectUtil.equal(recordDOs.size(), recordDO.getUserSize())) {
  66 + item.setStatus(CombinationRecordStatusEnum.SUCCESS.getStatus());
  67 + }
  68 + });
  69 + }
  70 + recordMapper.updateBatch(recordDOs);
  71 + }
  72 +
  73 + private CombinationRecordDO validateCombinationRecord(Long userId, Long orderId) {
  74 + // 校验拼团是否存在
  75 + CombinationRecordDO recordDO = recordMapper.selectByUserIdAndOrderId(userId, orderId);
  76 + if (recordDO == null) {
  77 + throw exception(COMBINATION_RECORD_NOT_EXISTS);
  78 + }
  79 + return recordDO;
  80 + }
  81 +
  82 + @Override
  83 + public void createCombinationRecord(CombinationRecordCreateReqDTO reqDTO) {
  84 + // 1.1 校验拼团活动
  85 + CombinationActivityDO activity = combinationActivityService.validateCombinationActivityExists(reqDTO.getActivityId());
  86 + // 1.2 需要校验下,他当前是不是已经参加了该拼团;
  87 + CombinationRecordDO recordDO = recordMapper.selectByUserIdAndOrderId(reqDTO.getUserId(), reqDTO.getOrderId());
  88 + if (recordDO != null) {
  89 + throw exception(COMBINATION_RECORD_EXISTS);
  90 + }
  91 + // 1.3 父拼团是否存在,是否已经满了
  92 + if (reqDTO.getHeadId() != null) {
  93 + CombinationRecordDO recordDO1 = recordMapper.selectRecordByHeadId(reqDTO.getHeadId(), reqDTO.getActivityId(), CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
  94 + if (recordDO1 == null) {
  95 + throw exception(COMBINATION_RECORD_HEAD_NOT_EXISTS);
  96 + }
  97 + // 校验拼团是否满足要求
  98 + if (ObjectUtil.equal(recordDO1.getUserCount(), recordDO1.getUserSize())) {
  99 + throw exception(COMBINATION_RECORD_USER_FULL);
  100 + }
  101 + }
  102 + // TODO @puhui999:应该还有一些校验,后续补噶;例如说,一个团,自己已经参与进去了,不能再参与进去;
  103 +
  104 + // 2. 创建拼团记录
  105 + CombinationRecordDO record = CombinationActivityConvert.INSTANCE.convert(reqDTO);
  106 + record.setVirtualGroup(false);
  107 + // TODO @puhui999:过期时间,应该是 Date 哈;
  108 + record.setExpireTime(activity.getLimitDuration());
  109 + record.setUserSize(activity.getUserSize());
  110 + recordMapper.insert(record);
  111 + }
  112 +
  113 + @Override
  114 + public CombinationRecordDO getCombinationRecord(Long userId, Long orderId) {
  115 + return validateCombinationRecord(userId, orderId);
  116 + }
  117 +
  118 + /**
  119 + * APP 端获取开团记录
  120 + *
  121 + * @return 开团记录
  122 + */
  123 + public List<CombinationRecordDO> getRecordListByStatus(Integer status) {
  124 + return recordMapper.selectListByStatus(status);
  125 + }
  126 +
  127 +}
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/seckillactivity/SeckillActivityService.java renamed to yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityService.java
1   -package cn.iocoder.yudao.module.promotion.service.seckill.seckillactivity;
  1 +package cn.iocoder.yudao.module.promotion.service.seckill;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 4 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO;
... ... @@ -56,14 +56,6 @@ public interface SeckillActivityService {
56 56 SeckillActivityDO getSeckillActivity(Long id);
57 57  
58 58 /**
59   - * 获得秒杀活动列表
60   - *
61   - * @param ids 编号
62   - * @return 秒杀活动列表
63   - */
64   - List<SeckillActivityDO> getSeckillActivityList(Collection<Long> ids);
65   -
66   - /**
67 59 * 获得秒杀活动分页
68 60 *
69 61 * @param pageReqVO 分页查询
... ... @@ -74,17 +66,17 @@ public interface SeckillActivityService {
74 66 /**
75 67 * 通过活动编号获取活动商品
76 68 *
77   - * @param id 活动编号
  69 + * @param activityId 活动编号
78 70 * @return 活动商品列表
79 71 */
80   - List<SeckillProductDO> getSeckillProductListByActivityId(Long id);
  72 + List<SeckillProductDO> getSeckillProductListByActivityId(Long activityId);
81 73  
82 74 /**
83 75 * 通过活动编号获取活动商品
84 76 *
85   - * @param ids 活动编号
  77 + * @param activityIds 活动编号
86 78 * @return 活动商品列表
87 79 */
88   - List<SeckillProductDO> getSeckillProductListByActivityId(Collection<Long> ids);
  80 + List<SeckillProductDO> getSeckillProductListByActivityId(Collection<Long> activityIds);
89 81  
90 82 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/seckillactivity/SeckillActivityServiceImpl.java renamed to yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java
1   -package cn.iocoder.yudao.module.promotion.service.seckill.seckillactivity;
  1 +package cn.iocoder.yudao.module.promotion.service.seckill;
2 2  
3   -import cn.hutool.core.collection.CollUtil;
4 3 import cn.hutool.core.util.ObjectUtil;
5 4 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
6 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
... ... @@ -11,14 +10,12 @@ import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
11 10 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO;
12 11 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO;
13 12 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO;
14   -import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductCreateReqVO;
15   -import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductUpdateReqVO;
  13 +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductBaseVO;
16 14 import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert;
17 15 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
18 16 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
19 17 import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity.SeckillActivityMapper;
20 18 import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity.SeckillProductMapper;
21   -import cn.iocoder.yudao.module.promotion.service.seckill.seckillconfig.SeckillConfigService;
22 19 import cn.iocoder.yudao.module.promotion.util.PromotionUtils;
23 20 import org.springframework.stereotype.Service;
24 21 import org.springframework.transaction.annotation.Transactional;
... ... @@ -27,7 +24,7 @@ import org.springframework.validation.annotation.Validated;
27 24 import javax.annotation.Resource;
28 25 import java.util.Collection;
29 26 import java.util.List;
30   -import java.util.Set;
  27 +import java.util.Map;
31 28  
32 29 import static cn.hutool.core.collection.CollUtil.isNotEmpty;
33 30 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
... ... @@ -35,7 +32,7 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.
35 32 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;
36 33 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS;
37 34 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
38   -import static cn.iocoder.yudao.module.promotion.util.PromotionUtils.validateProductSkuAllExists;
  35 +import static java.util.Collections.singletonList;
39 36  
40 37 /**
41 38 * 秒杀活动 Service 实现类
... ... @@ -60,19 +57,15 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
60 57 @Override
61 58 @Transactional(rollbackFor = Exception.class)
62 59 public Long createSeckillActivity(SeckillActivityCreateReqVO createReqVO) {
63   - // 校验商品秒秒杀时段是否冲突
64   - validateProductSpuSeckillConflict(createReqVO.getConfigIds(), createReqVO.getSpuId(), null);
65   - // 获取所选 spu 下的所有 sku
66   - List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(CollUtil.newArrayList(createReqVO.getSpuId()));
67   - // 校验商品 sku 是否存在
68   - if (skus.size() != createReqVO.getProducts().size()) {
69   - throw exception(SKU_NOT_EXISTS);
70   - }
  60 + // 校验商品秒杀时段是否冲突
  61 + validateProductConflict(createReqVO.getConfigIds(), createReqVO.getSpuId(), null);
  62 + // 校验商品是否存在
  63 + validateProductExists(createReqVO.getSpuId(), createReqVO.getProducts());
71 64  
72 65 // 插入秒杀活动
73 66 SeckillActivityDO activity = SeckillActivityConvert.INSTANCE.convert(createReqVO)
74 67 .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getEndTime()))
75   - .setTotalStock(getSumValue(createReqVO.getProducts(), SeckillProductCreateReqVO::getStock, Integer::sum));
  68 + .setTotalStock(getSumValue(createReqVO.getProducts(), SeckillProductBaseVO::getStock, Integer::sum));
76 69 seckillActivityMapper.insert(activity);
77 70 // 插入商品
78 71 List<SeckillProductDO> products = SeckillActivityConvert.INSTANCE.convertList(createReqVO.getProducts(), activity);
... ... @@ -80,35 +73,61 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
80 73 return activity.getId();
81 74 }
82 75  
83   - private void validateProductSpuSeckillConflict(List<Long> configIds, Long spuId, Long activityId) {
84   - // 校验秒杀时段是否存在
  76 + /**
  77 + * 校验秒杀商品参与的活动是否存在冲突
  78 + *
  79 + * 1. 校验秒杀时段是否存在
  80 + * 2. 秒杀商品是否参加其它活动
  81 + *
  82 + * @param configIds 秒杀时段数组
  83 + * @param spuId 商品 SPU 编号
  84 + * @param activityId 秒杀活动编号
  85 + */
  86 + private void validateProductConflict(List<Long> configIds, Long spuId, Long activityId) {
  87 + // 1. 校验秒杀时段是否存在
85 88 seckillConfigService.validateSeckillConfigExists(configIds);
86   - // 校验商品 spu 是否存在
87   - List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(CollUtil.newArrayList(spuId));
88   - if (CollUtil.isEmpty(spuList)) {
89   - throw exception(SPU_NOT_EXISTS);
90   - }
91   - // 查询所有开启的秒杀活动
92   - List<SeckillActivityDO> activityDOs = seckillActivityMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
93   - if (activityId != null) {
94   - // 更新时移除本活动
95   - activityDOs.removeIf(item -> ObjectUtil.equal(item.getId(), activityId));
  89 +
  90 + // 2.1 查询所有开启的秒杀活动
  91 + List<SeckillActivityDO> activityList = seckillActivityMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
  92 + if (activityId != null) { // 排除自己
  93 + activityList.removeIf(item -> ObjectUtil.equal(item.getId(), activityId));
96 94 }
97   - // 过滤出所有 spuId 有交集的活动
98   - List<SeckillActivityDO> activityDOs1 = convertList(activityDOs, c -> c, s -> ObjectUtil.equal(s.getSpuId(), spuId));
  95 + // TODO @puhui999:一个 spu,参与两个活动应该没关系,关键是活动时间不充能重叠;
  96 + // 2.2 过滤出所有 spuId 有交集的活动,判断是否存在重叠
  97 + List<SeckillActivityDO> activityDOs1 = filterList(activityList, s -> ObjectUtil.equal(s.getSpuId(), spuId));
99 98 if (isNotEmpty(activityDOs1)) {
100 99 throw exception(SECKILL_ACTIVITY_SPU_CONFLICTS);
101 100 }
102   - List<SeckillActivityDO> activityDOs2 = convertList(activityDOs, c -> c, s -> {
103   - // 判断秒杀时段是否有交集
104   - return containsAny(s.getConfigIds(), configIds);
105   - });
106   -
  101 + // 2.3 过滤出所有 configIds 有交集的活动,判断是否存在重叠
  102 + List<SeckillActivityDO> activityDOs2 = filterList(activityList, s -> containsAny(s.getConfigIds(), configIds));
107 103 if (isNotEmpty(activityDOs2)) {
108   - throw exception(SECKILL_TIME_CONFLICTS);
  104 + throw exception(SECKILL_ACTIVITY_SPU_CONFLICTS);
109 105 }
110 106 }
111 107  
  108 + /**
  109 + * 校验秒杀商品是否都存在
  110 + *
  111 + * @param spuId 商品 SPU 编号
  112 + * @param products 秒杀商品
  113 + */
  114 + private void validateProductExists(Long spuId, List<SeckillProductBaseVO> products) {
  115 + // 1. 校验商品 spu 是否存在
  116 + ProductSpuRespDTO spu = productSpuApi.getSpu(spuId);
  117 + if (spu == null) {
  118 + throw exception(SPU_NOT_EXISTS);
  119 + }
  120 +
  121 + // 2. 校验商品 sku 都存在
  122 + Map<Long, ProductSkuRespDTO> skuMap = convertMap(productSkuApi.getSkuListBySpuId(singletonList(spuId)),
  123 + ProductSkuRespDTO::getId);
  124 + products.forEach(product -> {
  125 + if (!skuMap.containsKey(product.getSkuId())) {
  126 + throw exception(SKU_NOT_EXISTS);
  127 + }
  128 + });
  129 + }
  130 +
112 131 @Override
113 132 @Transactional(rollbackFor = Exception.class)
114 133 public void updateSeckillActivity(SeckillActivityUpdateReqVO updateReqVO) {
... ... @@ -118,29 +137,26 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
118 137 throw exception(SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED);
119 138 }
120 139 // 校验商品是否冲突
121   - validateProductSpuSeckillConflict(updateReqVO.getConfigIds(), updateReqVO.getSpuId(), updateReqVO.getId());
122   - // 获取所选 spu下的所有 sku
123   - List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(CollUtil.newArrayList(updateReqVO.getSpuId()));
124   - // 校验商品 sku 是否存在
125   - validateProductSkuAllExists(skus, updateReqVO.getProducts(), SeckillProductUpdateReqVO::getSkuId);
  140 + validateProductConflict(updateReqVO.getConfigIds(), updateReqVO.getSpuId(), updateReqVO.getId());
  141 + // 校验商品是否存在
  142 + validateProductExists(updateReqVO.getSpuId(), updateReqVO.getProducts());
126 143  
127 144 // 更新活动
128 145 SeckillActivityDO updateObj = SeckillActivityConvert.INSTANCE.convert(updateReqVO)
129 146 .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getEndTime()))
130   - .setTotalStock(getSumValue(updateReqVO.getProducts(), SeckillProductUpdateReqVO::getStock, Integer::sum));
  147 + .setTotalStock(getSumValue(updateReqVO.getProducts(), SeckillProductBaseVO::getStock, Integer::sum));
131 148 seckillActivityMapper.updateById(updateObj);
132 149 // 更新商品
133 150 updateSeckillProduct(updateObj, updateReqVO.getProducts());
134 151 }
135 152  
136   -
137 153 /**
138 154 * 更新秒杀商品
139 155 *
140 156 * @param activity 秒杀活动
141 157 * @param products 该活动的最新商品配置
142 158 */
143   - private void updateSeckillProduct(SeckillActivityDO activity, List<SeckillProductUpdateReqVO> products) {
  159 + private void updateSeckillProduct(SeckillActivityDO activity, List<SeckillProductBaseVO> products) {
144 160 // 第一步,对比新老数据,获得添加、修改、删除的列表
145 161 List<SeckillProductDO> newList = SeckillActivityConvert.INSTANCE.convertList(products, activity);
146 162 List<SeckillProductDO> oldList = seckillProductMapper.selectListByActivityId(activity.getId());
... ... @@ -159,7 +175,6 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
159 175 if (isNotEmpty(diffList.get(1))) {
160 176 seckillProductMapper.updateBatch(diffList.get(1));
161 177 }
162   - // delete
163 178 if (isNotEmpty(diffList.get(2))) {
164 179 seckillProductMapper.deleteBatchIds(convertList(diffList.get(2), SeckillProductDO::getId));
165 180 }
... ... @@ -167,7 +182,6 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
167 182  
168 183 @Override
169 184 public void closeSeckillActivity(Long id) {
170   - // TODO 待验证没使用过
171 185 // 校验存在
172 186 SeckillActivityDO activity = validateSeckillActivityExists(id);
173 187 if (CommonStatusEnum.DISABLE.getStatus().equals(activity.getStatus())) {
... ... @@ -191,9 +205,8 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
191 205 // 删除活动
192 206 seckillActivityMapper.deleteById(id);
193 207 // 删除活动商品
194   - List<SeckillProductDO> productDOs = seckillProductMapper.selectListByActivityId(id);
195   - Set<Long> convertSet = convertSet(productDOs, SeckillProductDO::getSkuId);
196   - seckillProductMapper.deleteBatchIds(convertSet);
  208 + List<SeckillProductDO> products = seckillProductMapper.selectListByActivityId(id);
  209 + seckillProductMapper.deleteBatchIds(convertSet(products, SeckillProductDO::getId));
197 210 }
198 211  
199 212 private SeckillActivityDO validateSeckillActivityExists(Long id) {
... ... @@ -210,23 +223,18 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
210 223 }
211 224  
212 225 @Override
213   - public List<SeckillActivityDO> getSeckillActivityList(Collection<Long> ids) {
214   - return seckillActivityMapper.selectBatchIds(ids);
215   - }
216   -
217   - @Override
218 226 public PageResult<SeckillActivityDO> getSeckillActivityPage(SeckillActivityPageReqVO pageReqVO) {
219 227 return seckillActivityMapper.selectPage(pageReqVO);
220 228 }
221 229  
222 230 @Override
223   - public List<SeckillProductDO> getSeckillProductListByActivityId(Long id) {
224   - return seckillProductMapper.selectListByActivityId(id);
  231 + public List<SeckillProductDO> getSeckillProductListByActivityId(Long activityId) {
  232 + return seckillProductMapper.selectListByActivityId(activityId);
225 233 }
226 234  
227 235 @Override
228   - public List<SeckillProductDO> getSeckillProductListByActivityId(Collection<Long> ids) {
229   - return seckillProductMapper.selectListByActivityId(ids);
  236 + public List<SeckillProductDO> getSeckillProductListByActivityId(Collection<Long> activityIds) {
  237 + return seckillProductMapper.selectListByActivityId(activityIds);
230 238 }
231 239  
232 240 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/seckillconfig/SeckillConfigService.java renamed to yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillConfigService.java
1   -package cn.iocoder.yudao.module.promotion.service.seckill.seckillconfig;
  1 +package cn.iocoder.yudao.module.promotion.service.seckill;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 4 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigCreateReqVO;
... ... @@ -57,10 +57,9 @@ public interface SeckillConfigService {
57 57 /**
58 58 * 校验秒杀时段是否存在
59 59 *
60   - * @param timeIds 秒杀时段id集合
  60 + * @param ids 秒杀时段 id 集合
61 61 */
62   - void validateSeckillConfigExists(Collection<Long> timeIds);
63   -
  62 + void validateSeckillConfigExists(Collection<Long> ids);
64 63  
65 64 /**
66 65 * 获得秒杀时间段配置分页数据
... ... @@ -85,4 +84,5 @@ public interface SeckillConfigService {
85 84 * @param status 状态
86 85 */
87 86 void updateSeckillConfigStatus(Long id, Integer status);
  87 +
88 88 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/seckillconfig/SeckillConfigServiceImpl.java renamed to yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillConfigServiceImpl.java
1   -package cn.iocoder.yudao.module.promotion.service.seckill.seckillconfig;
  1 +package cn.iocoder.yudao.module.promotion.service.seckill;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.util.ObjectUtil;
5 5 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
6 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
7   -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
8 7 import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
9 8 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigCreateReqVO;
10 9 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigPageReqVO;
... ... @@ -13,7 +12,6 @@ import cn.iocoder.yudao.module.promotion.convert.seckill.seckillconfig.SeckillCo
13 12 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillconfig.SeckillConfigDO;
14 13 import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillconfig.SeckillConfigMapper;
15 14 import org.springframework.stereotype.Service;
16   -import org.springframework.transaction.annotation.Transactional;
17 15 import org.springframework.validation.annotation.Validated;
18 16  
19 17 import javax.annotation.Resource;
... ... @@ -37,7 +35,6 @@ public class SeckillConfigServiceImpl implements SeckillConfigService {
37 35 private SeckillConfigMapper seckillConfigMapper;
38 36  
39 37 @Override
40   - @Transactional(rollbackFor = Exception.class)
41 38 public Long createSeckillConfig(SeckillConfigCreateReqVO createReqVO) {
42 39 // 校验时间段是否冲突
43 40 validateSeckillConfigConflict(createReqVO.getStartTime(), createReqVO.getEndTime(), null);
... ... @@ -50,7 +47,6 @@ public class SeckillConfigServiceImpl implements SeckillConfigService {
50 47 }
51 48  
52 49 @Override
53   - @Transactional(rollbackFor = Exception.class)
54 50 public void updateSeckillConfig(SeckillConfigUpdateReqVO updateReqVO) {
55 51 // 校验存在
56 52 validateSeckillConfigExists(updateReqVO.getId());
... ... @@ -72,7 +68,6 @@ public class SeckillConfigServiceImpl implements SeckillConfigService {
72 68 }
73 69  
74 70 @Override
75   - @Transactional(rollbackFor = Exception.class)
76 71 public void deleteSeckillConfig(Long id) {
77 72 // 校验存在
78 73 validateSeckillConfigExists(id);
... ... @@ -83,35 +78,31 @@ public class SeckillConfigServiceImpl implements SeckillConfigService {
83 78  
84 79 private void validateSeckillConfigExists(Long id) {
85 80 if (seckillConfigMapper.selectById(id) == null) {
86   - throw exception(SECKILL_TIME_NOT_EXISTS);
  81 + throw exception(SECKILL_CONFIG_NOT_EXISTS);
87 82 }
88 83 }
89 84  
90 85 /**
91 86 * 校验时间是否存在冲突
92 87 *
93   - * @param startTime 开始时间
94   - * @param endTime 结束时间
  88 + * @param startTimeStr 开始时间
  89 + * @param endTimeStr 结束时间
95 90 */
96   - private void validateSeckillConfigConflict(String startTime, String endTime, Long seckillConfigId) {
97   - LocalTime startTime1 = LocalTime.parse(startTime);
98   - LocalTime endTime1 = LocalTime.parse(endTime);
99   - // 查询出所有的时段配置
100   - List<SeckillConfigDO> configDOs = seckillConfigMapper.selectList();
  91 + private void validateSeckillConfigConflict(String startTimeStr, String endTimeStr, Long id) {
  92 + // 1. 查询出所有的时段配置
  93 + LocalTime startTime = LocalTime.parse(startTimeStr);
  94 + LocalTime endTime = LocalTime.parse(endTimeStr);
  95 + List<SeckillConfigDO> configs = seckillConfigMapper.selectList();
101 96 // 更新时排除自己
102   - if (seckillConfigId != null) {
103   - configDOs.removeIf(item -> ObjectUtil.equal(item.getId(), seckillConfigId));
  97 + if (id != null) {
  98 + configs.removeIf(item -> ObjectUtil.equal(item.getId(), id));
104 99 }
105   - // 过滤出重叠的时段 ids
106   - boolean hasConflict = configDOs.stream().anyMatch(config -> {
107   - LocalTime startTime2 = LocalTime.parse(config.getStartTime());
108   - LocalTime endTime2 = LocalTime.parse(config.getEndTime());
109   - // 判断时间是否重叠
110   - return LocalDateTimeUtils.isOverlap(startTime1, endTime1, startTime2, endTime2);
111   - });
112 100  
  101 + // 2. 判断是否有重叠的时间
  102 + boolean hasConflict = configs.stream().anyMatch(config -> LocalDateTimeUtils.isOverlap(startTime, endTime,
  103 + LocalTime.parse(config.getStartTime()), LocalTime.parse(config.getEndTime())));
113 104 if (hasConflict) {
114   - throw exception(SECKILL_TIME_CONFLICTS);
  105 + throw exception(SECKILL_CONFIG_TIME_CONFLICTS);
115 106 }
116 107 }
117 108  
... ... @@ -127,22 +118,22 @@ public class SeckillConfigServiceImpl implements SeckillConfigService {
127 118 }
128 119  
129 120 @Override
130   - public void validateSeckillConfigExists(Collection<Long> configIds) {
131   - if (CollUtil.isEmpty(configIds)) {
132   - throw exception(SECKILL_TIME_NOT_EXISTS);
133   - }
134   - List<SeckillConfigDO> configDOs = seckillConfigMapper.selectBatchIds(configIds);
135   - if (CollUtil.isEmpty(configDOs)) {
136   - throw exception(SECKILL_TIME_NOT_EXISTS);
137   - }
138   - // 过滤出关闭的时段
139   - List<SeckillConfigDO> filterList = CollectionUtils.filterList(configDOs, item -> ObjectUtil.equal(item.getStatus(), CommonStatusEnum.DISABLE.getStatus()));
140   - if (CollUtil.isNotEmpty(filterList)) {
141   - throw exception(SECKILL_TIME_DISABLE);
  121 + public void validateSeckillConfigExists(Collection<Long> ids) {
  122 + if (CollUtil.isEmpty(ids)) {
  123 + return;
142 124 }
143   - if (configDOs.size() != configIds.size()) {
144   - throw exception(SECKILL_TIME_NOT_EXISTS);
  125 + // 1. 如果有数量不匹配,说明有不存在的,则抛出 SECKILL_CONFIG_NOT_EXISTS 业务异常
  126 + List<SeckillConfigDO> configs = seckillConfigMapper.selectBatchIds(ids);
  127 + if (configs.size() != ids.size()) {
  128 + throw exception(SECKILL_CONFIG_NOT_EXISTS);
145 129 }
  130 +
  131 + // 2. 如果存在关闭,则抛出 SECKILL_CONFIG_DISABLE 业务异常
  132 + configs.forEach(config -> {
  133 + if (ObjectUtil.equal(config.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
  134 + throw exception(SECKILL_CONFIG_DISABLE);
  135 + }
  136 + });
146 137 }
147 138  
148 139 @Override
... ...
yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/seckillactivity/SeckillActivityServiceImplTest.java
... ... @@ -7,7 +7,7 @@ import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.Se
7 7 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO;
8 8 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
9 9 import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity.SeckillActivityMapper;
10   -import cn.iocoder.yudao.module.promotion.service.seckill.seckillactivity.SeckillActivityServiceImpl;
  10 +import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityServiceImpl;
11 11 import org.junit.jupiter.api.Disabled;
12 12 import org.junit.jupiter.api.Test;
13 13 import org.springframework.context.annotation.Import;
... ...
yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/seckillconfig/SeckillConfigServiceImplTest.java
... ... @@ -5,7 +5,7 @@ import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.Seck
5 5 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigUpdateReqVO;
6 6 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillconfig.SeckillConfigDO;
7 7 import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillconfig.SeckillConfigMapper;
8   -import cn.iocoder.yudao.module.promotion.service.seckill.seckillconfig.SeckillConfigServiceImpl;
  8 +import cn.iocoder.yudao.module.promotion.service.seckill.SeckillConfigServiceImpl;
9 9 import com.fasterxml.jackson.core.JsonProcessingException;
10 10 import com.fasterxml.jackson.databind.ObjectMapper;
11 11 import org.junit.jupiter.api.Disabled;
... ... @@ -19,7 +19,7 @@ import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEq
19 19 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
20 20 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
21 21 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
22   -import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.SECKILL_TIME_NOT_EXISTS;
  22 +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.SECKILL_CONFIG_NOT_EXISTS;
23 23 import static org.junit.jupiter.api.Assertions.assertNotNull;
24 24 import static org.junit.jupiter.api.Assertions.assertNull;
25 25  
... ... @@ -94,7 +94,7 @@ public class SeckillConfigServiceImplTest extends BaseDbUnitTest {
94 94 SeckillConfigUpdateReqVO reqVO = randomPojo(SeckillConfigUpdateReqVO.class);
95 95  
96 96 // 调用, 并断言异常
97   - assertServiceException(() -> SeckillConfigService.updateSeckillConfig(reqVO), SECKILL_TIME_NOT_EXISTS);
  97 + assertServiceException(() -> SeckillConfigService.updateSeckillConfig(reqVO), SECKILL_CONFIG_NOT_EXISTS);
98 98 }
99 99  
100 100 @Test
... ... @@ -117,7 +117,7 @@ public class SeckillConfigServiceImplTest extends BaseDbUnitTest {
117 117 Long id = randomLongId();
118 118  
119 119 // 调用, 并断言异常
120   - assertServiceException(() -> SeckillConfigService.deleteSeckillConfig(id), SECKILL_TIME_NOT_EXISTS);
  120 + assertServiceException(() -> SeckillConfigService.deleteSeckillConfig(id), SECKILL_CONFIG_NOT_EXISTS);
121 121 }
122 122  
123 123 @Test
... ...
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderDeliveryStatusEnum.java deleted
1   -package cn.iocoder.yudao.module.trade.enums.order;
2   -
3   -import lombok.Getter;
4   -import lombok.RequiredArgsConstructor;
5   -
6   -/**
7   - * 交易订单 - 发货状态
8   - *
9   - * @author 芋道源码
10   - */
11   -@RequiredArgsConstructor
12   -@Getter
13   -public enum TradeOrderDeliveryStatusEnum {
14   -
15   - UNDELIVERED(0, "未发货"),
16   - DELIVERED(1, "已发货"),
17   - RECEIVED(2, "已收货");
18   -
19   - /**
20   - * 状态值
21   - */
22   - private final Integer status;
23   - /**
24   - * 状态名
25   - */
26   - private final String name;
27   -
28   -}
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java
... ... @@ -10,10 +10,12 @@ import cn.iocoder.yudao.module.trade.controller.app.order.vo.*;
10 10 import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemCommentCreateReqVO;
11 11 import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemRespVO;
12 12 import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
  13 +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO;
13 14 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
14 15 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
15 16 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
16 17 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
  18 +import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService;
17 19 import cn.iocoder.yudao.module.trade.service.order.TradeOrderService;
18 20 import com.google.common.collect.Maps;
19 21 import io.swagger.v3.oas.annotations.Operation;
... ... @@ -43,7 +45,11 @@ public class AppTradeOrderController {
43 45 @Resource
44 46 private TradeOrderService tradeOrderService;
45 47 @Resource
  48 + private DeliveryExpressService deliveryExpressService;
  49 +
  50 + @Resource
46 51 private ProductPropertyValueApi productPropertyValueApi;
  52 +
47 53 @Resource
48 54 private TradeOrderProperties tradeOrderProperties;
49 55  
... ... @@ -76,14 +82,21 @@ public class AppTradeOrderController {
76 82 public CommonResult<AppTradeOrderDetailRespVO> getOrder(@RequestParam("id") Long id) {
77 83 // 查询订单
78 84 TradeOrderDO order = tradeOrderService.getOrder(getLoginUserId(), id);
  85 + if (order == null) {
  86 + return success(null);
  87 + }
  88 +
79 89 // 查询订单项
80 90 List<TradeOrderItemDO> orderItems = tradeOrderService.getOrderItemListByOrderId(order.getId());
81 91 // 查询商品属性
82 92 List<ProductPropertyValueDetailRespDTO> propertyValueDetails = productPropertyValueApi
83 93 .getPropertyValueDetailList(TradeOrderConvert.INSTANCE.convertPropertyValueIds(orderItems));
  94 + // 查询物流公司
  95 + DeliveryExpressDO express = order.getLogisticsId() != null && order.getLogisticsId() > 0 ?
  96 + deliveryExpressService.getDeliveryExpress(order.getLogisticsId()) : null;
84 97 // 最终组合
85 98 return success(TradeOrderConvert.INSTANCE.convert02(order, orderItems,
86   - propertyValueDetails, tradeOrderProperties));
  99 + propertyValueDetails, tradeOrderProperties, express));
87 100 }
88 101  
89 102 @GetMapping("/page")
... ... @@ -122,7 +135,7 @@ public class AppTradeOrderController {
122 135 return success(orderCount);
123 136 }
124 137  
125   - @PutMapping("/take")
  138 + @PutMapping("/receive")
126 139 @Operation(summary = "确认交易订单收货")
127 140 @Parameter(name = "id", description = "交易订单编号")
128 141 public CommonResult<Boolean> takeOrder(@RequestParam("id") Long id) {
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderDetailRespVO.java
... ... @@ -80,6 +80,12 @@ public class AppTradeOrderDetailRespVO {
80 80 @Schema(description = "配送方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
81 81 private Integer deliveryType;
82 82  
  83 + @Schema(description = "发货物流公司编号", example = "10")
  84 + private Long logisticsId;
  85 +
  86 + @Schema(description = "发货物流名称", example = "顺丰快递")
  87 + private String logisticsName;
  88 +
83 89 @Schema(description = "发货物流单号", example = "1024")
84 90 private String logisticsNo;
85 91  
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/item/AppTradeOrderItemCommentCreateReqVO.java
... ... @@ -35,5 +35,4 @@ public class AppTradeOrderItemCommentCreateReqVO {
35 35 @Size(max = 9, message = "评论图片地址数组长度不能超过 9 张")
36 36 private List<String> picUrls;
37 37  
38   -
39 38 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/item/AppTradeOrderItemRespVO.java
... ... @@ -13,6 +13,9 @@ public class AppTradeOrderItemRespVO {
13 13 @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
14 14 private Long id;
15 15  
  16 + @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  17 + private Long orderId;
  18 +
16 19 @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
17 20 private Long spuId;
18 21 @Schema(description = "商品 SPU 名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码")
... ... @@ -48,5 +51,5 @@ public class AppTradeOrderItemRespVO {
48 51  
49 52 @Schema(description = "售后状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
50 53 private Integer afterSaleStatus;
51   -
  54 +
52 55 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
... ... @@ -25,6 +25,7 @@ import cn.iocoder.yudao.module.trade.controller.app.order.vo.*;
25 25 import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemCommentCreateReqVO;
26 26 import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemRespVO;
27 27 import cn.iocoder.yudao.module.trade.dal.dataobject.cart.TradeCartDO;
  28 +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO;
28 29 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
29 30 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
30 31 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum;
... ... @@ -234,7 +235,8 @@ public interface TradeOrderConvert {
234 235  
235 236 // TODO 芋艿:可简化
236 237 default AppTradeOrderDetailRespVO convert02(TradeOrderDO order, List<TradeOrderItemDO> orderItems,
237   - List<ProductPropertyValueDetailRespDTO> propertyValueDetails, TradeOrderProperties tradeOrderProperties) {
  238 + List<ProductPropertyValueDetailRespDTO> propertyValueDetails, TradeOrderProperties tradeOrderProperties,
  239 + DeliveryExpressDO express) {
238 240 AppTradeOrderDetailRespVO orderVO = convert3(order, orderItems);
239 241 orderVO.setPayExpireTime(addTime(tradeOrderProperties.getExpireTime()));
240 242 if (StrUtil.isNotEmpty(order.getPayChannelCode())) {
... ... @@ -260,6 +262,9 @@ public interface TradeOrderConvert {
260 262 }
261 263 // 处理收货地址
262 264 orderVO.setReceiverAreaName(AreaUtils.format(order.getReceiverAreaId()));
  265 + if (express != null) {
  266 + orderVO.setLogisticsId(express.getId()).setLogisticsName(express.getName());
  267 + }
263 268 return orderVO;
264 269 }
265 270  
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java
... ... @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.trade.dal.dataobject.order;
2 2  
3 3 import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
4 4 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  5 +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO;
5 6 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryPickUpStoreDO;
6 7 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
7 8 import cn.iocoder.yudao.module.trade.enums.order.*;
... ... @@ -174,18 +175,18 @@ public class TradeOrderDO extends BaseDO {
174 175 private Integer deliveryType;
175 176 /**
176 177 * 发货物流公司编号
  178 + *
  179 + * 如果无需发货,则 logisticsId 设置为 0。原因是,不想再添加额外字段
  180 + *
  181 + * 关联 {@link DeliveryExpressDO#getId()}
177 182 */
178 183 private Long logisticsId;
179 184 /**
180 185 * 发货物流单号
181   - */
182   - private String logisticsNo;
183   - /**
184   - * 发货状态
185 186 *
186   - * 枚举 {@link TradeOrderDeliveryStatusEnum}
  187 + * 如果无需发货,则 logisticsNo 设置 ""。原因是,不想再添加额外字段
187 188 */
188   - private Integer deliveryStatus;
  189 + private String logisticsNo;
189 190 /**
190 191 * 发货时间
191 192 */
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java
... ... @@ -233,8 +233,8 @@ public class TradeOrderServiceImpl implements TradeOrderService {
233 233 order.setTerminal(TerminalEnum.H5.getTerminal()); // todo 数据来源?
234 234 // 支付信息
235 235 order.setAdjustPrice(0).setPayStatus(false);
236   - // 物流信息 TODO 芋艿:暂时写死物流方式;应该是前端选择的
237   - order.setDeliveryType(createReqVO.getDeliveryType()).setDeliveryStatus(TradeOrderDeliveryStatusEnum.UNDELIVERED.getStatus());
  236 + // 物流信息
  237 + order.setDeliveryType(createReqVO.getDeliveryType());
238 238 // 退款信息
239 239 order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()).setRefundPrice(0);
240 240 tradeOrderMapper.insert(order);
... ... @@ -418,8 +418,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
418 418 }
419 419  
420 420 // 更新 TradeOrderDO 状态为已发货,等待收货
421   - updateOrderObj.setStatus(TradeOrderStatusEnum.DELIVERED.getStatus())
422   - .setDeliveryStatus(TradeOrderDeliveryStatusEnum.DELIVERED.getStatus()).setDeliveryTime(LocalDateTime.now());
  421 + updateOrderObj.setStatus(TradeOrderStatusEnum.DELIVERED.getStatus()).setDeliveryTime(LocalDateTime.now());
423 422 int updateCount = tradeOrderMapper.updateByIdAndStatus(order.getId(), order.getStatus(), updateOrderObj);
424 423 if (updateCount == 0) {
425 424 throw exception(ORDER_DELIVERY_FAIL_STATUS_NOT_UNDELIVERED);
... ... @@ -428,7 +427,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
428 427  
429 428 // 发送站内信
430 429 tradeMessageService.sendMessageWhenDeliveryOrder(new TradeOrderMessageWhenDeliveryOrderReqBO().setOrderId(order.getId())
431   - .setUserId(userId).setMessage(TradeOrderDeliveryStatusEnum.DELIVERED.getName()));
  430 + .setUserId(userId).setMessage(null));
432 431  
433 432 // TODO 芋艿:OrderLog
434 433 // TODO 设计:lili:是不是发货后,才支持售后?
... ... @@ -449,8 +448,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
449 448 throw exception(ORDER_NOT_FOUND);
450 449 }
451 450 // 校验订单是否是待发货状态
452   - if (!TradeOrderStatusEnum.isUndelivered(order.getStatus())
453   - || ObjectUtil.notEqual(order.getDeliveryStatus(), TradeOrderDeliveryStatusEnum.UNDELIVERED.getStatus())) {
  451 + if (!TradeOrderStatusEnum.isUndelivered(order.getStatus())) {
454 452 throw exception(ORDER_DELIVERY_FAIL_STATUS_NOT_UNDELIVERED);
455 453 }
456 454 // 校验订单是否退款
... ... @@ -482,8 +480,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
482 480  
483 481 // 更新 TradeOrderDO 状态为已完成
484 482 int updateCount = tradeOrderMapper.updateByIdAndStatus(order.getId(), order.getStatus(),
485   - new TradeOrderDO().setStatus(TradeOrderStatusEnum.COMPLETED.getStatus())
486   - .setDeliveryStatus(TradeOrderDeliveryStatusEnum.RECEIVED.getStatus()).setReceiveTime(LocalDateTime.now()));
  483 + new TradeOrderDO().setStatus(TradeOrderStatusEnum.COMPLETED.getStatus()).setReceiveTime(LocalDateTime.now()));
487 484 if (updateCount == 0) {
488 485 throw exception(ORDER_RECEIVE_FAIL_STATUS_NOT_DELIVERED);
489 486 }
... ... @@ -495,11 +492,6 @@ public class TradeOrderServiceImpl implements TradeOrderService {
495 492 return Boolean.TRUE;
496 493 }
497 494  
498   - @Override
499   - public TradeOrderDO getOrder(Long id) {
500   - return tradeOrderMapper.selectById(id);
501   - }
502   -
503 495 /**
504 496 * 校验交易订单满足可售货的条件
505 497 *
... ... @@ -516,14 +508,18 @@ public class TradeOrderServiceImpl implements TradeOrderService {
516 508 throw exception(ORDER_NOT_FOUND);
517 509 }
518 510 // 校验订单是否是待收货状态
519   - if (!TradeOrderStatusEnum.isDelivered(order.getStatus())
520   - || ObjectUtil.notEqual(order.getDeliveryStatus(), TradeOrderDeliveryStatusEnum.DELIVERED.getStatus())) {
  511 + if (!TradeOrderStatusEnum.isDelivered(order.getStatus())) {
521 512 throw exception(ORDER_RECEIVE_FAIL_STATUS_NOT_DELIVERED);
522 513 }
523 514 return order;
524 515 }
525 516  
526 517 @Override
  518 + public TradeOrderDO getOrder(Long id) {
  519 + return tradeOrderMapper.selectById(id);
  520 + }
  521 +
  522 + @Override
527 523 public TradeOrderDO getOrder(Long userId, Long id) {
528 524 TradeOrderDO order = tradeOrderMapper.selectById(id);
529 525 if (order != null
... ...
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java
... ... @@ -177,7 +177,6 @@ public class TradeOrderServiceTest extends BaseDbUnitTest {
177 177 assertEquals(tradeOrderDO.getPayOrderId(), 1000L);
178 178 assertNull(tradeOrderDO.getPayChannelCode());
179 179 assertNull(tradeOrderDO.getLogisticsId());
180   - assertEquals(tradeOrderDO.getDeliveryStatus(), TradeOrderDeliveryStatusEnum.UNDELIVERED.getStatus());
181 180 assertNull(tradeOrderDO.getDeliveryTime());
182 181 assertNull(tradeOrderDO.getReceiveTime());
183 182 assertEquals(tradeOrderDO.getReceiverName(), "芋艿");
... ... @@ -274,8 +273,7 @@ public class TradeOrderServiceTest extends BaseDbUnitTest {
274 273 // mock 数据(TradeOrder)
275 274 TradeOrderDO order = randomPojo(TradeOrderDO.class, o -> {
276 275 o.setId(1L).setStatus(TradeOrderStatusEnum.UNDELIVERED.getStatus());
277   - o.setLogisticsId(null).setLogisticsNo(null).setDeliveryTime(null)
278   - .setDeliveryStatus(TradeOrderDeliveryStatusEnum.UNDELIVERED.getStatus());
  276 + o.setLogisticsId(null).setLogisticsNo(null).setDeliveryTime(null);
279 277 });
280 278 tradeOrderMapper.insert(order);
281 279 // 准备参数
... ... @@ -288,7 +286,6 @@ public class TradeOrderServiceTest extends BaseDbUnitTest {
288 286 // 断言
289 287 TradeOrderDO dbOrder = tradeOrderMapper.selectById(1L);
290 288 assertEquals(dbOrder.getStatus(), TradeOrderStatusEnum.DELIVERED.getStatus());
291   - assertEquals(dbOrder.getDeliveryStatus(), TradeOrderDeliveryStatusEnum.DELIVERED.getStatus());
292 289 assertPojoEquals(dbOrder, deliveryReqVO);
293 290 assertNotNull(dbOrder.getDeliveryTime());
294 291 }
... ... @@ -298,7 +295,7 @@ public class TradeOrderServiceTest extends BaseDbUnitTest {
298 295 // mock 数据(TradeOrder)
299 296 TradeOrderDO order = randomPojo(TradeOrderDO.class, o -> {
300 297 o.setId(1L).setUserId(10L).setStatus(TradeOrderStatusEnum.DELIVERED.getStatus());
301   - o.setDeliveryStatus(TradeOrderDeliveryStatusEnum.DELIVERED.getStatus()).setReceiveTime(null);
  298 + o.setReceiveTime(null);
302 299 });
303 300 tradeOrderMapper.insert(order);
304 301 // 准备参数
... ... @@ -311,7 +308,6 @@ public class TradeOrderServiceTest extends BaseDbUnitTest {
311 308 // 断言
312 309 TradeOrderDO dbOrder = tradeOrderMapper.selectById(1L);
313 310 assertEquals(dbOrder.getStatus(), TradeOrderStatusEnum.COMPLETED.getStatus());
314   - assertEquals(dbOrder.getDeliveryStatus(), TradeOrderDeliveryStatusEnum.RECEIVED.getStatus());
315 311 assertNotNull(dbOrder.getReceiveTime());
316 312 }
317 313  
... ...
yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql
... ... @@ -25,7 +25,6 @@ CREATE TABLE IF NOT EXISTS &quot;trade_order&quot; (
25 25 "delivery_template_id" bigint,
26 26 "logistics_id" bigint,
27 27 "logistics_no" varchar,
28   - "delivery_status" smallint NOT NULL,
29 28 "delivery_time" datetime,
30 29 "receive_time" datetime,
31 30 "receiver_name" varchar NOT NULL,
... ...