瀏覽代碼

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
puhui999 1 年之前
父節點
當前提交
de828e3d04
共有 51 個文件被更改,包括 683 次插入351 次删除
  1. 38 0
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/app/file/AppFileController.java
  2. 20 0
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/app/file/vo/AppFileUploadReqVO.java
  3. 7 0
      yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/ProductSpuApi.java
  4. 11 5
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/spu/ProductSpuApiImpl.java
  5. 2 0
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java
  6. 3 6
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
  7. 22 5
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/BargainActivityController.java
  8. 1 1
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/BargainActivityBaseVO.java
  9. 0 14
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/BargainActivityCreateReqVO.java
  10. 12 7
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/CombinationActivityController.java
  11. 2 2
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityBaseVO.java
  12. 2 2
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityCreateReqVO.java
  13. 10 16
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityRespVO.java
  14. 2 2
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityUpdateReqVO.java
  15. 2 2
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductBaseVO.java
  16. 0 14
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductCreateReqVO.java
  17. 0 14
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductUpdateReqVO.java
  18. 17 11
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/SeckillActivityController.java
  19. 2 1
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/SeckillConfigController.java
  20. 1 1
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityBaseVO.java
  21. 2 2
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityCreateReqVO.java
  22. 6 6
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityRespVO.java
  23. 2 2
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityUpdateReqVO.java
  24. 1 1
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/product/SeckillProductBaseVO.java
  25. 0 13
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/product/SeckillProductCreateReqVO.java
  26. 0 14
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/product/SeckillProductUpdateReqVO.java
  27. 3 3
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/CombinationActivityDO.java
  28. 9 4
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/CombinationProductDO.java
  29. 1 1
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/CombinationProductMapper.java
  30. 0 13
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillProductMapper.java
  31. 0 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainActivityServiceImpl.java
  32. 8 8
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityService.java
  33. 208 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityServiceImpl.java
  34. 1 1
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordService.java
  35. 127 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java
  36. 5 13
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityService.java
  37. 66 58
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java
  38. 4 4
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillConfigService.java
  39. 29 38
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillConfigServiceImpl.java
  40. 1 1
      yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/seckillactivity/SeckillActivityServiceImplTest.java
  41. 4 4
      yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/seckillconfig/SeckillConfigServiceImplTest.java
  42. 0 28
      yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderDeliveryStatusEnum.java
  43. 15 2
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java
  44. 6 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderDetailRespVO.java
  45. 0 1
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/item/AppTradeOrderItemCommentCreateReqVO.java
  46. 4 1
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/item/AppTradeOrderItemRespVO.java
  47. 6 1
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
  48. 7 6
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java
  49. 12 16
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java
  50. 2 6
      yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java
  51. 0 1
      yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql

+ 38 - 0
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/app/file/AppFileController.java

@@ -0,0 +1,38 @@
+package cn.iocoder.yudao.module.infra.controller.app.file;
+
+import cn.hutool.core.io.IoUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.module.infra.controller.app.file.vo.AppFileUploadReqVO;
+import cn.iocoder.yudao.module.infra.service.file.FileService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.annotation.Resource;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "用户 App - 文件存储")
+@RestController
+@RequestMapping("/infra/file")
+@Validated
+@Slf4j
+public class AppFileController {
+
+    @Resource
+    private FileService fileService;
+
+    @PostMapping("/upload")
+    @Operation(summary = "上传文件")
+    public CommonResult<String> uploadFile(AppFileUploadReqVO uploadReqVO) throws Exception {
+        MultipartFile file = uploadReqVO.getFile();
+        String path = uploadReqVO.getPath();
+        return success(fileService.createFile(file.getOriginalFilename(), path, IoUtil.readBytes(file.getInputStream())));
+    }
+
+}

+ 20 - 0
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/app/file/vo/AppFileUploadReqVO.java

@@ -0,0 +1,20 @@
+package cn.iocoder.yudao.module.infra.controller.app.file.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.validation.constraints.NotNull;
+
+@Schema(description = "用户 App - 上传文件 Request VO")
+@Data
+public class AppFileUploadReqVO {
+
+    @Schema(description = "文件附件", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotNull(message = "文件附件不能为空")
+    private MultipartFile file;
+
+    @Schema(description = "文件附件", example = "yudaoyuanma.png")
+    private String path;
+
+}

+ 7 - 0
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 {
      */
     List<ProductSpuRespDTO> getSpuList(Collection<Long> ids);
 
+    /**
+     * 获得 SPU
+     *
+     * @return SPU
+     */
+    ProductSpuRespDTO getSpu(Long id);
+
 }

+ 11 - 5
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;
 import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert;
 import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
 import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper;
+import cn.iocoder.yudao.module.product.service.sku.ProductSkuService;
+import cn.iocoder.yudao.module.product.service.spu.ProductSpuService;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
@@ -24,15 +26,19 @@ import java.util.List;
 public class ProductSpuApiImpl implements ProductSpuApi {
 
     @Resource
-    private ProductSpuMapper productSpuMapper;
+    private ProductSpuService spuService;
 
     @Override
-    public List<ProductSpuRespDTO> getSpuList(Collection<Long> spuIds) {
-        if (CollectionUtil.isEmpty(spuIds)) {
+    public List<ProductSpuRespDTO> getSpuList(Collection<Long> ids) {
+        if (CollectionUtil.isEmpty(ids)) {
             return Collections.emptyList();
         }
-        List<ProductSpuDO> productSpuDOList = productSpuMapper.selectBatchIds(spuIds);
-        return ProductSpuConvert.INSTANCE.convertList2(productSpuDOList);
+        return ProductSpuConvert.INSTANCE.convertList2(spuService.getSpuList(ids));
+    }
+
+    @Override
+    public ProductSpuRespDTO getSpu(Long id) {
+        return ProductSpuConvert.INSTANCE.convert02(spuService.getSpu(id));
     }
 
 }

+ 2 - 0
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 {
 
     ProductSpuDetailRespVO convert03(ProductSpuDO spu);
 
+    ProductSpuRespDTO convert02(ProductSpuDO bean);
+
     // ========== 用户 App 相关 ==========
 
     PageResult<AppProductSpuPageRespVO> convertPageForGetSpuPage(PageResult<ProductSpuDO> page);

+ 3 - 6
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 {
     ErrorCode SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1013008003, "秒杀活动已关闭,不能修改");
     ErrorCode SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013008004, "秒杀活动未关闭或未结束,不能删除");
     ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1013008005, "秒杀活动已关闭,不能重复关闭");
-    ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_END = new ErrorCode(1013008006, "秒杀活动已结束,不能关闭");
 
     // ========== 秒杀时段 1013009000 ==========
-    ErrorCode SECKILL_TIME_NOT_EXISTS = new ErrorCode(1013009000, "秒杀时段不存在");
-    ErrorCode SECKILL_TIME_CONFLICTS = new ErrorCode(1013009001, "秒杀时段冲突");
-    ErrorCode SECKILL_TIME_EQUAL = new ErrorCode(1013009002, "秒杀时段开始时间和结束时间不能相等");
-    ErrorCode SECKILL_START_TIME_BEFORE_END_TIME = new ErrorCode(1013009003, "秒杀时段开始时间不能在结束时间之后");
-    ErrorCode SECKILL_TIME_DISABLE = new ErrorCode(1013009004, "秒杀时段已关闭");
+    ErrorCode SECKILL_CONFIG_NOT_EXISTS = new ErrorCode(1013009000, "秒杀时段不存在");
+    ErrorCode SECKILL_CONFIG_TIME_CONFLICTS = new ErrorCode(1013009001, "秒杀时段冲突");
+    ErrorCode SECKILL_CONFIG_DISABLE = new ErrorCode(1013009004, "秒杀时段已关闭");
 
     // ========== 拼团活动 1013010000 ==========
     ErrorCode COMBINATION_ACTIVITY_NOT_EXISTS = new ErrorCode(1013010000, "拼团活动不存在");

+ 22 - 5
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/BargainActivityController.java

@@ -1,12 +1,14 @@
 package cn.iocoder.yudao.module.promotion.controller.admin.bargain;
 
+import cn.hutool.core.collection.CollUtil;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
-import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityCreateReqVO;
-import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityPageReqVO;
-import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityRespVO;
-import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityUpdateReqVO;
+import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
+import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityCreateReqVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityPageReqVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityRespVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityUpdateReqVO;
 import cn.iocoder.yudao.module.promotion.convert.bargain.BargainActivityConvert;
 import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService;
 import io.swagger.v3.oas.annotations.Operation;
@@ -18,6 +20,8 @@ import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
 import javax.validation.Valid;
+import java.util.Collections;
+import java.util.List;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 
@@ -31,7 +35,7 @@ public class BargainActivityController {
     private BargainActivityService activityService;
 
     @Resource
-    private ProductSpuApi spuApi;
+    private ProductSpuApi productSpuApi;
 
     @PostMapping("/create")
     @Operation(summary = "创建砍价活动")
@@ -70,6 +74,19 @@ public class BargainActivityController {
     @PreAuthorize("@ss.hasPermission('promotion:bargain-activity:query')")
     public CommonResult<PageResult<BargainActivityRespVO>> getBargainActivityPage(
             @Valid BargainActivityPageReqVO pageVO) {
+        // 查询砍价活动
+        PageResult<BargainActivityDO> pageResult = activityService.getBargainActivityPage(pageVO);
+        if (CollUtil.isEmpty(pageResult.getList())) {
+            return success(PageResult.empty(pageResult.getTotal()));
+        }
+
+        // 拼接数据
+//        List<BargainProductDO> products = activityService.getBargainProductsByActivityIds(
+//                convertSet(pageResult.getList(), BargainActivityDO::getId));
+        List<BargainProductDO> products = Collections.emptyList();
+        List<ProductSpuRespDTO> spus = productSpuApi.getSpuList(
+                convertSet(pageResult.getList(), BargainActivityDO::getSpuId));
+        return success(BargainActivityConvert.INSTANCE.convertPage(pageResult, products, spus));
         return success(BargainActivityConvert.INSTANCE.convertPage(activityService.getBargainActivityPage(pageVO)));
     }
 

+ 1 - 1
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 {
     @NotNull(message = "砍价名称不能为空")
     private String name;
 
-    @Schema(description = "商品 SPU 编号,关联 ProductSpuDO 的 id", example = "[1,2,3]")
+    @Schema(description = "商品 SPU 编号", example = "1")
     @NotNull(message = "砍价商品不能为空")
     private Long spuId;
 

+ 0 - 14
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/bargain/vo/BargainActivityCreateReqVO.java

@@ -1,14 +0,0 @@
-package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-
-@Schema(description = "管理后台 - 砍价活动创建 Request VO")
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-public class BargainActivityCreateReqVO extends BargainActivityBaseVO {
-
-}

+ 12 - 7
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/CombinationActivityController.java

@@ -1,8 +1,10 @@
 package cn.iocoder.yudao.module.promotion.controller.admin.combination;
 
+import cn.hutool.core.collection.CollUtil;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
+import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityRespVO;
@@ -21,7 +23,6 @@ import org.springframework.web.bind.annotation.*;
 import javax.annotation.Resource;
 import javax.validation.Valid;
 import java.util.List;
-import java.util.Set;
 
 import static cn.hutool.core.collection.CollectionUtil.newArrayList;
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@@ -37,7 +38,7 @@ public class CombinationActivityController {
     private CombinationActivityService combinationActivityService;
 
     @Resource
-    private ProductSpuApi spuApi;
+    private ProductSpuApi productSpuApi;
 
     @PostMapping("/create")
     @Operation(summary = "创建拼团活动")
@@ -80,12 +81,16 @@ public class CombinationActivityController {
             @Valid CombinationActivityPageReqVO pageVO) {
         // 查询拼团活动
         PageResult<CombinationActivityDO> pageResult = combinationActivityService.getCombinationActivityPage(pageVO);
+        if (CollUtil.isEmpty(pageResult.getList())) {
+            return success(PageResult.empty(pageResult.getTotal()));
+        }
+
         // 拼接数据
-        Set<Long> activityIds = convertSet(pageResult.getList(), CombinationActivityDO::getId);
-        Set<Long> spuIds = convertSet(pageResult.getList(), CombinationActivityDO::getSpuId);
-        return success(CombinationActivityConvert.INSTANCE.convertPage(pageResult,
-                combinationActivityService.getCombinationProductsByActivityIds(activityIds),
-                spuApi.getSpuList(spuIds)));
+        List<CombinationProductDO> products = combinationActivityService.getCombinationProductsByActivityIds(
+                convertSet(pageResult.getList(), CombinationActivityDO::getId));
+        List<ProductSpuRespDTO> spus = productSpuApi.getSpuList(
+                convertSet(pageResult.getList(), CombinationActivityDO::getSpuId));
+        return success(CombinationActivityConvert.INSTANCE.convertPage(pageResult, products, spus));
     }
 
 }

+ 2 - 2
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 {
     @NotNull(message = "拼团名称不能为空")
     private String name;
 
-    @Schema(description = "商品 SPU 编号,关联 ProductSpuDO 的 id", example = "[1,2,3]")
+    @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
     @NotNull(message = "拼团商品不能为空")
     private Long spuId;
 
@@ -48,7 +48,7 @@ public class CombinationActivityBaseVO {
     @NotNull(message = "开团人数不能为空")
     private Integer userSize;
 
-    @Schema(description = "限制时长(小时)", requiredMode = Schema.RequiredMode.REQUIRED)
+    @Schema(description = "限制时长(小时)", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
     @NotNull(message = "限制时长不能为空")
     private Integer limitDuration;
 

+ 2 - 2
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityCreateReqVO.java

@@ -1,6 +1,6 @@
 package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity;
 
-import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductCreateReqVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductBaseVO;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
@@ -17,6 +17,6 @@ public class CombinationActivityCreateReqVO extends CombinationActivityBaseVO {
 
     @Schema(description = "拼团商品", requiredMode = Schema.RequiredMode.REQUIRED)
     @Valid
-    private List<CombinationProductCreateReqVO> products;
+    private List<CombinationProductBaseVO> products;
 
 }

+ 10 - 16
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;
 @ToString(callSuper = true)
 public class CombinationActivityRespVO extends CombinationActivityBaseVO {
 
-    @Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "618大促")
+    @Schema(description = "活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "22901")
+    private Long id;
+
+    @Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "618 大促")
     private String spuName;
 
     @Schema(description = "商品主图", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.png")
     private String picUrl;
 
-    @Schema(description = "活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "22901")
-    private Long id;
-
     @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
     private LocalDateTime createTime;
 
-    @Schema(description = "开团人数", requiredMode = Schema.RequiredMode.REQUIRED)
-    @NotNull(message = "开团人数不能为空")
+    @Schema(description = "开团人数", requiredMode = Schema.RequiredMode.REQUIRED, example = "666")
     private Integer userSize;
 
-    @Schema(description = "开团组数", requiredMode = Schema.RequiredMode.REQUIRED)
-    @NotNull(message = "开团组数不能为空")
-    private Integer totalNum;
+    @Schema(description = "开团组数", requiredMode = Schema.RequiredMode.REQUIRED, example = "33")
+    private Integer totalCount;
 
-    @Schema(description = "成团组数", requiredMode = Schema.RequiredMode.REQUIRED)
-    @NotNull(message = "成团组数不能为空")
-    private Integer successNum;
+    @Schema(description = "成团组数", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
+    private Integer successCount;
 
-    @Schema(description = "虚拟成团", requiredMode = Schema.RequiredMode.REQUIRED)
-    @NotNull(message = "虚拟成团不能为空")
+    @Schema(description = "虚拟成团", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
     private Integer virtualGroup;
 
     @Schema(description = "活动状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
-    @NotNull(message = "活动状态不能为空")
     private Integer status;
 
     @Schema(description = "拼团商品", requiredMode = Schema.RequiredMode.REQUIRED)
-    @Valid
     private List<CombinationProductRespVO> products;
 
 }

+ 2 - 2
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityUpdateReqVO.java

@@ -1,6 +1,6 @@
 package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity;
 
-import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductUpdateReqVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductBaseVO;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
@@ -22,6 +22,6 @@ public class CombinationActivityUpdateReqVO extends CombinationActivityBaseVO {
 
     @Schema(description = "拼团商品", requiredMode = Schema.RequiredMode.REQUIRED)
     @Valid
-    private List<CombinationProductUpdateReqVO> products;
+    private List<CombinationProductBaseVO> products;
 
 }

+ 2 - 2
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 {
     private Long skuId;
 
     @Schema(description = "拼团价格,单位分", requiredMode = Schema.RequiredMode.REQUIRED, example = "27682")
-    @NotNull(message = "拼团价格,单位分不能为空")
-    private Integer activePrice;
+    @NotNull(message = "拼团价格不能为空")
+    private Integer combinationPrice;
 
 }

+ 0 - 14
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductCreateReqVO.java

@@ -1,14 +0,0 @@
-package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-
-@Schema(description = "管理后台 - 拼团商品创建 Request VO")
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-public class CombinationProductCreateReqVO extends CombinationProductBaseVO {
-
-}

+ 0 - 14
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductUpdateReqVO.java

@@ -1,14 +0,0 @@
-package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-
-@Schema(description = "管理后台 - 拼团商品更新 Request VO")
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-public class CombinationProductUpdateReqVO extends CombinationProductBaseVO {
-
-}

+ 17 - 11
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/SeckillActivityController.java

@@ -1,5 +1,6 @@
 package cn.iocoder.yudao.module.promotion.controller.admin.seckill;
 
+import cn.hutool.core.collection.CollUtil;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
@@ -8,7 +9,7 @@ import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.*;
 import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
-import cn.iocoder.yudao.module.promotion.service.seckill.seckillactivity.SeckillActivityService;
+import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
 import io.swagger.v3.oas.annotations.tags.Tag;
@@ -19,7 +20,6 @@ import org.springframework.web.bind.annotation.*;
 import javax.annotation.Resource;
 import javax.validation.Valid;
 import java.util.List;
-import java.util.Set;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
@@ -33,7 +33,7 @@ public class SeckillActivityController {
     @Resource
     private SeckillActivityService seckillActivityService;
     @Resource
-    private ProductSpuApi spuApi;
+    private ProductSpuApi productSpuApi;
 
     @PostMapping("/create")
     @Operation(summary = "创建秒杀活动")
@@ -73,21 +73,27 @@ public class SeckillActivityController {
     @Parameter(name = "id", description = "编号", required = true, example = "1024")
     @PreAuthorize("@ss.hasPermission('promotion:seckill-activity:query')")
     public CommonResult<SeckillActivityDetailRespVO> getSeckillActivity(@RequestParam("id") Long id) {
-        SeckillActivityDO seckillActivity = seckillActivityService.getSeckillActivity(id);
-        List<SeckillProductDO> seckillProducts = seckillActivityService.getSeckillProductListByActivityId(id);
-        return success(SeckillActivityConvert.INSTANCE.convert(seckillActivity, seckillProducts));
+        SeckillActivityDO activity = seckillActivityService.getSeckillActivity(id);
+        List<SeckillProductDO> products = seckillActivityService.getSeckillProductListByActivityId(id);
+        return success(SeckillActivityConvert.INSTANCE.convert(activity, products));
     }
 
     @GetMapping("/page")
     @Operation(summary = "获得秒杀活动分页")
     @PreAuthorize("@ss.hasPermission('promotion:seckill-activity:query')")
     public CommonResult<PageResult<SeckillActivityRespVO>> getSeckillActivityPage(@Valid SeckillActivityPageReqVO pageVO) {
+        // 查询活动列表
         PageResult<SeckillActivityDO> pageResult = seckillActivityService.getSeckillActivityPage(pageVO);
-        Set<Long> aIds = convertSet(pageResult.getList(), SeckillActivityDO::getId);
-        List<SeckillProductDO> seckillProducts = seckillActivityService.getSeckillProductListByActivityId(aIds);
-        Set<Long> spuIds = convertSet(pageResult.getList(), SeckillActivityDO::getSpuId);
-        List<ProductSpuRespDTO> spuList = spuApi.getSpuList(spuIds);
-        return success(SeckillActivityConvert.INSTANCE.convertPage(pageResult, seckillProducts, spuList));
+        if (CollUtil.isEmpty(pageResult.getList())) {
+            return success(PageResult.empty(pageResult.getTotal()));
+        }
+
+        // 拼接数据
+        List<SeckillProductDO> products = seckillActivityService.getSeckillProductListByActivityId(
+                convertSet(pageResult.getList(), SeckillActivityDO::getId));
+        List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(
+                convertSet(pageResult.getList(), SeckillActivityDO::getSpuId));
+        return success(SeckillActivityConvert.INSTANCE.convertPage(pageResult, products, spuList));
     }
 
 }

+ 2 - 1
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;
 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.*;
 import cn.iocoder.yudao.module.promotion.convert.seckill.seckillconfig.SeckillConfigConvert;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillconfig.SeckillConfigDO;
-import cn.iocoder.yudao.module.promotion.service.seckill.seckillconfig.SeckillConfigService;
+import cn.iocoder.yudao.module.promotion.service.seckill.SeckillConfigService;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
 import io.swagger.v3.oas.annotations.tags.Tag;
@@ -92,4 +92,5 @@ public class SeckillConfigController {
         PageResult<SeckillConfigDO> pageResult = seckillConfigService.getSeckillConfigPage(pageVO);
         return success(SeckillConfigConvert.INSTANCE.convertPage(pageResult));
     }
+
 }

+ 1 - 1
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_
 @Data
 public class SeckillActivityBaseVO {
 
-    @Schema(description = "秒杀活动商品id", requiredMode = Schema.RequiredMode.REQUIRED, example = "[121,1212]")
+    @Schema(description = "秒杀活动商品 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "[121,1212]")
     @NotNull(message = "秒杀活动商品不能为空")
     private Long spuId;
 

+ 2 - 2
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityCreateReqVO.java

@@ -1,7 +1,7 @@
 package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity;
 
 
-import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductCreateReqVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductBaseVO;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
@@ -16,6 +16,6 @@ import java.util.List;
 public class SeckillActivityCreateReqVO extends SeckillActivityBaseVO {
 
     @Schema(description = "秒杀商品", requiredMode = Schema.RequiredMode.REQUIRED)
-    private List<SeckillProductCreateReqVO> products;
+    private List<SeckillProductBaseVO> products;
 
 }

+ 6 - 6
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 {
     @Schema(description = "商品主图", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.png")
     private String picUrl;
 
-    @Schema(description = "秒杀活动id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    @Schema(description = "秒杀活动 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
     private Long id;
 
     @Schema(description = "秒杀商品", requiredMode = Schema.RequiredMode.REQUIRED)
     private List<SeckillProductRespVO> products;
 
-    @Schema(description = "活动状态 开启:0 禁用:1", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+    @Schema(description = "活动状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
     private Integer status;
 
     @Schema(description = "订单实付金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "22354")
     private Integer totalPrice;
 
-    @Schema(description = "秒杀库存", example = "10")
+    @Schema(description = "秒杀库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
     private Integer stock;
 
-    @Schema(description = "秒杀总库存", example = "20")
+    @Schema(description = "秒杀总库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
     private Integer totalStock;
 
-    @Schema(description = "新增订单数", example = "20")
+    @Schema(description = "新增订单数", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
     private Integer orderCount;
 
-    @Schema(description = "付款人数", example = "20")
+    @Schema(description = "付款人数", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
     private Integer userCount;
 
     @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)

+ 2 - 2
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityUpdateReqVO.java

@@ -1,6 +1,6 @@
 package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity;
 
-import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductUpdateReqVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductBaseVO;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
@@ -18,6 +18,6 @@ public class SeckillActivityUpdateReqVO extends SeckillActivityBaseVO {
     private Long id;
 
     @Schema(description = "秒杀商品", requiredMode = Schema.RequiredMode.REQUIRED)
-    private List<SeckillProductUpdateReqVO> products;
+    private List<SeckillProductBaseVO> products;
 
 }

+ 1 - 1
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 {
     @NotNull(message = "秒杀金额,单位:分不能为空")
     private Integer seckillPrice;
 
-    @Schema(description = "秒杀库存", requiredMode = Schema.RequiredMode.REQUIRED)
+    @Schema(description = "秒杀库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
     @NotNull(message = "秒杀库存不能为空")
     private Integer stock;
 

+ 0 - 13
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/product/SeckillProductCreateReqVO.java

@@ -1,13 +0,0 @@
-package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-@Schema(description = "管理后台 - 秒杀参与商品创建 Request VO")
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-public class SeckillProductCreateReqVO extends SeckillProductBaseVO {
-
-}

+ 0 - 14
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/product/SeckillProductUpdateReqVO.java

@@ -1,14 +0,0 @@
-package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-
-@Schema(description = "管理后台 - 秒杀参与商品更新 Request VO")
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-public class SeckillProductUpdateReqVO extends SeckillProductBaseVO {
-
-}

+ 3 - 3
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 {
     /**
      * 开团组数
      */
-    private Integer totalNum;
+    private Integer totalCount;
     /**
      * 成团组数
      */
-    private Integer successNum;
+    private Integer successCount;
     /**
      * 参与人数
      */
@@ -76,7 +76,7 @@ public class CombinationActivityDO extends BaseDO {
      */
     private Integer virtualGroup;
     /**
-     * 活动状态:0开启 1关闭
+     * 活动状态
      *
      * 枚举 {@link CommonStatusEnum}
      */

+ 9 - 4
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/CombinationProductDO.java

@@ -40,6 +40,11 @@ public class CombinationProductDO extends BaseDO {
      * 商品 SKU 编号
      */
     private Long skuId;
+    /**
+     * 拼团价格,单位分
+     */
+    private Integer combinationPrice;
+
     /**
      * 拼团商品状态
      *
@@ -48,15 +53,15 @@ public class CombinationProductDO extends BaseDO {
     private Integer activityStatus;
     /**
      * 活动开始时间点
+     *
+     * 冗余 {@link CombinationActivityDO#getStartTime()}
      */
     private LocalDateTime activityStartTime;
     /**
      * 活动结束时间点
+     *
+     * 冗余 {@link CombinationActivityDO#getEndTime()}
      */
     private LocalDateTime activityEndTime;
-    /**
-     * 拼团价格,单位分
-     */
-    private Integer activePrice;
 
 }

+ 1 - 1
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<CombinationProduct
                 .eqIfPresent(CombinationProductDO::getActivityStatus, reqVO.getActivityStatus())
                 .betweenIfPresent(CombinationProductDO::getActivityStartTime, reqVO.getActivityStartTime())
                 .betweenIfPresent(CombinationProductDO::getActivityEndTime, reqVO.getActivityEndTime())
-                .eqIfPresent(CombinationProductDO::getActivePrice, reqVO.getActivePrice())
+                .eqIfPresent(CombinationProductDO::getCombinationPrice, reqVO.getActivePrice())
                 .betweenIfPresent(CombinationProductDO::getCreateTime, reqVO.getCreateTime())
                 .orderByDesc(CombinationProductDO::getId));
     }

+ 0 - 13
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillProductMapper.java

@@ -1,9 +1,7 @@
 package cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity;
 
-import cn.hutool.core.collection.CollUtil;
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
-import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
 import org.apache.ibatis.annotations.Mapper;
 
 import java.util.Collection;
@@ -25,15 +23,4 @@ public interface SeckillProductMapper extends BaseMapperX<SeckillProductDO> {
         return selectList(SeckillProductDO::getActivityId, ids);
     }
 
-    default List<SeckillProductDO> selectListBySkuIds(Collection<Long> skuIds) {
-        return selectList(SeckillProductDO::getSkuId, skuIds);
-    }
-
-    default void updateTimeIdsByActivityId(Long id, List<Long> timeIds) {
-        new LambdaUpdateChainWrapper<>(this)
-                .set(SeckillProductDO::getConfigIds, CollUtil.join(timeIds, ","))
-                .eq(SeckillProductDO::getActivityId, id)
-                .update();
-    }
-
 }

+ 0 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainServiceImpl.java → yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainActivityServiceImpl.java


+ 8 - 8
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 {
     void deleteCombinationActivity(Long id);
 
     /**
-     * 获得拼团活动
+     * 校验拼团活动是否存在
      *
      * @param id 编号
      * @return 拼团活动
      */
-    CombinationActivityDO getCombinationActivity(Long id);
+    CombinationActivityDO validateCombinationActivityExists(Long id);
 
     /**
-     * 获得拼团活动列表
+     * 获得拼团活动
      *
-     * @param ids 编号
-     * @return 拼团活动列表
+     * @param id 编号
+     * @return 拼团活动
      */
-    List<CombinationActivityDO> getCombinationActivityList(Collection<Long> ids);
+    CombinationActivityDO getCombinationActivity(Long id);
 
     /**
      * 获得拼团活动分页
@@ -67,9 +67,9 @@ public interface CombinationActivityService {
     /**
      * 获得拼团活动商品列表
      *
-     * @param ids 拼团活动 ids
+     * @param activityIds 拼团活动 ids
      * @return 拼团活动的商品列表
      */
-    List<CombinationProductDO> getCombinationProductsByActivityIds(Collection<Long> ids);
+    List<CombinationProductDO> getCombinationProductsByActivityIds(Collection<Long> activityIds);
 
 }

+ 208 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityServiceImpl.java

@@ -0,0 +1,208 @@
+package cn.iocoder.yudao.module.promotion.service.combination;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
+import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
+import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
+import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
+import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductBaseVO;
+import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO;
+import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationActivityMapper;
+import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationProductMapper;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+
+import javax.annotation.Resource;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
+import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;
+import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS;
+import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
+import static java.util.Collections.singletonList;
+
+/**
+ * 拼团活动 Service 实现类
+ *
+ * @author HUIHUI
+ */
+@Service
+@Validated
+public class CombinationActivityServiceImpl implements CombinationActivityService {
+
+    @Resource
+    private CombinationActivityMapper combinationActivityMapper;
+    @Resource
+    private CombinationProductMapper combinationProductMapper;
+
+    @Resource
+    private ProductSpuApi productSpuApi;
+    @Resource
+    private ProductSkuApi productSkuApi;
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Long createCombinationActivity(CombinationActivityCreateReqVO createReqVO) {
+        // 校验商品 SPU 是否存在是否参加的别的活动
+        validateProductConflict(createReqVO.getSpuId(), null);
+        // 校验商品是否存在
+        validateProductExists(createReqVO.getSpuId(), createReqVO.getProducts());
+
+        // 插入拼团活动
+        CombinationActivityDO activity = CombinationActivityConvert.INSTANCE.convert(createReqVO)
+                .setStatus(CommonStatusEnum.ENABLE.getStatus())
+                .setTotalCount(0).setSuccessCount(0).setOrderUserCount(0).setVirtualGroup(0);
+        combinationActivityMapper.insert(activity);
+        // 插入商品
+        List<CombinationProductDO> products = CombinationActivityConvert.INSTANCE.convertList(createReqVO.getProducts(), activity);
+        combinationProductMapper.insertBatch(products);
+        // 返回
+        return activity.getId();
+    }
+
+    /**
+     * 校验拼团商品参与的活动是否存在冲突
+     *
+     * @param spuId 商品 SPU 编号
+     * @param activityId 拼团活动编号
+     */
+    private void validateProductConflict(Long spuId, Long activityId) {
+        // 查询所有开启的拼团活动
+        List<CombinationActivityDO> activityList = combinationActivityMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
+        if (activityId != null) { // 时排除自己
+            activityList.removeIf(item -> ObjectUtil.equal(item.getId(), activityId));
+        }
+        // 查找是否有其它活动,选择了该产品
+        List<CombinationActivityDO> matchActivityList = filterList(activityList, activity -> ObjectUtil.equal(activity.getId(), spuId));
+        if (CollUtil.isNotEmpty(matchActivityList)) {
+            throw exception(COMBINATION_ACTIVITY_SPU_CONFLICTS);
+        }
+    }
+
+    /**
+     * 校验拼团商品是否都存在
+     *
+     * @param spuId 商品 SPU 编号
+     * @param products 秒杀商品
+     */
+    private void validateProductExists(Long spuId, List<CombinationProductBaseVO> products) {
+        // 1. 校验商品 spu 是否存在
+        ProductSpuRespDTO spu = productSpuApi.getSpu(spuId);
+        if (spu == null) {
+            throw exception(SPU_NOT_EXISTS);
+        }
+
+        // 2. 校验商品 sku 都存在
+        Map<Long, ProductSkuRespDTO> skuMap = convertMap(productSkuApi.getSkuListBySpuId(singletonList(spuId)),
+                ProductSkuRespDTO::getId);
+        products.forEach(product -> {
+            if (!skuMap.containsKey(product.getSkuId())) {
+                throw exception(SKU_NOT_EXISTS);
+            }
+        });
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void updateCombinationActivity(CombinationActivityUpdateReqVO updateReqVO) {
+        // 校验存在
+        CombinationActivityDO activityDO = validateCombinationActivityExists(updateReqVO.getId());
+        // 校验状态
+        if (ObjectUtil.equal(activityDO.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
+            throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE);
+        }
+        // 校验商品冲突
+        validateProductConflict(updateReqVO.getSpuId(), updateReqVO.getId());
+        // 校验商品是否存在
+        validateProductExists(updateReqVO.getSpuId(), updateReqVO.getProducts());
+
+        // 更新活动
+        CombinationActivityDO updateObj = CombinationActivityConvert.INSTANCE.convert(updateReqVO);
+        combinationActivityMapper.updateById(updateObj);
+        // 更新商品
+        updateCombinationProduct(updateObj, updateReqVO.getProducts());
+    }
+
+    /**
+     * 更新拼团商品
+     *
+     * @param activity 拼团活动
+     * @param products  该活动的最新商品配置
+     */
+    private void updateCombinationProduct(CombinationActivityDO activity, List<CombinationProductBaseVO> products) {
+        // 第一步,对比新老数据,获得添加、修改、删除的列表
+        List<CombinationProductDO> newList = CombinationActivityConvert.INSTANCE.convertList(products, activity);
+        List<CombinationProductDO> oldList = combinationProductMapper.selectListByActivityIds(CollUtil.newArrayList(activity.getId()));
+        List<List<CombinationProductDO>> diffList = CollectionUtils.diffList(oldList, newList, (oldVal, newVal) -> {
+            boolean same = ObjectUtil.equal(oldVal.getSkuId(), newVal.getSkuId());
+            if (same) {
+                newVal.setId(oldVal.getId());
+            }
+            return same;
+        });
+
+        // 第二步,批量添加、修改、删除
+        if (CollUtil.isNotEmpty(diffList.get(0))) {
+            combinationProductMapper.insertBatch(diffList.get(0));
+        }
+        if (CollUtil.isNotEmpty(diffList.get(1))) {
+            combinationProductMapper.updateBatch(diffList.get(1));
+        }
+        if (CollUtil.isNotEmpty(diffList.get(2))) {
+            combinationProductMapper.deleteBatchIds(CollectionUtils.convertList(diffList.get(2), CombinationProductDO::getId));
+        }
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void deleteCombinationActivity(Long id) {
+        // 校验存在
+        CombinationActivityDO activityDO = validateCombinationActivityExists(id);
+        // 校验状态
+        if (ObjectUtil.equal(activityDO.getStatus(), CommonStatusEnum.ENABLE.getStatus())) {
+            throw exception(COMBINATION_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END);
+        }
+
+        // 删除
+        combinationActivityMapper.deleteById(id);
+    }
+
+    @Override
+    public CombinationActivityDO validateCombinationActivityExists(Long id) {
+        CombinationActivityDO activityDO = combinationActivityMapper.selectById(id);
+        if (activityDO == null) {
+            throw exception(COMBINATION_ACTIVITY_NOT_EXISTS);
+        }
+        return activityDO;
+    }
+
+    @Override
+    public CombinationActivityDO getCombinationActivity(Long id) {
+        return validateCombinationActivityExists(id);
+    }
+
+    @Override
+    public PageResult<CombinationActivityDO> getCombinationActivityPage(CombinationActivityPageReqVO pageReqVO) {
+        return combinationActivityMapper.selectPage(pageReqVO);
+    }
+
+    @Override
+    public List<CombinationProductDO> getCombinationProductsByActivityIds(Collection<Long> activityIds) {
+        return combinationProductMapper.selectListByActivityIds(activityIds);
+    }
+
+}

+ 1 - 1
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
 import java.util.List;
 
 /**
- * 商品活动记录 service
+ * 拼团记录 Service 接口
  *
  * @author HUIHUI
  */

+ 127 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java

@@ -0,0 +1,127 @@
+package cn.iocoder.yudao.module.promotion.service.combination;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
+import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordUpdateStatusReqDTO;
+import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO;
+import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationRecordMapper;
+import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
+import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COMBINATION_RECORD_USER_FULL;
+
+// TODO 芋艿:等拼团记录做完,完整 review 下
+/**
+ * 拼团记录 Service 实现类
+ *
+ * @author HUIHUI
+ */
+@Service
+@Validated
+public class CombinationRecordServiceImpl implements CombinationRecordService {
+
+    @Resource
+    private CombinationActivityService combinationActivityService;
+
+    @Resource
+    private CombinationRecordMapper recordMapper;
+
+    @Override
+    public void updateCombinationRecordStatusByUserIdAndOrderId(CombinationRecordUpdateStatusReqDTO reqDTO) {
+        // 校验拼团是否存在
+        CombinationRecordDO recordDO = validateCombinationRecord(reqDTO.getUserId(), reqDTO.getOrderId());
+
+        // 更新状态
+        recordDO.setStatus(reqDTO.getStatus());
+        recordMapper.updateById(recordDO);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void updateCombinationRecordStatusAndStartTimeByUserIdAndOrderId(CombinationRecordUpdateStatusReqDTO reqDTO) {
+        CombinationRecordDO recordDO = validateCombinationRecord(reqDTO.getUserId(), reqDTO.getOrderId());
+        // 更新状态
+        recordDO.setStatus(reqDTO.getStatus());
+        // 更新开始时间
+        recordDO.setStartTime(reqDTO.getStartTime());
+        recordMapper.updateById(recordDO);
+
+        // 更新拼团参入人数
+        List<CombinationRecordDO> recordDOs = recordMapper.selectListByHeadIdAndStatus(recordDO.getHeadId(), reqDTO.getStatus());
+        if (CollUtil.isNotEmpty(recordDOs)) {
+            recordDOs.forEach(item -> {
+                item.setUserCount(recordDOs.size());
+                // 校验拼团是否满足要求
+                if (ObjectUtil.equal(recordDOs.size(), recordDO.getUserSize())) {
+                    item.setStatus(CombinationRecordStatusEnum.SUCCESS.getStatus());
+                }
+            });
+        }
+        recordMapper.updateBatch(recordDOs);
+    }
+
+    private CombinationRecordDO validateCombinationRecord(Long userId, Long orderId) {
+        // 校验拼团是否存在
+        CombinationRecordDO recordDO = recordMapper.selectByUserIdAndOrderId(userId, orderId);
+        if (recordDO == null) {
+            throw exception(COMBINATION_RECORD_NOT_EXISTS);
+        }
+        return recordDO;
+    }
+
+    @Override
+    public void createCombinationRecord(CombinationRecordCreateReqDTO reqDTO) {
+        // 1.1 校验拼团活动
+        CombinationActivityDO activity = combinationActivityService.validateCombinationActivityExists(reqDTO.getActivityId());
+        // 1.2 需要校验下,他当前是不是已经参加了该拼团;
+        CombinationRecordDO recordDO = recordMapper.selectByUserIdAndOrderId(reqDTO.getUserId(), reqDTO.getOrderId());
+        if (recordDO != null) {
+            throw exception(COMBINATION_RECORD_EXISTS);
+        }
+        // 1.3 父拼团是否存在,是否已经满了
+        if (reqDTO.getHeadId() != null) {
+            CombinationRecordDO recordDO1 = recordMapper.selectRecordByHeadId(reqDTO.getHeadId(), reqDTO.getActivityId(), CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
+            if (recordDO1 == null) {
+                throw exception(COMBINATION_RECORD_HEAD_NOT_EXISTS);
+            }
+            // 校验拼团是否满足要求
+            if (ObjectUtil.equal(recordDO1.getUserCount(), recordDO1.getUserSize())) {
+                throw exception(COMBINATION_RECORD_USER_FULL);
+            }
+        }
+        // TODO @puhui999:应该还有一些校验,后续补噶;例如说,一个团,自己已经参与进去了,不能再参与进去;
+
+        // 2. 创建拼团记录
+        CombinationRecordDO record = CombinationActivityConvert.INSTANCE.convert(reqDTO);
+        record.setVirtualGroup(false);
+        // TODO @puhui999:过期时间,应该是 Date 哈;
+        record.setExpireTime(activity.getLimitDuration());
+        record.setUserSize(activity.getUserSize());
+        recordMapper.insert(record);
+    }
+
+    @Override
+    public CombinationRecordDO getCombinationRecord(Long userId, Long orderId) {
+        return validateCombinationRecord(userId, orderId);
+    }
+
+    /**
+     * APP 端获取开团记录
+     *
+     * @return 开团记录
+     */
+    public List<CombinationRecordDO> getRecordListByStatus(Integer status) {
+        return recordMapper.selectListByStatus(status);
+    }
+
+}

+ 5 - 13
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/seckillactivity/SeckillActivityService.java → yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityService.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.module.promotion.service.seckill.seckillactivity;
+package cn.iocoder.yudao.module.promotion.service.seckill;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO;
@@ -55,14 +55,6 @@ public interface SeckillActivityService {
      */
     SeckillActivityDO getSeckillActivity(Long id);
 
-    /**
-     * 获得秒杀活动列表
-     *
-     * @param ids 编号
-     * @return 秒杀活动列表
-     */
-    List<SeckillActivityDO> getSeckillActivityList(Collection<Long> ids);
-
     /**
      * 获得秒杀活动分页
      *
@@ -74,17 +66,17 @@ public interface SeckillActivityService {
     /**
      * 通过活动编号获取活动商品
      *
-     * @param id 活动编号
+     * @param activityId 活动编号
      * @return 活动商品列表
      */
-    List<SeckillProductDO> getSeckillProductListByActivityId(Long id);
+    List<SeckillProductDO> getSeckillProductListByActivityId(Long activityId);
 
     /**
      * 通过活动编号获取活动商品
      *
-     * @param ids 活动编号
+     * @param activityIds 活动编号
      * @return 活动商品列表
      */
-    List<SeckillProductDO> getSeckillProductListByActivityId(Collection<Long> ids);
+    List<SeckillProductDO> getSeckillProductListByActivityId(Collection<Long> activityIds);
 
 }

+ 66 - 58
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/seckillactivity/SeckillActivityServiceImpl.java → yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java

@@ -1,6 +1,5 @@
-package cn.iocoder.yudao.module.promotion.service.seckill.seckillactivity;
+package cn.iocoder.yudao.module.promotion.service.seckill;
 
-import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
@@ -11,14 +10,12 @@ import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO;
-import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductCreateReqVO;
-import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductUpdateReqVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductBaseVO;
 import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
 import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity.SeckillActivityMapper;
 import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity.SeckillProductMapper;
-import cn.iocoder.yudao.module.promotion.service.seckill.seckillconfig.SeckillConfigService;
 import cn.iocoder.yudao.module.promotion.util.PromotionUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -27,7 +24,7 @@ import org.springframework.validation.annotation.Validated;
 import javax.annotation.Resource;
 import java.util.Collection;
 import java.util.List;
-import java.util.Set;
+import java.util.Map;
 
 import static cn.hutool.core.collection.CollUtil.isNotEmpty;
 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.
 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;
 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS;
 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
-import static cn.iocoder.yudao.module.promotion.util.PromotionUtils.validateProductSkuAllExists;
+import static java.util.Collections.singletonList;
 
 /**
  * 秒杀活动 Service 实现类
@@ -60,19 +57,15 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
     @Override
     @Transactional(rollbackFor = Exception.class)
     public Long createSeckillActivity(SeckillActivityCreateReqVO createReqVO) {
-        // 校验商品秒秒杀时段是否冲突
-        validateProductSpuSeckillConflict(createReqVO.getConfigIds(), createReqVO.getSpuId(), null);
-        // 获取所选 spu 下的所有 sku
-        List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(CollUtil.newArrayList(createReqVO.getSpuId()));
-        // 校验商品 sku 是否存在
-        if (skus.size() != createReqVO.getProducts().size()) {
-            throw exception(SKU_NOT_EXISTS);
-        }
+        // 校验商品秒杀时段是否冲突
+        validateProductConflict(createReqVO.getConfigIds(), createReqVO.getSpuId(), null);
+        // 校验商品是否存在
+        validateProductExists(createReqVO.getSpuId(), createReqVO.getProducts());
 
         // 插入秒杀活动
         SeckillActivityDO activity = SeckillActivityConvert.INSTANCE.convert(createReqVO)
                 .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getEndTime()))
-                .setTotalStock(getSumValue(createReqVO.getProducts(), SeckillProductCreateReqVO::getStock, Integer::sum));
+                .setTotalStock(getSumValue(createReqVO.getProducts(), SeckillProductBaseVO::getStock, Integer::sum));
         seckillActivityMapper.insert(activity);
         // 插入商品
         List<SeckillProductDO> products = SeckillActivityConvert.INSTANCE.convertList(createReqVO.getProducts(), activity);
@@ -80,35 +73,61 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
         return activity.getId();
     }
 
-    private void validateProductSpuSeckillConflict(List<Long> configIds, Long spuId, Long activityId) {
-        // 校验秒杀时段是否存在
+    /**
+     * 校验秒杀商品参与的活动是否存在冲突
+     *
+     * 1. 校验秒杀时段是否存在
+     * 2. 秒杀商品是否参加其它活动
+     *
+     * @param configIds 秒杀时段数组
+     * @param spuId 商品 SPU 编号
+     * @param activityId 秒杀活动编号
+     */
+    private void validateProductConflict(List<Long> configIds, Long spuId, Long activityId) {
+        // 1. 校验秒杀时段是否存在
         seckillConfigService.validateSeckillConfigExists(configIds);
-        // 校验商品 spu 是否存在
-        List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(CollUtil.newArrayList(spuId));
-        if (CollUtil.isEmpty(spuList)) {
-            throw exception(SPU_NOT_EXISTS);
-        }
-        // 查询所有开启的秒杀活动
-        List<SeckillActivityDO> activityDOs = seckillActivityMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
-        if (activityId != null) {
-            // 更新时移除本活动
-            activityDOs.removeIf(item -> ObjectUtil.equal(item.getId(), activityId));
+
+        // 2.1 查询所有开启的秒杀活动
+        List<SeckillActivityDO> activityList = seckillActivityMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
+        if (activityId != null) { // 排除自己
+            activityList.removeIf(item -> ObjectUtil.equal(item.getId(), activityId));
         }
-        // 过滤出所有 spuId 有交集的活动
-        List<SeckillActivityDO> activityDOs1 = convertList(activityDOs, c -> c, s -> ObjectUtil.equal(s.getSpuId(), spuId));
+        // TODO @puhui999:一个 spu,参与两个活动应该没关系,关键是活动时间不充能重叠;
+        // 2.2 过滤出所有 spuId 有交集的活动,判断是否存在重叠
+        List<SeckillActivityDO> activityDOs1 = filterList(activityList, s -> ObjectUtil.equal(s.getSpuId(), spuId));
         if (isNotEmpty(activityDOs1)) {
             throw exception(SECKILL_ACTIVITY_SPU_CONFLICTS);
         }
-        List<SeckillActivityDO> activityDOs2 = convertList(activityDOs, c -> c, s -> {
-            // 判断秒杀时段是否有交集
-            return containsAny(s.getConfigIds(), configIds);
-        });
-
+        // 2.3 过滤出所有 configIds 有交集的活动,判断是否存在重叠
+        List<SeckillActivityDO> activityDOs2 = filterList(activityList, s -> containsAny(s.getConfigIds(), configIds));
         if (isNotEmpty(activityDOs2)) {
-            throw exception(SECKILL_TIME_CONFLICTS);
+            throw exception(SECKILL_ACTIVITY_SPU_CONFLICTS);
         }
     }
 
+    /**
+     * 校验秒杀商品是否都存在
+     *
+     * @param spuId 商品 SPU 编号
+     * @param products 秒杀商品
+     */
+    private void validateProductExists(Long spuId, List<SeckillProductBaseVO> products) {
+        // 1. 校验商品 spu 是否存在
+        ProductSpuRespDTO spu = productSpuApi.getSpu(spuId);
+        if (spu == null) {
+            throw exception(SPU_NOT_EXISTS);
+        }
+
+        // 2. 校验商品 sku 都存在
+        Map<Long, ProductSkuRespDTO> skuMap = convertMap(productSkuApi.getSkuListBySpuId(singletonList(spuId)),
+                ProductSkuRespDTO::getId);
+        products.forEach(product -> {
+            if (!skuMap.containsKey(product.getSkuId())) {
+                throw exception(SKU_NOT_EXISTS);
+            }
+        });
+    }
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void updateSeckillActivity(SeckillActivityUpdateReqVO updateReqVO) {
@@ -118,29 +137,26 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
             throw exception(SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED);
         }
         // 校验商品是否冲突
-        validateProductSpuSeckillConflict(updateReqVO.getConfigIds(), updateReqVO.getSpuId(), updateReqVO.getId());
-        // 获取所选 spu下的所有 sku
-        List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(CollUtil.newArrayList(updateReqVO.getSpuId()));
-        // 校验商品 sku 是否存在
-        validateProductSkuAllExists(skus, updateReqVO.getProducts(), SeckillProductUpdateReqVO::getSkuId);
+        validateProductConflict(updateReqVO.getConfigIds(), updateReqVO.getSpuId(), updateReqVO.getId());
+        // 校验商品是否存在
+        validateProductExists(updateReqVO.getSpuId(), updateReqVO.getProducts());
 
         // 更新活动
         SeckillActivityDO updateObj = SeckillActivityConvert.INSTANCE.convert(updateReqVO)
                 .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getEndTime()))
-                .setTotalStock(getSumValue(updateReqVO.getProducts(), SeckillProductUpdateReqVO::getStock, Integer::sum));
+                .setTotalStock(getSumValue(updateReqVO.getProducts(), SeckillProductBaseVO::getStock, Integer::sum));
         seckillActivityMapper.updateById(updateObj);
         // 更新商品
         updateSeckillProduct(updateObj, updateReqVO.getProducts());
     }
 
-
     /**
      * 更新秒杀商品
      *
      * @param activity 秒杀活动
      * @param products  该活动的最新商品配置
      */
-    private void updateSeckillProduct(SeckillActivityDO activity, List<SeckillProductUpdateReqVO> products) {
+    private void updateSeckillProduct(SeckillActivityDO activity, List<SeckillProductBaseVO> products) {
         // 第一步,对比新老数据,获得添加、修改、删除的列表
         List<SeckillProductDO> newList = SeckillActivityConvert.INSTANCE.convertList(products, activity);
         List<SeckillProductDO> oldList = seckillProductMapper.selectListByActivityId(activity.getId());
@@ -159,7 +175,6 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
         if (isNotEmpty(diffList.get(1))) {
             seckillProductMapper.updateBatch(diffList.get(1));
         }
-        // delete
         if (isNotEmpty(diffList.get(2))) {
             seckillProductMapper.deleteBatchIds(convertList(diffList.get(2), SeckillProductDO::getId));
         }
@@ -167,7 +182,6 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
 
     @Override
     public void closeSeckillActivity(Long id) {
-        // TODO 待验证没使用过
         // 校验存在
         SeckillActivityDO activity = validateSeckillActivityExists(id);
         if (CommonStatusEnum.DISABLE.getStatus().equals(activity.getStatus())) {
@@ -191,9 +205,8 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
         // 删除活动
         seckillActivityMapper.deleteById(id);
         // 删除活动商品
-        List<SeckillProductDO> productDOs = seckillProductMapper.selectListByActivityId(id);
-        Set<Long> convertSet = convertSet(productDOs, SeckillProductDO::getSkuId);
-        seckillProductMapper.deleteBatchIds(convertSet);
+        List<SeckillProductDO> products = seckillProductMapper.selectListByActivityId(id);
+        seckillProductMapper.deleteBatchIds(convertSet(products, SeckillProductDO::getId));
     }
 
     private SeckillActivityDO validateSeckillActivityExists(Long id) {
@@ -209,24 +222,19 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
         return validateSeckillActivityExists(id);
     }
 
-    @Override
-    public List<SeckillActivityDO> getSeckillActivityList(Collection<Long> ids) {
-        return seckillActivityMapper.selectBatchIds(ids);
-    }
-
     @Override
     public PageResult<SeckillActivityDO> getSeckillActivityPage(SeckillActivityPageReqVO pageReqVO) {
         return seckillActivityMapper.selectPage(pageReqVO);
     }
 
     @Override
-    public List<SeckillProductDO> getSeckillProductListByActivityId(Long id) {
-        return seckillProductMapper.selectListByActivityId(id);
+    public List<SeckillProductDO> getSeckillProductListByActivityId(Long activityId) {
+        return seckillProductMapper.selectListByActivityId(activityId);
     }
 
     @Override
-    public List<SeckillProductDO> getSeckillProductListByActivityId(Collection<Long> ids) {
-        return seckillProductMapper.selectListByActivityId(ids);
+    public List<SeckillProductDO> getSeckillProductListByActivityId(Collection<Long> activityIds) {
+        return seckillProductMapper.selectListByActivityId(activityIds);
     }
 
 }

+ 4 - 4
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/seckillconfig/SeckillConfigService.java → yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillConfigService.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.module.promotion.service.seckill.seckillconfig;
+package cn.iocoder.yudao.module.promotion.service.seckill;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigCreateReqVO;
@@ -57,10 +57,9 @@ public interface SeckillConfigService {
     /**
      * 校验秒杀时段是否存在
      *
-     * @param timeIds 秒杀时段id集合
+     * @param ids 秒杀时段 id 集合
      */
-    void validateSeckillConfigExists(Collection<Long> timeIds);
-
+    void validateSeckillConfigExists(Collection<Long> ids);
 
     /**
      * 获得秒杀时间段配置分页数据
@@ -85,4 +84,5 @@ public interface SeckillConfigService {
      * @param status 状态
      */
     void updateSeckillConfigStatus(Long id, Integer status);
+
 }

+ 29 - 38
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/seckillconfig/SeckillConfigServiceImpl.java → yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillConfigServiceImpl.java

@@ -1,10 +1,9 @@
-package cn.iocoder.yudao.module.promotion.service.seckill.seckillconfig;
+package cn.iocoder.yudao.module.promotion.service.seckill;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigCreateReqVO;
 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
 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillconfig.SeckillConfigDO;
 import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillconfig.SeckillConfigMapper;
 import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
 
 import javax.annotation.Resource;
@@ -37,7 +35,6 @@ public class SeckillConfigServiceImpl implements SeckillConfigService {
     private SeckillConfigMapper seckillConfigMapper;
 
     @Override
-    @Transactional(rollbackFor = Exception.class)
     public Long createSeckillConfig(SeckillConfigCreateReqVO createReqVO) {
         // 校验时间段是否冲突
         validateSeckillConfigConflict(createReqVO.getStartTime(), createReqVO.getEndTime(), null);
@@ -50,7 +47,6 @@ public class SeckillConfigServiceImpl implements SeckillConfigService {
     }
 
     @Override
-    @Transactional(rollbackFor = Exception.class)
     public void updateSeckillConfig(SeckillConfigUpdateReqVO updateReqVO) {
         // 校验存在
         validateSeckillConfigExists(updateReqVO.getId());
@@ -72,7 +68,6 @@ public class SeckillConfigServiceImpl implements SeckillConfigService {
     }
 
     @Override
-    @Transactional(rollbackFor = Exception.class)
     public void deleteSeckillConfig(Long id) {
         // 校验存在
         validateSeckillConfigExists(id);
@@ -83,35 +78,31 @@ public class SeckillConfigServiceImpl implements SeckillConfigService {
 
     private void validateSeckillConfigExists(Long id) {
         if (seckillConfigMapper.selectById(id) == null) {
-            throw exception(SECKILL_TIME_NOT_EXISTS);
+            throw exception(SECKILL_CONFIG_NOT_EXISTS);
         }
     }
 
     /**
      * 校验时间是否存在冲突
      *
-     * @param startTime 开始时间
-     * @param endTime   结束时间
+     * @param startTimeStr 开始时间
+     * @param endTimeStr   结束时间
      */
-    private void validateSeckillConfigConflict(String startTime, String endTime, Long seckillConfigId) {
-        LocalTime startTime1 = LocalTime.parse(startTime);
-        LocalTime endTime1 = LocalTime.parse(endTime);
-        // 查询出所有的时段配置
-        List<SeckillConfigDO> configDOs = seckillConfigMapper.selectList();
+    private void validateSeckillConfigConflict(String startTimeStr, String endTimeStr, Long id) {
+        // 1. 查询出所有的时段配置
+        LocalTime startTime = LocalTime.parse(startTimeStr);
+        LocalTime endTime = LocalTime.parse(endTimeStr);
+        List<SeckillConfigDO> configs = seckillConfigMapper.selectList();
         // 更新时排除自己
-        if (seckillConfigId != null) {
-            configDOs.removeIf(item -> ObjectUtil.equal(item.getId(), seckillConfigId));
+        if (id != null) {
+            configs.removeIf(item -> ObjectUtil.equal(item.getId(), id));
         }
-        // 过滤出重叠的时段 ids
-        boolean hasConflict = configDOs.stream().anyMatch(config -> {
-            LocalTime startTime2 = LocalTime.parse(config.getStartTime());
-            LocalTime endTime2 = LocalTime.parse(config.getEndTime());
-            // 判断时间是否重叠
-            return LocalDateTimeUtils.isOverlap(startTime1, endTime1, startTime2, endTime2);
-        });
 
+        // 2. 判断是否有重叠的时间
+        boolean hasConflict = configs.stream().anyMatch(config -> LocalDateTimeUtils.isOverlap(startTime, endTime,
+                LocalTime.parse(config.getStartTime()), LocalTime.parse(config.getEndTime())));
         if (hasConflict) {
-            throw exception(SECKILL_TIME_CONFLICTS);
+            throw exception(SECKILL_CONFIG_TIME_CONFLICTS);
         }
     }
 
@@ -127,22 +118,22 @@ public class SeckillConfigServiceImpl implements SeckillConfigService {
     }
 
     @Override
-    public void validateSeckillConfigExists(Collection<Long> configIds) {
-        if (CollUtil.isEmpty(configIds)) {
-            throw exception(SECKILL_TIME_NOT_EXISTS);
-        }
-        List<SeckillConfigDO> configDOs = seckillConfigMapper.selectBatchIds(configIds);
-        if (CollUtil.isEmpty(configDOs)) {
-            throw exception(SECKILL_TIME_NOT_EXISTS);
-        }
-        // 过滤出关闭的时段
-        List<SeckillConfigDO> filterList = CollectionUtils.filterList(configDOs, item -> ObjectUtil.equal(item.getStatus(), CommonStatusEnum.DISABLE.getStatus()));
-        if (CollUtil.isNotEmpty(filterList)) {
-            throw exception(SECKILL_TIME_DISABLE);
+    public void validateSeckillConfigExists(Collection<Long> ids) {
+        if (CollUtil.isEmpty(ids)) {
+            return;
         }
-        if (configDOs.size() != configIds.size()) {
-            throw exception(SECKILL_TIME_NOT_EXISTS);
+        // 1. 如果有数量不匹配,说明有不存在的,则抛出 SECKILL_CONFIG_NOT_EXISTS 业务异常
+        List<SeckillConfigDO> configs = seckillConfigMapper.selectBatchIds(ids);
+        if (configs.size() != ids.size()) {
+            throw exception(SECKILL_CONFIG_NOT_EXISTS);
         }
+
+        // 2. 如果存在关闭,则抛出 SECKILL_CONFIG_DISABLE 业务异常
+        configs.forEach(config -> {
+            if (ObjectUtil.equal(config.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
+                throw exception(SECKILL_CONFIG_DISABLE);
+            }
+        });
     }
 
     @Override

+ 1 - 1
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
 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
 import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity.SeckillActivityMapper;
-import cn.iocoder.yudao.module.promotion.service.seckill.seckillactivity.SeckillActivityServiceImpl;
+import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityServiceImpl;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 import org.springframework.context.annotation.Import;

+ 4 - 4
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
 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigUpdateReqVO;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillconfig.SeckillConfigDO;
 import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillconfig.SeckillConfigMapper;
-import cn.iocoder.yudao.module.promotion.service.seckill.seckillconfig.SeckillConfigServiceImpl;
+import cn.iocoder.yudao.module.promotion.service.seckill.SeckillConfigServiceImpl;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import org.junit.jupiter.api.Disabled;
@@ -19,7 +19,7 @@ import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEq
 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
-import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.SECKILL_TIME_NOT_EXISTS;
+import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.SECKILL_CONFIG_NOT_EXISTS;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertNull;
 
@@ -94,7 +94,7 @@ public class SeckillConfigServiceImplTest extends BaseDbUnitTest {
         SeckillConfigUpdateReqVO reqVO = randomPojo(SeckillConfigUpdateReqVO.class);
 
         // 调用, 并断言异常
-        assertServiceException(() -> SeckillConfigService.updateSeckillConfig(reqVO), SECKILL_TIME_NOT_EXISTS);
+        assertServiceException(() -> SeckillConfigService.updateSeckillConfig(reqVO), SECKILL_CONFIG_NOT_EXISTS);
     }
 
     @Test
@@ -117,7 +117,7 @@ public class SeckillConfigServiceImplTest extends BaseDbUnitTest {
         Long id = randomLongId();
 
         // 调用, 并断言异常
-        assertServiceException(() -> SeckillConfigService.deleteSeckillConfig(id), SECKILL_TIME_NOT_EXISTS);
+        assertServiceException(() -> SeckillConfigService.deleteSeckillConfig(id), SECKILL_CONFIG_NOT_EXISTS);
     }
 
     @Test

+ 0 - 28
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderDeliveryStatusEnum.java

@@ -1,28 +0,0 @@
-package cn.iocoder.yudao.module.trade.enums.order;
-
-import lombok.Getter;
-import lombok.RequiredArgsConstructor;
-
-/**
- * 交易订单 - 发货状态
- *
- * @author 芋道源码
- */
-@RequiredArgsConstructor
-@Getter
-public enum TradeOrderDeliveryStatusEnum {
-
-    UNDELIVERED(0, "未发货"),
-    DELIVERED(1, "已发货"),
-    RECEIVED(2, "已收货");
-
-    /**
-     * 状态值
-     */
-    private final Integer status;
-    /**
-     * 状态名
-     */
-    private final String name;
-
-}

+ 15 - 2
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.*;
 import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemCommentCreateReqVO;
 import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemRespVO;
 import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
+import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO;
 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
+import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService;
 import cn.iocoder.yudao.module.trade.service.order.TradeOrderService;
 import com.google.common.collect.Maps;
 import io.swagger.v3.oas.annotations.Operation;
@@ -42,8 +44,12 @@ public class AppTradeOrderController {
 
     @Resource
     private TradeOrderService tradeOrderService;
+    @Resource
+    private DeliveryExpressService deliveryExpressService;
+
     @Resource
     private ProductPropertyValueApi productPropertyValueApi;
+
     @Resource
     private TradeOrderProperties tradeOrderProperties;
 
@@ -76,14 +82,21 @@ public class AppTradeOrderController {
     public CommonResult<AppTradeOrderDetailRespVO> getOrder(@RequestParam("id") Long id) {
         // 查询订单
         TradeOrderDO order = tradeOrderService.getOrder(getLoginUserId(), id);
+        if (order == null) {
+            return success(null);
+        }
+
         // 查询订单项
         List<TradeOrderItemDO> orderItems = tradeOrderService.getOrderItemListByOrderId(order.getId());
         // 查询商品属性
         List<ProductPropertyValueDetailRespDTO> propertyValueDetails = productPropertyValueApi
                 .getPropertyValueDetailList(TradeOrderConvert.INSTANCE.convertPropertyValueIds(orderItems));
+        // 查询物流公司
+        DeliveryExpressDO express = order.getLogisticsId() != null && order.getLogisticsId() > 0 ?
+                deliveryExpressService.getDeliveryExpress(order.getLogisticsId()) : null;
         // 最终组合
         return success(TradeOrderConvert.INSTANCE.convert02(order, orderItems,
-                propertyValueDetails, tradeOrderProperties));
+                propertyValueDetails, tradeOrderProperties, express));
     }
 
     @GetMapping("/page")
@@ -122,7 +135,7 @@ public class AppTradeOrderController {
         return success(orderCount);
     }
 
-    @PutMapping("/take")
+    @PutMapping("/receive")
     @Operation(summary = "确认交易订单收货")
     @Parameter(name = "id", description = "交易订单编号")
     public CommonResult<Boolean> takeOrder(@RequestParam("id") Long id) {

+ 6 - 0
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 {
     @Schema(description = "配送方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
     private Integer deliveryType;
 
+    @Schema(description = "发货物流公司编号", example = "10")
+    private Long logisticsId;
+
+    @Schema(description = "发货物流名称", example = "顺丰快递")
+    private String logisticsName;
+
     @Schema(description = "发货物流单号", example = "1024")
     private String logisticsNo;
 

+ 0 - 1
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 {
     @Size(max = 9, message = "评论图片地址数组长度不能超过 9 张")
     private List<String> picUrls;
 
-
 }

+ 4 - 1
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 {
     @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
     private Long id;
 
+    @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    private Long orderId;
+
     @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
     private Long spuId;
     @Schema(description = "商品 SPU 名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码")
@@ -48,5 +51,5 @@ public class AppTradeOrderItemRespVO {
 
     @Schema(description = "售后状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
     private Integer afterSaleStatus;
-    
+
 }

+ 6 - 1
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.*;
 import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemCommentCreateReqVO;
 import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemRespVO;
 import cn.iocoder.yudao.module.trade.dal.dataobject.cart.TradeCartDO;
+import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO;
 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum;
@@ -234,7 +235,8 @@ public interface TradeOrderConvert {
 
     // TODO 芋艿:可简化
     default AppTradeOrderDetailRespVO convert02(TradeOrderDO order, List<TradeOrderItemDO> orderItems,
-                                                List<ProductPropertyValueDetailRespDTO> propertyValueDetails, TradeOrderProperties tradeOrderProperties) {
+                                                List<ProductPropertyValueDetailRespDTO> propertyValueDetails, TradeOrderProperties tradeOrderProperties,
+                                                DeliveryExpressDO express) {
         AppTradeOrderDetailRespVO orderVO = convert3(order, orderItems);
         orderVO.setPayExpireTime(addTime(tradeOrderProperties.getExpireTime()));
         if (StrUtil.isNotEmpty(order.getPayChannelCode())) {
@@ -260,6 +262,9 @@ public interface TradeOrderConvert {
         }
         // 处理收货地址
         orderVO.setReceiverAreaName(AreaUtils.format(order.getReceiverAreaId()));
+        if (express != null) {
+            orderVO.setLogisticsId(express.getId()).setLogisticsName(express.getName());
+        }
         return orderVO;
     }
 

+ 7 - 6
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;
 
 import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO;
 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryPickUpStoreDO;
 import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
 import cn.iocoder.yudao.module.trade.enums.order.*;
@@ -174,18 +175,18 @@ public class TradeOrderDO extends BaseDO {
     private Integer deliveryType;
     /**
      * 发货物流公司编号
+     *
+     * 如果无需发货,则 logisticsId 设置为 0。原因是,不想再添加额外字段
+     *
+     * 关联 {@link DeliveryExpressDO#getId()}
      */
     private Long logisticsId;
     /**
      * 发货物流单号
-     */
-    private String logisticsNo;
-    /**
-     * 发货状态
      *
-     * 枚举 {@link TradeOrderDeliveryStatusEnum}
+     * 如果无需发货,则 logisticsNo 设置 ""。原因是,不想再添加额外字段
      */
-    private Integer deliveryStatus;
+    private String logisticsNo;
     /**
      * 发货时间
      */

+ 12 - 16
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 {
         order.setTerminal(TerminalEnum.H5.getTerminal()); // todo 数据来源?
         // 支付信息
         order.setAdjustPrice(0).setPayStatus(false);
-        // 物流信息 TODO 芋艿:暂时写死物流方式;应该是前端选择的
-        order.setDeliveryType(createReqVO.getDeliveryType()).setDeliveryStatus(TradeOrderDeliveryStatusEnum.UNDELIVERED.getStatus());
+        // 物流信息
+        order.setDeliveryType(createReqVO.getDeliveryType());
         // 退款信息
         order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()).setRefundPrice(0);
         tradeOrderMapper.insert(order);
@@ -418,8 +418,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
         }
 
         // 更新 TradeOrderDO 状态为已发货,等待收货
-        updateOrderObj.setStatus(TradeOrderStatusEnum.DELIVERED.getStatus())
-                .setDeliveryStatus(TradeOrderDeliveryStatusEnum.DELIVERED.getStatus()).setDeliveryTime(LocalDateTime.now());
+        updateOrderObj.setStatus(TradeOrderStatusEnum.DELIVERED.getStatus()).setDeliveryTime(LocalDateTime.now());
         int updateCount = tradeOrderMapper.updateByIdAndStatus(order.getId(), order.getStatus(), updateOrderObj);
         if (updateCount == 0) {
             throw exception(ORDER_DELIVERY_FAIL_STATUS_NOT_UNDELIVERED);
@@ -428,7 +427,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
 
         // 发送站内信
         tradeMessageService.sendMessageWhenDeliveryOrder(new TradeOrderMessageWhenDeliveryOrderReqBO().setOrderId(order.getId())
-                .setUserId(userId).setMessage(TradeOrderDeliveryStatusEnum.DELIVERED.getName()));
+                .setUserId(userId).setMessage(null));
 
         // TODO 芋艿:OrderLog
         // TODO 设计:lili:是不是发货后,才支持售后?
@@ -449,8 +448,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
             throw exception(ORDER_NOT_FOUND);
         }
         // 校验订单是否是待发货状态
-        if (!TradeOrderStatusEnum.isUndelivered(order.getStatus())
-                || ObjectUtil.notEqual(order.getDeliveryStatus(), TradeOrderDeliveryStatusEnum.UNDELIVERED.getStatus())) {
+        if (!TradeOrderStatusEnum.isUndelivered(order.getStatus())) {
             throw exception(ORDER_DELIVERY_FAIL_STATUS_NOT_UNDELIVERED);
         }
         // 校验订单是否退款
@@ -482,8 +480,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
 
         // 更新 TradeOrderDO 状态为已完成
         int updateCount = tradeOrderMapper.updateByIdAndStatus(order.getId(), order.getStatus(),
-                new TradeOrderDO().setStatus(TradeOrderStatusEnum.COMPLETED.getStatus())
-                        .setDeliveryStatus(TradeOrderDeliveryStatusEnum.RECEIVED.getStatus()).setReceiveTime(LocalDateTime.now()));
+                new TradeOrderDO().setStatus(TradeOrderStatusEnum.COMPLETED.getStatus()).setReceiveTime(LocalDateTime.now()));
         if (updateCount == 0) {
             throw exception(ORDER_RECEIVE_FAIL_STATUS_NOT_DELIVERED);
         }
@@ -495,11 +492,6 @@ public class TradeOrderServiceImpl implements TradeOrderService {
         return Boolean.TRUE;
     }
 
-    @Override
-    public TradeOrderDO getOrder(Long id) {
-        return tradeOrderMapper.selectById(id);
-    }
-
     /**
      * 校验交易订单满足可售货的条件
      *
@@ -516,13 +508,17 @@ public class TradeOrderServiceImpl implements TradeOrderService {
             throw exception(ORDER_NOT_FOUND);
         }
         // 校验订单是否是待收货状态
-        if (!TradeOrderStatusEnum.isDelivered(order.getStatus())
-                || ObjectUtil.notEqual(order.getDeliveryStatus(), TradeOrderDeliveryStatusEnum.DELIVERED.getStatus())) {
+        if (!TradeOrderStatusEnum.isDelivered(order.getStatus())) {
             throw exception(ORDER_RECEIVE_FAIL_STATUS_NOT_DELIVERED);
         }
         return order;
     }
 
+    @Override
+    public TradeOrderDO getOrder(Long id) {
+        return tradeOrderMapper.selectById(id);
+    }
+
     @Override
     public TradeOrderDO getOrder(Long userId, Long id) {
         TradeOrderDO order = tradeOrderMapper.selectById(id);

+ 2 - 6
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 {
         assertEquals(tradeOrderDO.getPayOrderId(), 1000L);
         assertNull(tradeOrderDO.getPayChannelCode());
         assertNull(tradeOrderDO.getLogisticsId());
-        assertEquals(tradeOrderDO.getDeliveryStatus(), TradeOrderDeliveryStatusEnum.UNDELIVERED.getStatus());
         assertNull(tradeOrderDO.getDeliveryTime());
         assertNull(tradeOrderDO.getReceiveTime());
         assertEquals(tradeOrderDO.getReceiverName(), "芋艿");
@@ -274,8 +273,7 @@ public class TradeOrderServiceTest extends BaseDbUnitTest {
         // mock 数据(TradeOrder)
         TradeOrderDO order = randomPojo(TradeOrderDO.class, o -> {
             o.setId(1L).setStatus(TradeOrderStatusEnum.UNDELIVERED.getStatus());
-            o.setLogisticsId(null).setLogisticsNo(null).setDeliveryTime(null)
-                    .setDeliveryStatus(TradeOrderDeliveryStatusEnum.UNDELIVERED.getStatus());
+            o.setLogisticsId(null).setLogisticsNo(null).setDeliveryTime(null);
         });
         tradeOrderMapper.insert(order);
         // 准备参数
@@ -288,7 +286,6 @@ public class TradeOrderServiceTest extends BaseDbUnitTest {
         // 断言
         TradeOrderDO dbOrder = tradeOrderMapper.selectById(1L);
         assertEquals(dbOrder.getStatus(), TradeOrderStatusEnum.DELIVERED.getStatus());
-        assertEquals(dbOrder.getDeliveryStatus(), TradeOrderDeliveryStatusEnum.DELIVERED.getStatus());
         assertPojoEquals(dbOrder, deliveryReqVO);
         assertNotNull(dbOrder.getDeliveryTime());
     }
@@ -298,7 +295,7 @@ public class TradeOrderServiceTest extends BaseDbUnitTest {
         // mock 数据(TradeOrder)
         TradeOrderDO order = randomPojo(TradeOrderDO.class, o -> {
             o.setId(1L).setUserId(10L).setStatus(TradeOrderStatusEnum.DELIVERED.getStatus());
-            o.setDeliveryStatus(TradeOrderDeliveryStatusEnum.DELIVERED.getStatus()).setReceiveTime(null);
+            o.setReceiveTime(null);
         });
         tradeOrderMapper.insert(order);
         // 准备参数
@@ -311,7 +308,6 @@ public class TradeOrderServiceTest extends BaseDbUnitTest {
         // 断言
         TradeOrderDO dbOrder = tradeOrderMapper.selectById(1L);
         assertEquals(dbOrder.getStatus(), TradeOrderStatusEnum.COMPLETED.getStatus());
-        assertEquals(dbOrder.getDeliveryStatus(), TradeOrderDeliveryStatusEnum.RECEIVED.getStatus());
         assertNotNull(dbOrder.getReceiveTime());
     }
 

+ 0 - 1
yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql

@@ -25,7 +25,6 @@ CREATE TABLE IF NOT EXISTS "trade_order" (
      "delivery_template_id" bigint,
      "logistics_id" bigint,
      "logistics_no" varchar,
-     "delivery_status" smallint NOT NULL,
      "delivery_time" datetime,
      "receive_time" datetime,
      "receiver_name" varchar NOT NULL,